实现一个多语言文案快速转换工具

Posted 唯鹿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现一个多语言文案快速转换工具相关的知识,希望对你有一定的参考价值。

在海外项目中,多语言的支持是很重要的一部分。例如我们的项目中需要支持简中繁中英法德西日韩俄意这十种类型。一个版本下来,需要添加就有二十多条新的文案,即使有时只有几条,当数量乘以10,都不是一个小数目。如果一条条的添加至项目中,也就是不下几十上百次的重复操作。

发现问题

  • 耗时耗力
  • 不能保证准确度(例如漏掉或岔行)
  • 出错带来的二次检查修改

由于给到我们的多语言文案是表格形式,如下图:


可以看到产品同学整理的很方便,第一列有我们需要的key,其余每列是不同语言文案。

实现

因为以前用Python写过一些爬虫,中间就操作过一些表格的读写。所以优先想到用Python的openpyxl模块来处理excle表格。

思路就是每次循环key所在列,同时读取对应的语言列获取value。之所以循环key是保证每次循环数量一致,因为表格中会有许多空内容。这里我的处理是当获取的key为空时,结束本次循环。

这里我也查了一个ios需要的输出格式,也简单支持了一下。代码如下:

"""
多语言文案表格转android string.xml 和 iOS Localizable.strings脚本

两个参数,第一个是文件路径(必传),第二个是操作工作表名称(不传为默认工作表)。
注意文件必须是xlsx格式,
"""

import sys
import openpyxl
import xml.dom.minidom as minidom

wb = openpyxl.load_workbook(sys.argv[1])

if len(sys.argv) == 3:
	if sys.argv[2] is None:
		# 获取当前工作表
		sheet = wb.active
	else:
		# 获取某一特定的工作表
		sheet = wb.get_sheet_by_name(sys.argv[2])
else:
	sheet = wb.active


print('Start')

language = ["English", "traditional Chinese", "simplified Chinese", "French", "Spanish", "German", "Japanese", "Korean", "Russian", "Italian"]
area_code = ["", "-zh-rTW", "-zh-rCN", "-fr", "-es", "-de", "-ja", "-ko", "-ru", "-it"]

xml = minidom.getDOMImplementation()

# iOS内容
localizableContent = ''

for index, code in enumerate(area_code):
	dom = xml.createDocument(None, 'resources', None)
	root = dom.documentElement
	# 对某一特定的列进行遍历 第三列为“key”
	for i, cell in enumerate(list(sheet.columns)[3]):
		if cell.value is None:
			# 遇到key为空结束循环
			break

		value = sheet.cell(i + 1, index + 5).value
		# 空单元格不添加
		if not value is None:
			element = dom.createElement('string')
			if isinstance(value, str):
				# 去除左右两边空格、换行
				element.appendChild(dom.createTextNode(value.strip()))
				localizableContent += "\\"\\" = \\"\\"\\n".format(cell.value, value.strip().replace('"','\\\\"'))
			else:
				# 非字符类型转化为str,例如数字。
				element.appendChild(dom.createTextNode(str(value)))
				localizableContent += "\\"\\" = \\"\\"\\n".format(cell.value, str(value))

			element.setAttribute('name', cell.value)
			root.appendChild(element)

	# 保存安卓string.xml文件
	with open('string' + code + '.xml', 'w', encoding='utf-8') as f:
		dom.writexml(f, addindent='\\t', newl='\\n', encoding='utf-8')

	localizableContent += "\\n\\n"
	print(language[index] + ' Complete!')

# iOS文件统一写入部分
with open('Localizable.strings', 'w', encoding='utf-8') as file_object:
    file_object.write(localizableContent)

print('End')

PS :注意这里的代码是根据表格内容格式实现的,并不具有通用性。

代码里还处理了几件事:

  • 去除文案前后有时多出来的空格和换行。
  • iOS部分会将引号转义。
  • 如果value为空,则不添加。避免程序获取文字为空。
  • 由于Android部分使用的minidom来处理xml,所以会自动转义,避免了使用"<“字符和”&"字符的影响。

使用起来很简单,执行命令python language_convert_strings.py xxx.xlsx


输出结果:

如果有些文案是不需要或者key的名称问题,可以一开始整理好表格内容再转换。然后直接将结果复制进项目就好了。

优化

这个脚本它也有一些限制,因为是用Python写的,所以它需要使用者的电脑有Python环境和对应的工具模块。为了便于组内的同学使用,那就需要将脚本打包成可执行文件。这里就用到了PyInstaller,它的作用是将 Python 程序打包成一个独立可执行软件包,支持 Windows、Linux 和 Mac OS X。

所以我需要写一个简单的图形界面,刚好用python自带Tkinter模块。最终代码如下:

import sys
import openpyxl
import xml.dom.minidom as minidom
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showinfo

def file_open():
    filepath = askopenfilename(title="Select xlsx file", filetypes = (('xlsx files', '*.xlsx'),))  # 获得文件
    if filepath:
        v.set(filepath)
        print(v.get())

def convert():
	if v.get() == '':
		showinfo(title = '错误', message = '请选择文件!')
		return

	try:
		wb = openpyxl.load_workbook(v.get())
	except Exception as e:
		showinfo(title = '错误', message = str(e))
		return


	sheet = wb.active

	area_code = ["", "-zh-rTW", "-zh-rCN", "-fr", "-es", "-de", "-ja", "-ko", "-ru", "-it"]

	xml = minidom.getDOMImplementation()

	# iOS内容
	localizableContent = ''

	for index, code in enumerate(area_code):
		dom = xml.createDocument(None, 'resources', None)
		root = dom.documentElement
		# 对某一特定的列进行遍历 第三列为“key”
		for i, cell in enumerate(list(sheet.columns)[3]):
			if cell.value is None:
				# 遇到key为空结束循环
				break

			value = sheet.cell(i + 1, index + 5).value
			# 空单元格不添加
			if not value is None:
				element = dom.createElement('string')
				if isinstance(value, str):
					# 去除左右两边空格、换行
					element.appendChild(dom.createTextNode(value.strip()))
					localizableContent += "\\"\\" = \\"\\"\\n".format(cell.value, value.strip().replace('"','\\\\"'))
				else:
					# 非字符类型转化为str,例如数字。
					element.appendChild(dom.createTextNode(str(value)))
					localizableContent += "\\"\\" = \\"\\"\\n".format(cell.value, str(value))

				element.setAttribute('name', cell.value)
				root.appendChild(element)

		# 保存安卓string.xml文件
		with open('string' + code + '.xml', 'w', encoding='utf-8') as f:
			dom.writexml(f, addindent='\\t', newl='\\n', encoding='utf-8')

		localizableContent += "\\n\\n"

	# iOS文件统一写入部分
	with open('Localizable.strings', 'w', encoding='utf-8') as file_object:
	    file_object.write(localizableContent)

	showinfo(title = '完成', message = '转换完成!')


if __name__ == '__main__':
    root = Tk()
    root.geometry('300x100')
    root.wm_title('多语言文案表格转换工具')
    frame = Frame(root)
    frame.pack(padx = 10, pady = 10)
    frame1 = Frame(root)
    frame1.pack(padx = 10, pady = 10)

    v = StringVar()
    entry = Entry(frame, width = 20, textvariable = v).pack(fill = X, side = LEFT)
    btn = Button(frame, text='选择文件', width = 20, command = file_open).pack(fill = X, padx = 10)
    btn1 = Button(frame1, text='转换', width = 20, command = convert).pack(fill = X, padx = 10)
    root.mainloop()

然后使用命令pyinstaller -F -w language_convert_strings.py打包就行了。

下面简单演示一下(mac 版):

然后选择需要转换的文件,点击转换按钮。

如果文件路径错误,提示:

添加图形界面的好处:

  • 便于使用操作。
  • 选择文件时可以限制文件格式。
  • 良好的提示信息。

当然这个小工具还可以进一步优化,比如可以指定输出目录,直接将结果添加到项目文件中。具体在后面使用中再不断去改进它。


本篇提供一个解决此类重复性高问题的思路,希望可以对你有启发作用。

以上是关于实现一个多语言文案快速转换工具的主要内容,如果未能解决你的问题,请参考以下文章

实现一个多语言文案快速转换工具

App Languages 批量导入管理flutter多语言文案

App Languages 批量导入管理flutter多语言文案

App Languages 批量导入管理flutter多语言文案

App Languages 批量导入管理Android多语言文案

App Languages 批量导入管理Android(安卓)多语言文案