Python中国际化(i18n)完整指南

Python中国际化(i18n)完整指南

这是一个完整的指南,展示了如何为一个Python应用程序进行国际化(i18n)。当我在handroll项目中添加i18n时,我很难找到支持其他语言的明确建议。这是我个人的一点经验,解释了我是如何做到这一点的。

目录:

  • 标记字符串
  • 提取主列表
  • 获得其他语言的翻译
  • 打包在一起
  • 测试包
  • 问题?

概述

要使代码国际化,您必须以一种特定的方式处理用户文本字符串。所有的文本字符串都必须用一个特殊的函数调用来包装。这个特殊的函数将字符串标记为需要翻译的东西。一旦所有的字符串都被标记之后,i18n工具就可以扫描您的代码,生成一个包含所有内容的主列表。有了主列表,翻译器就可以为每种需要的语言生成一个翻译后的字符串列表。翻译后的字符串被添加回Python代码中,这些字符串都被打包成一个很好的翻译后的最终产品。然后您可能就想测试一下。

这牵扯到很多东西,但是我将详细解释这个过程的每一部分。出于本指南的目的,我的所有示例代码都将引用handroll包。如果这是您的Python代码,请用您的顶级Python包的名称替换handroll。

标记字符串

我在概述中提到的特殊函数看起来像_('Hello World')。这个函数来自gettext模块。Python使用GNU gettext进行翻译,所以让我们看看在handroll/i18n.py中创建_函数的handroll代码。

Python中国际化(i18n)完整指南

这一小段代码使用locale目录作为已翻译字符串的源来创建一个翻译对象。您的locale目录还不存在,但它是您的应用程序在运行时查找译文的地方。从translation对象中,我为translation .gettext创建了一个_ 别名。这个下划线并不是特别特殊,但是,它是Python社区所使用的这个函数的常见名称。

我希望现在这里有足够的内容来帮助我们去理解运行时将发生什么。重要的是,“Hello World”就像一个键。当代码执行时,该“键”将用于查找本地化数据,以找到一个匹配的翻译。_的返回值将是翻译后的字符串,如果翻译缺失,返回值将是原始字符串。

_ and format strings

如果您为您的字串使用format,您很快就会遇到一个奇怪的情况,那就是在哪里关闭_圆括号。这里有一个例子可以说明这一点。

Python中国际化(i18n)完整指南

提取主列表

使用_()将所有字符串标记之后,现在是将它们提取到一个主列表中的时候了。Gettext会将这个主列表引用为Portable Object Template (POT)文件。为了生成该POT文件,我使用了一个名为Babel的工具。Babel旨在帮助开发人员以多种方式处理i18n问题。它有很多很酷的特性,但在本指南中,我将重点介绍它对gettext的支持。

Babel使用新命令扩展了一个setup.py文件。(Python打包超出了本指南的范围,所以如果setup.py对您来说是完全陌生的,请查看《分发Python模块》以获得更多信息。

要生成一个POT文件,请运行python setup.py extract_messages。您将需要一些类似这样的设置:

Python中国际化(i18n)完整指南

获得其他语言的翻译

现在您已经生成了一个POT文件,您已经准备好获取您的字符串的翻译版本了。记住,POT中的T是表示模板。翻译后的文件称为PO文件,翻译人员使用该POT文件作为一个起点来生成他们的PO文件。通过手动创建PO文件来进行翻译是可能的,但是这很单调。此时,我转向一个名为Transifex的服务。

Transifex致力于使翻译变得简单。它对开源项目是免费的,而且非常容易使用。我为handroll设置了一个项目,并配置了Transifex来“监视”POT文件的变化,这样翻译器就可以轻松地翻译本项目中的所有字符串。Transifex有一个API,可以让我在需要的时候把PO文件拖回存储库。这个脚本太长了,不适合放在本文中,但是您可以在GitHub上查看它。

此脚本所做的一件重要事情是将PO文件以一种特定的结构存储在locale目录中。Gettext期望一个类似于<language>/LC_MESSAGES/handroll.po的顺序。

打包在一起

翻译后的PO文件就绪后,您就可以打包您的翻译数据了。设置过程所包括的额外数据在MANIFEST.in中。添加一个类似下面的行,以确保将所有locale数据被放入包存档中。

recursive-include handroll/locale *

到目前为止,为了解释清楚,我撒了个小谎。Gettext并不直接使用PO文件来查找译文。事实上,PO文件必须被编译成一个二进制机器对象(MO)文件(为了获得更快的速度)。我们可以再次向Babel求助。Babel有一个compile_catalog命令,可以将PO编译成MO。您可以使用python setup.py compile_catalog来运行它。

它需要如下设置:

Python中国际化(i18n)完整指南

因为没有MO文件,译文就无法起作用,所以我扩展了setup.py,以便sdist命令将始终运行compile_catalog。

Python中国际化(i18n)完整指南

如果您要这样做,请不要忘记在您的setup调用中添加cmdclass={'sdist': Sdist} 和 setup_requires=['Babel']。

此时,运行python setup.py sdist应该会为您的项目创建一个带有翻译的tarball。您几乎就完成了!

测试该包

测试翻译并不容易。如果您多做一点此测试,您就会知道来自不同文化的人都可以享受您的软件。但是翻译测试并不容易,因为您需要运行代码中的每个字符串的测试。对于handroll来说,那意味着我必须达到100%的测试覆盖率,才能得到那些非常奇怪的边角情况。

测试的原因是因为不正确翻译的字符串会破坏您的代码。如果您有一个像_('Hello {name}!').format(name='Johnny')这样的格式字符串,并且翻译人员犯了一个像'¡Hola {nombre}!'这样的错误!,然后该代码对西班牙用户来说就会崩溃。

Python中国际化(i18n)完整指南

要测试这些字符串,您需要两样东西:MO文件和 LANGUAGE环境变量。我们假设您使用的是nose运行器。要测试您的西班牙语支持,您可以运行:

Python中国际化(i18n)完整指南

在您使用的任何持续集成系统中,对您支持的每种语言运行您的单元测试,会给您一些信心,让您相信您的翻译没有破坏软件。handroll tox.ini提供了一个可以比较的例子。Tox对这类东西来说是非常棒的。

问题?

在本指南中,我尽我最大的努力记录了我为使我的项目国际化所做的一切。我希望所有的具体细节都能帮助您了解如何翻译您自己的项目。如果有什么东西丢了或损坏了,请及时告诉我,我很乐意更新此帖。

英文原文:https://www.mattlayman.com/blog/2015/i18n/

译者:好酒不上头

相关推荐