开发高效提速系列目录
- 软件多语言文案脚本自动化方案
软件多语言文案脚本自动化方案
- 背景
- 目标
- 整体方案
- 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 xlrd2
importlib.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, colToStringsMap
keyColNum = 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, colToStringsMap
keyColNum = 3
colToStringsMap = [(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, colToStringsMap
keyColNum = 2
colToStringsMap = [(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是空使用defaultValue
if value == " ":
value = " "
if not typeColNum is ANDROID and (value is None or value == ""):
value = defaultValue
if 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).value
typeColValue = table.cell(i, typeColNum).value
keyColValue = table.cell(i, keyColNum).value
defaultValue = ""
# 将一行的各列写入对应的多语言文件
for (col, strFile) in colToFileMap:
value = table.cell(i, col).value
value = formatValue(value)
if col == colToFileMap[0][0]:
defaultValue = value
write_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
相关链接:
- 软件多语言文案脚本自动化方案
扩展链接:
- 项目开发混淆从初识到理解
- 项目开发代码分支管理
博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !