软件多语言文案脚本自动化方案
开发高效提速系列目录
- 软件多语言文案脚本自动化方案
软件多语言文案脚本自动化方案
- 背景
- 目标
- 整体方案
- 1. 创建文案资源文件
- 2. python脚本开发
- 3. Python脚本执行与管理
- 4. 人员职责分配
- PyCharm使用说明
- 1. PyCharm下载
- 2. PyCharm安装配置
- 3. 异常情况解决
- 总结
博客创建时间:2023.05.03
博客更新时间:2023.05.03
以Android studio gradle=7.5,SDKVersion 32来分析讲解。如图文和网上其他资料不一致,可能是别的资料版本较低而已。
背景
在海外项目中多语言的支持是很重要的一部分。在我们的项目中常常需要支持简中、繁体、英、日、韩、西班牙语等十多种语言,当我们进行文案的新增、修改、删除时,需要在软件项目多语言文案资源文件中进行文案Key和文案内容对应的复制粘贴,非常耗时耗力且容易出现疲劳性错误。
目前关于多语言文案的管理,有部分公司的项目管理可能还停留在如下流程中:
-
文案由开发在项目资源文件中进行维护(如Android的strings.xml、IOS的Localizable.strings、PC云端的XXX.ini ),当需要进行文案翻译时,将文案文件语言.xml文件给到产品经理

-
由产品经理经过其他操作对文案进行翻译,提供多语言翻译后的excel文档给到软件开发,此时文案Key和文案内容失去关联关系

-
软件开发根据给到的翻译内容查找到对应的文案Key,然后复制到对应的资源文件中进行文案的更新操作
该流程实现过程中,会出现可能的几点问题:
- 在版本开发迭代期间,频繁的文案新增修改,需要开发人员频繁手动对齐文案和Key的关系,费时费力
- 每一中语言都需要将操作重复进行一遍,语言种类越多耗时越久且手动复制粘贴中容易出现疲劳性错误
目标
为了方便对文案资源进行统一管理,方便产品、开发、测试对文案内容的统一对齐,应该在已有的翻译excel文档的基础上完善文案,对每条文案新增对应的文案Key,同时采用python脚本方法,实现脚本自动化程序更新文案资源,达到提升文案管理和使用效率提升。该方案可以支持Android、IOS、PC云端项目的。
整体方案
该方案的主要思路是:
- 创建好统一管理Android、IOS或PC 云端项目的文案管理excel文件
- 根据文案资源Excel文件进行python脚本的编写,达到执行脚本时能生成不同格式的文案资源文件
- 当文案资源有更新时,在excel文档中进行更新,执行脚本程序完成文案资源的更新

根据思路我将其细分为如下几个细分步骤:
- 建立标准化文案管理文件。一般是用excel文件管理
- 编写Python脚本开发
- Python文件管理与程序触发执行
- 项目组内人员职责分配
1. 创建文案资源文件
多语言文案可以放在某个excel文件中进行管理,一般使用公司的办公软件如钉钉或飞书软件中进行管理。文案资源的格式可以一般同产品沟通协商共同制作,符合自己公司产品的需求即可,我这里给出移动端文案sheet和PC 云端sheet模板样式,云端和移动端因文案差异太大,建议不用放在一起。



注意:多语言的文案翻译根据软件的实际需求进行使用,如软件不支持某种语言如"土耳其语",将其对应列空着即可。
2. python脚本开发
python脚本代码如下
# coding=utf-8
import importlib
import re
import sys
import os
import xlrd2importlib.reload(sys)
# isAndroid = True
ANDROID = "Android"
IOS = "IOS"
PC = "PC"
# 配置文件修改区 START *****/
# 平台类型 Android、IOS、PC 区分大小写
platformType = "Android"# 项目多语言资源文件
excelPath = os.path.expanduser('~/Downloads/多语言文案.xlsx')
# 输出路径
outputPath = "D:/Ken.Luo/res/"# 选择需要导出文案的sheet名
sheetName = "App文案"
# 配置文件修改区 END *****/# 导出文案的类型
# entryType = "Android"
commentColNum = 4
typeColNum = 2
keyColNum = 2
colToStringsMap = None# 切换到iOS
def switchToAndroid():global keyColNum, colToStringsMapkeyColNum = 2# 对应关系元组Android (列数 : 多语言文件)colToStringsMap = [(7, "values/strings.xml"),(5, "values-zh/strings.xml"),(6, "values-zh-TW/strings.xml"),(8, "values-de/strings.xml"),(9, "values-fr/strings.xml"),(10, "values-es/strings.xml"),(11, "values-ja/strings.xml"),(12, "values-ko/strings.xml"),(13, "values-ar/strings.xml"),(14, "values-it/strings.xml"),(15, "values-pt/strings.xml"),(16, "values-tr/strings.xml"),(17, "values-ru/strings.xml")]# 切换到iOS
def switchToIOS():global keyColNum, colToStringsMapkeyColNum = 3colToStringsMap = [(7, "values/Localizable.strings"),(5, "values-zh/Localizable.strings"),(6, "values-zh-TW/Localizable.strings"),(8, "values-de/Localizable.strings"),(9, "values-fr/Localizable.strings"),(10, "values-es/Localizable.strings"),(11, "values-ja/Localizable.strings"),(12, "values-ko/Localizable.strings"),(13, "values-ar/Localizable.strings"),(14, "values-it/Localizable.strings"),(15, "values-pt/Localizable.strings"),(16, "values-tr/Localizable.strings"),(17, "values-ru/Localizable.strings")]def switchToPC():global keyColNum, colToStringsMapkeyColNum = 2colToStringsMap = [(7, "values/strings.ini"),(5, "values-zh/strings.ini"),(6, "values-zh-TW/strings.ini"),(8, "values-de/strings.ini"),(9, "values-fr/strings.ini"),(10, "values-es/strings.ini"),(11, "values-ja/strings.ini"),(12, "values-ko/strings.ini"),(13, "values-ar/strings.ini"),(14, "values-it/strings.ini"),(15, "values-pt/strings.ini"),(16, "values-tr/strings.ini"),(17, "values-ru/strings.ini")]# ******* #def formatValue(originalStr):''' 格式化字符串成为app 程序需要的样子'''print("originalStr:" + originalStr)# excel中的换行符换成 \n转义字符, 文案首尾的换行符认为是翻译人员不小心按出来的,在此去掉originalStr = re.sub(r'\n+$', "", originalStr, re.S)originalStr = re.sub(r'^\n+', "", originalStr, re.S)originalStr = re.sub(r'\n', "\\\\n", originalStr, re.S)# 安卓需要对&进行处理if platformType is ANDROID:# 不处理,待后续直接替换成空格if originalStr != ' ':originalStr = re.sub(r'&', "&", originalStr, re.S)print("")return originalStr### 写多语言文件函数 ###
def write_header(strFile):if platformType is ANDROID:strFile.write("""<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">\n""")def write_trailer(strFile):if platformType is ANDROID:strFile.write("\n</resources>")def write_comment(strFile, comment):'''生成注释文案'''if comment != "" and comment != None:if platformType is ANDROID:strFile.write("\t<!-- " + str(comment) + "-->\n")elif platformType is IOS:strFile.write("/** " + str(comment) + " */\n")elif platformType is PC:strFile.write("# " + str(comment) + " \n")def write_key_value(strFile, key, value, defaultValue):# iOS对于value是空使用defaultValueif value == " ":value = " "if not typeColNum is ANDROID and (value is None or value == ""):value = defaultValueif key is None or key == "" or value is None or value == "":return# 处理一个文案多个key的情况keyColValues = key.splitlines()for keyColValue in keyColValues:if platformType is ANDROID:strFile.write("\t<string name=\"" + keyColValue.strip() + "\">" + value.strip() + "</string>\n")elif platformType is IOS:strFile.write("\"" + keyColValue.strip() + "\" = \"" + value.strip() + "\";\n")elif platformType is PC:strFile.write(keyColValue.strip() + " = \"" + value.strip() + "\";\n")# ******* #
workbook = xlrd2.open_workbook(excelPath)
table = workbook.sheet_by_name(sheetName)def writeToFiles():nrows = table.nrows# 打开文件colToFileMap = []for (col, fileName) in colToStringsMap:paths = os.path.split(fileName)print("paths 路径", paths)if len(paths) > 1:pathDir = outputPath + paths[0]print("dir 路径", pathDir)# 输出目录文件夹不存在就创建if not (os.path.exists(pathDir)):os.makedirs(pathDir)file = open(outputPath + fileName, "w+", 1024, "utf-8")colToFileMap.append((col, file))write_header(file)# 导出文案for i in range(2, nrows):print(table)comment = table.cell(i, commentColNum).valuetypeColValue = table.cell(i, typeColNum).valuekeyColValue = table.cell(i, keyColNum).valuedefaultValue = ""# 将一行的各列写入对应的多语言文件for (col, strFile) in colToFileMap:value = table.cell(i, col).valuevalue = formatValue(value)if col == colToFileMap[0][0]:defaultValue = valuewrite_comment(strFile, comment)# if typeColValue.find(entryType) >= 0:write_key_value(strFile, keyColValue, value, defaultValue)# 关闭文件for (_, file) in colToFileMap:write_trailer(file)file.close()if __name__ == '__main__':if platformType is ANDROID:switchToAndroid()writeToFiles()elif platformType is IOS:switchToIOS()writeToFiles()elif platformType is PC:switchToPC()writeToFiles()
3. Python脚本执行与管理
Python脚本的执行需要在电脑中进行触发程序执行,需要电脑有python运行环境,我使用的是Pycharm idea软件,一键安装即可用,和Android studio使用是一样的。后面会专门讲解PyCharm的使用操作。
参数配置
当执行软件安装好后,需要进行部分参数的配置,配置完参数后即可进行程序的执行,生成对应的资源文件。
ANDROID = "Android"
IOS = "IOS"
PC = "PC"
# 配置文件修改区 START *****/
# 平台类型 Android、IOS、PC 区分大小写
platformType = "PC"# 项目多语言资源文件
excelPath = os.path.expanduser('~/Downloads/Remo文案汇总.xlsx')
# 输出路径
outputPath = "D:/Ken.Luo/res88888/"# 选择需要导出文案的sheet名
sheetName = "APP文案"
# 配置文件修改区 END *****/
主要修改的是参数为
- platformType:资源使用的平台,目前定义有Android、IOS、PC云端
- excelPath :excel资源文件的目录地址
- outputPath:脚本执行后的生成的输出位置
- sheetName :APP和PC云端的文案资源我设计是分开放的,所以是两个sheet,需要执行程序时手动选择
执行效果
以Android举例,多语言文案资源是放置在res/value/strings.xml文件中下的。现在我们预计通过执行python脚本程序,实现文案内容自动更新到各语言的strings.xml中。

脚本管理
python脚本是为了减少开发进行文案更新时提效的,当脚本程序开发完毕后考虑后期可能有优化,需要对齐进行持久化管理,所以首先想到的是使用gitee进行管理。https://gitee.com/luofaxin/LanguageRes.git
4. 人员职责分配
在多语言文案管理中,不同角色有自己的任务分配

PyCharm使用说明
在python脚本准备好后,需要通过某种方式实现程序的触发,第一阶段先考虑手动操作pycharm程序执行脚本程序,后期也可以考虑在服务器上进行脚本的自触发。
1. PyCharm下载
手动触发方式需要使用者安装Pycharm 软件,用于执行文案脚本程序。https://www.jetbrains.com/pycharm/download/#section=windows

2. PyCharm安装配置

-
配置.py运行环境


-
配置脚本执行变量
对于.py文件,需要动态的更改路径的配置

-
执行脚本程序
点击执行脚本程序,python脚本将会自动执行,将excel文件生成res/strings.xml文件

3. 异常情况解决
- Python ModuleNotFoundError: No module named ‘xlrd‘ 异常
解决方案


总结
希望这个python脚本自动化方案能帮助大家,多语言文案资源和pyhton脚本我都放到gitee仓库中了,可以下载使用。欢迎大家提出更好的优化建议。
仓库地址:https://gitee.com/luofaxin/LanguageRes.git
相关链接:
- 软件多语言文案脚本自动化方案
扩展链接:
- 项目开发混淆从初识到理解
- 项目开发代码分支管理
博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !
相关文章:
软件多语言文案脚本自动化方案
开发高效提速系列目录 软件多语言文案脚本自动化方案 软件多语言文案脚本自动化方案 背景目标整体方案1. 创建文案资源文件2. python脚本开发3. Python脚本执行与管理4. 人员职责分配 PyCharm使用说明1. PyCharm下载2. PyCharm安装配置3. 异常情况解决 总结 博客创建时间&…...
C++017-C++文件读写应用
文章目录 C017-C文件读写应用C文件读写应用CSP-J目标1. 文件的基本概念、文本文件的基本操作2.文本文件类型与二进制文件类型文本文件类型二进制文件类型二进制查看工具 3.文件重定向、文件读写等操作关闭文件文件操作-写入文本文件文件操作-读取文本文件文件操作-写入二进制文…...
计算机网络 实验二
⭐计网实验专栏,欢迎订阅与关注! ★观前提示:本篇内容为计算机网络实验。内容可能会不符合每个人实验的要求,因此以下内容建议仅做思路参考。 一、实验目的 (1)掌握IP地址的基本结构(网络部分与主机部分的…...
Unity 3D 学习笔记(1)
文章目录 1.Unity 3D 概述2.Unity的安装过程3.Unity 3D 的项目管理4.Unity 3D 中的场景5.Unity 3D 的界面组成 1.Unity 3D 概述 Unity 3D简介:Unity 3D是虚拟现实行业中使用率较高的一款开发引擎,由Unity Technology公司开发。通过Unity,开发…...
P1050 [NOIP2005 普及组] 循环
题目描述 乐乐是一个聪明而又勤奋好学的孩子。他总喜欢探求事物的规律。一天,他突然对数的正整数次幂产生了兴趣。 众所周知,22 的正整数次幂最后一位数总是不断的在重复 2,4,8,6,2,4,8,6…2,4,8,6,2,4,8,6… 我们说 22 的正整数次幂最后一位的循环长度…...
软考算法-排序篇-上
数据排序 一:故事背景二:直接插入排序2.1 概念2.2 画图表示2.3 代码实现2.4 总结提升 三:希尔排序3.1 概念3.2 画图表示3.3 代码实现3.4 总结提升 四:直接选择排序4.1 概念4.2 画图表示4.3 代码实现4.4 总结提升 五:堆…...
总结836
学习目标: 4月(复习完高数18讲内容,背诵21篇短文,熟词僻义300词基础词) 学习内容: 暴力英语:背诵《keep your direction》,默写,英语语法 高等数学:刷题&a…...
ginbuilder 工具快速创建
ginbuilder github 地址 快速创建一个ginweb项目: 目前apps下只有http服务,如果后续有需要的话,会添加上rpc服务,websocket服务后边如果有需要会添加上swagger 创建完成的目录结构 ├── apps │ ├── apis // 所有的apis…...
【Java基础面试宝典】堆、栈、方法区分别都存储了那些内容?wait 和 sleep 方法的区别?
目录 堆、栈、方法区分别都存储了那些内容? 堆(heap) 栈(stack) 方法区(method) 在 java 中 wait 和 sleep 方法的区别? 堆、栈、方法区分别都存储了那些内容? 堆&a…...
古剑飞仙手游Linux系统服务器架设教程
安装宝塔直接运行命令即可。 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 搭建环境: centos 7以上系统服务器 宝塔面板安装应用如下: Nginx1.14 mysql5.7 php5.6 1…...
python实战应用讲解-【numpy数组篇】常用函数(十)(附python示例代码)
目录 Python Numpy MaskedArray.ravel()函数 Python Numpy MaskedArray.reshape()函数 Python Numpy MaskedArray.resize()函数 Python Numpy MaskedArray.std()函数 Python Numpy MaskedArray.sum()函数 Python Numpy MaskedArray.swapaxes()函数 Python Numpy MaskedA…...
计算机组成原理(考研408)练习题#2
用于复习408或计算机组成原理期末考试。如有错误请在评论区指出。 So lets start studying with questions! それでは、問題の勉強を始めましょう! 11.某 cache 采用全相联映射,假设 cache 有 3 块,程序运行过程中需要访问的主存块号依 次为…...
Apache POI,springboot中导出excel报表
2. Apache POI 2.1 介绍 Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下,POI 都是用于操作 Excel 文件。 Apache POI 的应用场景…...
CSS(一)-- 三种样式表
目录 1. 行内样式表 2. 内部样式表 3. 外部样式表(即引入 .css文件)(重点掌握) 1. 行内样式表 行内样式表(内联样式表)是在元素标签内部的 style 属性中设定 CSS 样式。适合于修改简单样式。 <di…...
嵌入式之Samba服务器搭建
在嵌入式系统开发应用平台中,tftp、nfs和samba服务器是最常用的文件传输工具 tftp和nfs是在嵌入式Linux开发环境中经常使用的传输工具 samba则是Linux和Windows之间的文件传输工具。 下面演示在linux上搭建Samba服务器 sudo apt-get install samba chmod -R 77…...
vue3+go——看到了就去学习吧
vue3go——看到了就去学习吧 Vue3.2 Vite Element-Plus 实现最基础的 CRUD1.效果展示【02:36】2.创建项目【03:16】3.添加github管理【04:10】4.引入element-plus【04:21】5.内容布局【08:59】6.布局优化【05:31】7.添加弹窗【09:34】8.ref改$ref【02:47】9.新增数据【09:22】…...
Perf工具统计CPU性能
Perf 性能检测工具 Perf 是一个内置于Linux内核中的工具,用于性能分析和调优。它可以对系统的CPU使用情况、内存使用情况、磁盘I/O、网络I/O等进行监控和分析,并提供了丰富的分析和可视化工具,以帮助用户定位和解决性能问题。perf可以进行函…...
考验大家指针功底的时候到了:请问如何理解 (int*)1 + 1 ?
来,猜猜看,这里的执行结果是什么? 这是今天课上的一道理解题,给大家一点点思考时间。 (心里有答案了再往下滑哦) 5 4 3 2 1 . 答案是,报warning!因为%d不是用来输出指针的哈…...
英语基础-介词
介词 方位介词 in:在…里面 Its in the box. 在盒子里 in my backpack 在背包里 in the tree 长在树上on:在…上面(指与物体表面接触) Its on the box. 在盒子上(和盒子接触) on the floor.在地板上 on the tree.在树上under:在…下面 Its unde…...
Linux进程通信:进程组 会话
1. 进程组 (1)概念:一个或多个进程的集合,也称为“作业”。 (2)父进程创建子进程时,默认属于同一个进程组。进程组ID为组长进程ID。 (3)进程组中只要有一个进程存在&a…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
