2013-03-24 47 views
2

我需要合并/更新/删除.po文件消息,并需要一些Python包,它允许我完全解析.po文件,包括:消息,复数,位置,上下文和注释。是否有任何允许解析.po文件(消息,包括上下文注释)的Python包?

我想做一个简单的工具来检查文件之间的差异。我也可以使用一些图形用户界面已经完成,但不知道是否有这样的工具,将添加新的翻译或删除未使用的翻译。

我在搜索一些文章,但没有找到如何去做。请推荐一些可完全解析.po的Python软件包(可以是其他语言)或工具来完成这样重要的任务,以保持良好的翻译。

回答

1

你不需要花哨的工具来阅读.po文件;他们是纯文本文件,基本上包含消息/翻译对:

#: buttons.c:425 
msgid "Extra" 
msgstr "Thêm" 

#: buttons.c:433 
msgid "Help" 
msgstr "Trợ giúp" 

对于一个简单的工具来比较他们,我会建议使用diff -u

有一个.mo扩展名的二进制格式。您可以使用gettext-tools包中的msgunfmt程序将它们转换回纯文本。从.po文件

提取ID /翻译对并不难:

In [1]: po = '''#: buttons.c:425 
    ...: msgid "Extra" 
    ...: msgstr "Thêm" 
    ...: 
    ...: #: buttons.c:433 
    ...: msgid "Help" 
    ...: msgstr "Trợ giúp" 
    ...: 
    ...: ''' 

In [2]: import re 

In [3]: re.findall('^msgid \"(.*)\"', po, re.MULTILINE) 
Out[3]: ['Extra', 'Help'] 

In [4]: re.findall('^msgstr \"(.*)\"', po, re.MULTILINE) 
Out[4]: ['Th\xc3\xaam', 'Tr\xe1\xbb\xa3 gi\xc3\xbap'] 

In [5]: zip(re.findall('^msgid \"(.*)\"[^\"]*', po, re.MULTILINE), re.findall('^msgstr \"(.*)\"[^\"]*', po, re.MULTILINE)) 
Out[5]: [('Extra', 'Th\xc3\xaam'), ('Help', 'Tr\xe1\xbb\xa3 gi\xc3\xbap')] 

我使用的^re.MULTILINE防止注释掉的消息在这里露面。作为完整性检查,确保包含消息ID和消息字符串的列表长度相等。

编辑:你有一个关于随机指定和使用diff有效的观点。但是,您可以使用上面的代码为旧的和新的.po文件创建(消息ID,翻译)元组的列表。如果您通过消息ID对这些列表进行排序,则可以使用difflib.unified_diff来显示差异。

例如:

In [1]: import re, itertools, difflib 

#I've used cpaste to input two pieces of a .po file, the latter with some changes 

In [4]: orig_po 
Out[4]: '#: mixedgauge.c:64\nmsgid "Passed"\nmsgstr "\xc4\x90\xe1\xbb\x97"\n\n#: mixedgauge.c:67\nmsgid "Completed"\nmsgstr "Ho\xc3\xa0n to\xc3\xa0n"\n\n#: mixedgauge.c:70\nmsgid "Checked"\nmsgstr "\xc4\x90\xc3\xa3 ki\xe1\xbb\x83m tra"\n\n#: mixedgauge.c:73\nmsgid "Done"\nmsgstr "Ho\xc3\xa0n t\xe1\xba\xa5t"\n\n#: mixedgauge.c:76\nmsgid "Skipped"\nmsgstr "B\xe1\xbb\x8b b\xe1\xbb\x8f qua"\n\n#: mixedgauge.c:79\nmsgid "In Progress"\nmsgstr "\xc4\x90ang ch\xe1\xba\xa1y"\n\n#: mixedgauge.c:85\nmsgid "N/A"\nmsgstr "Kh\xc3\xb4ng c\xc3\xb3"\n\n#: mixedgauge.c:193\nmsgid "Overall Progress"\nmsgstr "To\xc3\xa0n ti\xe1\xba\xbfn h\xc3\xa0nh"\n' 

In [5]: changed_po 
Out[5]: '#: mixedgauge.c:64\nmsgid "Passed"\nmsgstr "\xc4\x90\xe1\xbb\x97"\n\n#: mixedgauge.c:193\nmsgid "Overall Progres"\nmsgstr "To\xc3\xa0n ti\xe1\xba\xbfn h\xc3\xa0nh"\n\n#: mixedgauge.c:67\nmsgid "Completed"\nmsgstr "Ho\xc3\xa0na to\xc3\xa0n"\n\n#: mixedgauge.c:76\nmsgid "Skipped"\nmsgstr "B\xe1\xbb\x8b b\xe1\xbb\x8f qua"\n\n#: mixedgauge.c:79\nmsgid "In Progress"\nmsgstr "\xc4\x90ang ch\xe1\xba\xa1y"\n\n#: mixedgauge.c:85\nmsgid "N/A"\nmsgstr "Kh\xc3\xb4ng c\xc3\xb3e"\n\n#: mixedgauge.c:70\nmsgid "Checked"\nmsgstr "\xc4\x90\xc3\xa3 ki\xe1\xbb\x83m tra"\n\n#: mixedgauge.c:73\nmsgid "Done"\nmsgstr "Ho\xc3\xa0n t\xe1\xba\xa5t"\n' 

# Making a list of tuples 

In [6]: orig_list = zip(re.findall('^(msgid \".*\")', orig_po, re.MULTILINE), re.findall('^(msgstr \".*\")', orig_po, re.MULTILINE)) 

In [7]: changed_list = zip(re.findall('^(msgid \".*\")', changed_po, re.MULTILINE), re.findall('^(msgstr \".*\")', changed_po, re.MULTILINE)) 

# Sort them by the message-id 

In [8]: orig_list.sort(key=lambda t: t[0]) 

In [9]: changed_list.sort(key=lambda t: t[0]) 

# Now flatten the list 

In [10]: orig_string_list = [i for i in itertools.chain(*orig_list)] 

In [11]: changed_string_list = [i for i in itertools.chain(*changed_list)] 

In [12]: orig_list[0:3] 
Out[12]: [('msgid "Checked"', 'msgstr "\xc4\x90\xc3\xa3 ki\xe1\xbb\x83m tra"'), ('msgid "Completed"', 'msgstr "Ho\xc3\xa0n to\xc3\xa0n"'), ('msgid "Done"', 'msgstr "Ho\xc3\xa0n t\xe1\xba\xa5t"')] 

In [13]: orig_string_list[0:6] 
Out[13]: ['msgid "Checked"', 'msgstr "\xc4\x90\xc3\xa3 ki\xe1\xbb\x83m tra"', 'msgid "Completed"', 'msgstr "Ho\xc3\xa0n to\xc3\xa0n"', 'msgid "Done"', 'msgstr "Ho\xc3\xa0n t\xe1\xba\xa5t"'] 

# print the diff 

In [14]: for l in difflib.unified_diff(orig_string_list, changed_string_list, fromfile='original', tofile='changed'): 
    ....:  print l 
    ....:  
--- original 

+++ changed 

@@ -1,14 +1,14 @@ 

msgid "Checked" 
msgstr "Đã kiểm tra" 
msgid "Completed" 
-msgstr "Hoàn toàn" 
+msgstr "Hoàna toàn" 
msgid "Done" 
msgstr "Hoàn tất" 
msgid "In Progress" 
msgstr "Đang chạy" 
msgid "N/A" 
-msgstr "Không có" 
-msgid "Overall Progress" 
+msgstr "Không cóe" 
+msgid "Overall Progres" 
msgstr "Toàn tiến hành" 
msgid "Passed" 
msgstr "Đỗ" 
+0

感谢您的建议 - 我想避免编写另一个解析器,但正如您所说,编写解析器非常容易。无论如何,仍然认为有更高层次的解决方案。 Diff -u不适用于比较,因为字符串的顺序可能是随机的 - 如果.po文件将完全解析,可以对它进行排序并尝试winmerge,但它仍然是低级别的 - 我想将它简化为右,左,删除,添加。译者可能会犯错误,并产生高昂的测试和调试代价,不会让他们犯错误,包括我:) – Chameleon 2013-03-25 08:05:19

+0

@Chameleon我已经添加了一个示例如何在python中创建_sorted_统一差异。 – 2013-03-25 20:31:01

+0

谢谢 - 我目前正在测试PoEdit + Google翻译工具包。它不完美,但看起来可以使用。这是非常好的自动化,请参阅翻译工具包(底部) - http://translate.google.com/。 我会尽快研究你的代码。 – Chameleon 2013-03-26 12:20:27

2

尝试babel模块。它包括babel.messages.catalogbabel.messages.pofile等中的.po解析器。

+0

非常感谢。我会很快尝试。我正在编写一些开源的Python i18n eclipse插件,可能会包含合并po文件。 – Chameleon 2013-03-26 12:22:46

4

polib包很不错。它解析文件并提供几种访问数据的方式,包括一个循环遍历msgid,msgstr对的迭代器以执行您所需的任何操作。这里是Quick Start documentation

如果.po不可用,它也可以解析.mo,特别是处理过时的消息字符串,迭代仅翻译的字符串以及其他不错的功能。

相关问题