前言
一些app有上架海外支持多国家用户使用的需求,需要翻译为英文、日文、法文等一些语言。而自动翻译未必能满足精确翻译的需求,如果翻译人员不是开发人员的话,他未必能看懂strings.xml文件,不知道该将翻译文本写到什么位置,增加出错风险和学习成本,至少我遇到的翻译人员会看不懂xml文件,即使xml文件结构很简单。而且如果后续xml中添加了需要翻译文本也很容易遗漏,无法很直观的知道是否已逐条翻译。
如果能将strings.xml中需要翻译的问题对应填入excel中,管理起来会方便很多,避免遗漏翻译,也不需要翻译人员能看懂xml。
比如有一个中文strings.xml如下:
<resources>
<string name="app_name">应用名</string>
<string name="name">姓名</string>
<string name="sex">性别</string>
<string name="age">年龄</string>
</resources>
将内容填入excel表格中,翻译人员只关注将前一列中文翻译后的文本填入图中红框内的单元格:
如果文本内容很多很多,这就需要一个脚本来支撑xml和excel两种文件的互相转换,此脚本基于本地excel实现,可考虑使用在线excel文档方便共享。
本文用的是 python版本是3.12.0,相关模块有xml.etree.ElementTree、openpyxl和os。
strings.xml转excel
思路将所有语言的strings.xml存放到一个文件夹,遍历一个个取出strings.xml内容存放在excel表格中。第一列存放string的name,从第二列开始每列存放一个strings.xml中的value值(即每一列是一种语言)。
如果后续strings.xml中有新的name值,则添加到第一列最后一行,如将strings_cn.xml、strings_en.xml、strings_other.xml转换:
<resources>
<string name="app_name">应用名</string>
<string name="name">姓名</string>
<string name="sex">性别</string>
<string name="age">年龄</string>
</resources>
<resources>
<string name="app_name">app_name</string>
<string name="name">name</string>
<string name="sex">sex</string>
<string name="age">age</string>
</resources>
<resources>
<string name="app_name">任意其他语言</string>
<string name="ext">其他元素,若其他strings.xml没有这个元素,则会在生成的excel单元格中留空</string>
</resources>
输出的excel结果为,翻译人员可直观的查看没种语言之间的差异(缺少翻译项),翻译后填入红框处即可。
脚本运行过程(脚本代码在文章末尾):
输入的strings.xml:
输出excel(具体内容在上面):
excel转strings.xml
若理解了上面strings.xml转excel的思路,那excel转strings.xml不过是将上述流程反向输出:
获取excel中内容,第一列为strings.xml的name,第二列开始每一列为一个strings.xml文件内容value,第一行为输出的文件名。从第二列开始遍历每一列逐个拼接每一行为一个xml元素。
脚本运行过程(脚本代码在文章末尾):
输出:
以中文示例,以下为excel内容和strings.xml的内容(红框内):
完整代码
#可实现string.xml中资源汇总到excel文件,需自行创建in文件夹,并把string.xml文件全部放入,生成excel在out文件夹
#也可通过excel统计的资源生成对应string.xml,放至out文件夹
import openpyxl
import os
import xml.etree.ElementTree as ET
outPath="out"
outExcelName=os.path.join(outPath, '翻译文本.xlsx')
inPath="in"
def check_suffix(filePath):
return os.path.splitext(filePath)[1]=='.xml'
def check_out_put():
# 检查文件夹是否存在
if not os.path.exists(outPath):
# 如果文件夹不存在,则创建文件夹
os.makedirs(outPath)
def excel_2_xml():
path = input("请输入Excel文件(.xlsx)路径: ")
# path = "D:/code/py_stringxml/tets.xlsx"
# 打开Excel文件
workbook = openpyxl.load_workbook(path)
# 获取工作表对象
worksheet = workbook.active
# 检查/创建输出路径
check_out_put()
# 遍历列数据,不包含最大数
for col in range(2, worksheet.max_column+1):
# 取excel当前列第一行作为strings.xml的文件名
filename = os.path.join(outPath, worksheet.cell(row=1, column=col).value)
print("file name:", filename)
# 创建根元素
root = ET.Element("resources")
for rows in range(2, worksheet.max_row+1):
#每一行第一列为name
key = worksheet.cell(rows, 1).value
value = worksheet.cell(rows, col).value
# 创建子元素
if not value is None:
item = ET.SubElement(root, "string", name=key)
item.text = value
# 将XML写入文件
tree = ET.ElementTree(root)
# 添加换行和缩进
ET.indent(tree, space='\t', level=0)
tree.write(filename, xml_declaration=True, encoding="utf-8")
# 关闭Excel文件
workbook.close()
print("处理完成")
def xml_2_excel():
# 检查/创建输出路径
check_out_put()
# 删除上次生成的excel文件
if os.path.isfile(outExcelName):
os.remove(outExcelName)
# 创建一个新的工作簿对象
workbook = openpyxl.Workbook()
# 选择活动工作表
worksheet = workbook.active
stringNames=[]
# 第一列存放string.xml中的name,翻译文件从第二列开始
col=2
# 遍历输入路径夹中所有xml文件
for file in os.listdir(inPath):
# 非xml后缀名不做处理
if check_suffix(file) is False:
continue
print("file", file)
row=1
# 解析 XML 文件
tree = ET.parse(os.path.join(inPath, file))
# 获取根元素
root = tree.getroot()
#设置单元格属性(自动换行,顶端对齐)
cell_style = openpyxl.styles.Alignment(vertical='top', wrap_text=True)
#excel文件名添加到第一行
worksheet.cell(row=row, column=col, value=file)
# 从第二行开始写入value值
row=row+1
# 遍历所有子元素
for child in root.iter():
key = child.get('name')
if key is None:
continue
# 判断元素是否已经添加到excel文件,将xml的name添加到第一列
if key in stringNames:
# 找出当前元素所在行
# 数组下标从零开始,excel文件下标从1开始,得加1,第一行是文件名,再加1
row = stringNames.index(key)+2
else:
# 元素名添加到数组
stringNames.append(key)
# 添加到最后一行,第一行是文件名,得加1
row = len(stringNames)+1
m_cell = worksheet.cell(row=row, column=1)
m_cell.value = key
# 设置单元格属性
m_cell.alignment = cell_style
value = child.text
# 将翻译的文本内容写入对应excel单元格
if not key is None:
# print("current", col, row)
m_cell = worksheet.cell(row=row, column=col)
m_cell.value = value
# 设置单元格属性
m_cell.alignment = cell_style
else:
print("key is None:", col, row)
# 写入下一行
row=row+1
# 下一个文件从下一列开始
col=col+1
for i in range(1, col):
#因为列名是字母需要将数字转换成字母
c = openpyxl.utils.get_column_letter(i)
#设置单元格宽度
worksheet.column_dimensions[c].width = 40
# 保存Excel文件
workbook.save(outExcelName)
print("处理完成")
if __name__ == "__main__":
select = input("请输入操作选项:\n1、excel文件转换成string.xml\n2、string.xml转换成excel文件\n")
if select == "1":
excel_2_xml()
else:
xml_2_excel()
input("按任意键退出...")