用 Python 管理 Android 中 strings.xml 的字符翻译

对于一个带有多种语言的 Android 应用。如果要修改某个字符某种语言的翻译,就要去修改该语言对应的 strings.xml 文件字符的内容。这样操作比较麻烦,也容易出错。于是,就想着利用 Excel 表格的可读性和易于管理性,通过 Python 脚本将 Excel 表格转化成 strings.xml 对应的字符。该脚本的源码见:https://github.com/heray1990/txt2xml

构建 Excel 表格

假设在我们的 Android 应用里,values-zh/ 目录下的 strings.xml 文件内容如下:

<?xml version="1.0" ?>
<resources>
  <string name="Main.MenuShowHistory">历史</string>
  <string name="Main.MenuShowDownloads">下载</string>
  <string name="Main.MenuPreferences">配置</string>
  <string name="PreferencesActivity.EnableJavascriptPreferenceSummary">如果不支持JavaScript,很多网站效果不能打开,建议打开.</string>
</resources>

根据上述 strings.xml 文件的内容,我们在 Excel 中创建类似如下表格(翻译不一定准确,仅供参考):

zhfresde
Main.MenuShowHistory历史HistoriqueHistorialVerlauf
Main.MenuShowDownloads下载TéléchargementsDescargasDownloads
Main.MenuPreferences配置PréférencesPreferenciasEinstellungen
PreferencesActivity.EnableJavascriptPreferenceSummary如果不支持JavaScript,很多网站效果不能打开,建议打开.Active ou désactive le JavaScript.Activar o desactivar JavaScript.JavaScript ein-/ausschalten.

其中,第一行表示了 Android 应用中不同语言的语言简码。例如,我们的应用中有中文、法语、西班牙语和德语,那么对应的表格第一行就有 zh、fr、es和de。

表格中的第一列则对应 strings.xml 文件中 <string> 节点 name 属性的值。

表格中剩下的部分对应 strings.xml 文件中 <string> 节点的值。例如:“历史”就是 Main.MenuShowHistory 对应的中文翻译。

生成 Unicode txt 文件

构建完 Excel 表格之后,将内容保存到 Unicode txt 文件中。即在 Excel 软件里面:另存为 -> Unicode 文本(*.txt)。这样就生成了 Python 可以解析的 txt 文件(假设我们这里的文件名字为:strings.txt)。内容如下:

    zh  fr  es  de
Main.MenuShowHistory    历史  Historique  Historial   Verlauf
Main.MenuShowDownloads  下载  Téléchargements Descargas   Downloads
Main.MenuPreferences    配置  Préférences Preferencias    Einstellungen
PreferencesActivity.EnableJavascriptPreferenceSummary   如果不支持JavaScript,很多网站效果不能打开,建议打开.    Active ou désactive le JavaScript.  Activar o desactivar JavaScript.     JavaScript ein-/ausschalten.

解析 Unicode txt 文件

注意到,从 Excel 表格生成的 strings.txt Unicode txt 文件里,每个单元格之间使用制表符 '\t' 隔开。在解析的时候可以通过检测制表符来获取每个单元格的内容。

由于 strings.txt 的内容是以 Unicode 进行编码,因此需要先将 Unicode 转成 utf-8,便于后面的字符处理。这要用到 codecs 模块,此部分的代码如下:

        cwd = os.path.dirname(sys.argv[0])
        self.txt_fd = codecs.open(os.path.join(cwd,txt_fname),'r','utf-16')

        ls = [line.strip().encode('utf-8') for line in self.txt_fd]
        self.txt_fd.close()

其中,我们将 strings.txt 文件中的每一行作为列表的一个元素保存到列表 ls 中。此时,我们已经初步将 strings.txt 的内容提取出来。

接下来,我们对提取出来的内容做进一步的分解。将第一行的语言简码保存到 self.langls 列表中,用于后面根据不同的语言生成不同的 values-* 目录。

Note: Android 中,不同语言的 strings.xml 文件被放到不同的 values-* 目录。例如,中文的 strings.xml 文件会放到 values-zh 目录。而 zh 就是对应于 Excel 表格第一行(ls[0])的语言简码。

获取语言简码的代码如下:

        self.langls = ls[0].split('\t')

最后,将字符的变量名和对应的字符翻译放到一个字典 self.stringdict 中。其中变量名为 key,字符的翻译为 value。以字典的形式保存字符翻译,便于后面的操作。这部分的代码如下:

        lskey = []
        lsval = []
        for i in ls[1:]:
            subls = i.split('\t')
            lskey.append(subls[0])
            lsval.append(subls[1:])

        self.stringdict = collections.OrderedDict(zip(lskey,lsval))

其中,lskey 列表保存了表格中第一列的字符变量名。该列表的内容应该如下:

['Main.MenuShowHistory', 'Main.MenuShowDownloads', 'Main.MenuPreferences', 'PreferencesActivity.EnableJavascriptPreferenceSummary']

lsval 列表则保存了字符翻译的值,该列表的内容如下:

[['\xe5\x8e\x86\xe5\x8f\xb2', 'Historique', 'Historial', 'Verlauf'], ['\xe4\xb8\x8b\xe8\xbd\xbd', 'T\xc3\xa9l\xc3\xa9chargements', 'Descargas', 'Downloads'], ['\xe9\x85\x8d\xe7\xbd\xae', 'Pr\xc3\xa9f\xc3\xa9rences', 'Preferencias', 'Einstellungen'], ['\xe5\xa6\x82\xe6\x9e\x9c\xe4\xb8\x8d\xe6\x94\xaf\xe6\x8c\x81JavaScript\xef\xbc\x8c\xe5\xbe\x88\xe5\xa4\x9a\xe7\xbd\x91\xe7\xab\x99\xe6\x95\x88\xe6\x9e\x9c\xe4\xb8\x8d\xe8\x83\xbd\xe6\x89\x93\xe5\xbc\x80\xef\xbc\x8c\xe5\xbb\xba\xe8\xae\xae\xe6\x89\x93\xe5\xbc\x80.', 'Active ou d\xc3\xa9sactive le JavaScript.', 'Activar o desactivar JavaScript.', ' JavaScript ein-/ausschalten.']]

collections.OrderedDict(zip()) 函数可以将两个列表转换成一个字典。下面是一个关于该函数的例子:

>>> a = ['a','b','c']
>>> b = [[1,2,3],[4,5,6],[7,8,9]]
>>> zip(a,b)
[('a', [1, 2, 3]), ('b', [4, 5, 6]), ('c', [7, 8, 9])]
>>> import collections
>>> collections.OrderedDict(zip(a,b))
OrderedDict([('a', [1, 2, 3]), ('b', [4, 5, 6]), ('c', [7, 8, 9])])

在这个地方,本来是用 dict() 函数的,即

        self.stringdict = dict(zip(lskey,lsval))

但是由于在 Python 中,字典是无序的。这样会导致产生字典的字符顺序与最初 Excel 表格的字符顺序不一致。下面是用 dict() 函数的例子:

>>> a = ['a','b','c']
>>> b = [[1,2,3],[4,5,6],[7,8,9]]
>>> zip(a,b)
[('a', [1, 2, 3]), ('b', [4, 5, 6]), ('c', [7, 8, 9])]
>>> dict(zip(a,b))
{'a': [1, 2, 3], 'c': [7, 8, 9], 'b': [4, 5, 6]}

可以看到用 dict() 函数输出的字典键值对的顺序与输入的时候不一致。而 collections.OrderedDict() 则可以保证输入输出前后字典键值对的顺序一致。

补充:

下面提供一种更加简单的方法来生成 self.stringdict(上面的方法有点啰嗦,其实字典是可以直接地构建的):

        for i in ls[1:]:
            subls = i.split('\t')
            self.stringdict[subls[0]] = subls[1:]

生成 strings.xml 文件

首先,我们要根据前面提到的 self.langls 列表来生成不同语言的目录 values-*。下面是这部分的代码:

        for j in self.langls:
            # Create the directories according to the language.
            os.mkdir(XML_FILE_DIR_PREFIX + j)

然后,就是调用 Python 的 xml.dom.minidom 模块构建 XML 的节点和相关的内容。其中,字符对应语言的翻译是从 self.stringdict 字典提取出来。相关代码如下:

            doc = Document()
            resources = doc.createElement("resources")
            doc.appendChild(resources)

            for k,v in self.stringdict.items():
                stringele = doc.createElement("string")
                stringele.setAttribute("name",k)
                text = doc.createTextNode(v[self.langls.index(j)])
                stringele.appendChild(text)
                resources.appendChild(stringele)

最后,生成 strings.xml 文件:

            uglyXml = doc.toprettyxml(indent='  ')
            text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)    
            prettyXml = text_re.sub('>\g<1></', uglyXml)

            self.xmlfd = open(os.path.join(XML_FILE_DIR_PREFIX + j,XML_FILE_NAME),'w')
            #doc.writexml(self.xmlfd)
            self.xmlfd.write(prettyXml)
            self.xmlfd.close()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值