16.3. gettext — 翻译消息 | 国际化和本地化 |《python 3 标准库实例教程》| python 技术论坛-江南app体育官方入口
目的:用于国际化的消息目录api。
gettext
模块提供了与gnu gettext 库兼容的纯 python 实现,用于消息翻译和目录管理。 python 源分发版提供的工具使您能够从一组源文件中提取消息,构建包含翻译的消息目录,并使用该消息目录在运行时为用户显示适当的消息。
消息目录可用于为程序提供国际化的界面,以适合用户的语言显示消息。它们还可以用于其他消息自定义,包括为不同包装程序或江南app体育官方入口的合作伙伴“设置”界面外观。
注意
尽管标准库文档说 python 随附了所有必需的工具,但即使使用适当的命令行选项,
pygettext.py
也无法提取包装在ngettext
调用中的消息。这些示例改用gnu gettext工具集中的xgettext
。
翻译工作流程概述
设置和使用翻译的过程包括五个步骤。
- 在源代码中标识并标记包含要翻译的消息的文字字符串。
首先确定程序源中需要翻译的消息,并标记文字字符串,以便提取程序可以找到它们。
- 提取消息。
在源中识别出可翻译字符串后,使用xgettext
提取它们并创建一个.pot
文件或翻译模板。模板是一个文本文件,其中包含所有已标识字符串的副本以及其翻译的占位符。
- 翻译消息。
将.pot
文件的副本提供给翻译器,将扩展名更改为.po
。 .po
文件是可编辑的源文件,用作编译步骤的输入。翻译人员应更新文件中的标题文本,并提供所有字符串的翻译。
- “翻译”来自翻译的消息目录。
转换器将已完成的.po
文件发送回时,请使用msgfmt
将文本文件编译为二进制目录格式。运行时目录查找代码使用二进制格式。
- *在运行时加载并激活适当的消息目录。
最后一步是向应用程序添加几行,以配置和加载消息目录并安装翻译功能。有两种方法可以实现此目的,同时需要进行权衡取舍。
本节的其余部分将从需要的代码修改开始,对这些步骤进行更详细的研究。
从源代码创建消息目录
gettext
的工作方式是在翻译数据库中查找文字字符串,然后提取适当的翻译字符串。通常的模式是将适当的查找函数绑定到名称“ _
”(单个下划线字符),以使代码不会因调用多个具有较长名称的函数而混乱。
消息提取程序xgettext
查找在对目录查找功能的调用中嵌入的消息。它了解不同的源语言,并为每种语言使用适当的解析器。如果查找功能是别名或添加了其他功能,请在提取消息时给xgettext
名称以考虑其他符号。
该脚本只有一条消息可供翻译。
gettext_example.py
import gettext
# 设置消息目录访问
t = gettext.translation(
'example_domain', 'locale',
fallback=true,
)
_ = t.gettext
print(_('this message is in the script.'))
文本"this message is in the script."
是要从目录中替换的消息。启用了回退模式,因此,如果在没有消息目录的情况下运行脚本,则会打印内联消息。
$ python3 gettext_example.py
this message is in the script.
下一步是使用pygettext.py
或xgettext
提取消息并创建.pot
文件。
$ xgettext -o example.pot gettext_example.py
产生的输出文件包含以下内容。
example.pot
#一些描述性标题。
#江南app体育官方入口的版权所有(c)套餐的江南app体育官方入口的版权持有人
#此文件与package软件包使用相同的许可证分发。
#第一作者,年份。
#
#,模糊
msgid ""
msgstr ""
"project-id-version: package version."
"report-msgid-bugs-to: ."
"pot-creation-date: 2018-03-18 16:20-0400."
"po-revision-date: year-mo-da ho:mi zone."
"last-translator: full name ."
"language-team: language <[email protected]>."
"language: ."
"mime-version: 1.0."
"content-type: text/plain; charset=charset."
"content-transfer-encoding: 8bit."
#: gettext_example.py:19
msgid "this message is in the script."
msgstr ""
消息目录安装在按域和语言组织的目录中。域由应用程序或库提供,通常是唯一的值,例如应用程序名称。在这种情况下,gettext_example.py
中的域是example_domain
。语言值由用户的环境在运行时通过环境变量language
,lc_all
,lc_messages
或lang
中的一个来提供,具体取决于其配置和平台。这些示例均以设置为en_us
的语言运行。
现在已经准备好模板,下一步是创建所需的目录结构,并将模板复制到正确的位置。这些示例的pymotw源树中的locale
目录将用作消息目录目录的根目录,但是通常最好使用系统范围可访问的目录,以便所有用户都可以访问消息目录。目录输入源的完整路径为$ localedir / $ language / lc_messages / $ domain.po
,实际目录的文件扩展名为.mo
。
通过将example.pot
复制到locale / en_us / lc_messages / example.po
并进行编辑以更改标题中的值并设置备用消息来创建目录。结果如下所示。
locale/en_us/lc_messages/example.po
# 来自gettext_example.py的消息。
#江南app体育官方入口的版权所有(c)2009 doug hellmann
#doug hellmann <[email protected]>,2016年。
#
msgid ""
msgstr ""
"project-id-version: pymotw-3."
"report-msgid-bugs-to: doug hellmann <[email protected]>."
"pot-creation-date: 2016-01-24 13:04-0500."
"po-revision-date: 2016-01-24 13:04-0500."
"last-translator: doug hellmann <[email protected]>."
"language-team: us english <[email protected]>."
"mime-version: 1.0."
"content-type: text/plain; charset=utf-8."
"content-transfer-encoding: 8bit."
#: gettext_example.py:16
msgid "this message is in the script."
msgstr "this message is in the en_us catalog."
该目录是使用msgformat
从.po
文件构建的。
$ cd locale/en_us/lc_messages; msgfmt -o example.mo example.po
gettext_example.py
中的域是example_domain
,但文件名为example.pot
。要使gettext
找到正确的翻译文件,名称必须匹配。
gettext_example_corrected.py
t = gettext.translation(
'example', 'locale',
fallback=true,
)
现在,当运行脚本时,将打印目录中的消息,而不是内联字符串。
$ python3 gettext_example_corrected.py
this message is in the en_us catalog.
在运行时查找消息目录
如前所述,包含消息目录的 locale目录 是根据语言来组织的,目录具有以程序的 domain 命名的目录。不同的操作系统定义了自己的默认值,但是gettext
并不知道所有这些默认值。它使用默认的语言环境目录sys.prefix '/ share / locale'
,但是在大多数情况下,始终显式给出localedir
值比依赖于此更安全默认有效。 find()
函数负责在运行时查找适当的消息目录。
gettext_find.py
import gettext
catalogs = gettext.find('example', 'locale', all=true)
print('catalogs:', catalogs)
路径的语言部分来自可用于配置本地化功能的几个环境变量之一(language
,lc_all
,lc_messages
和lang
)。使用发现要设置的第一个变量。通过使用冒号(:
)分隔值,可以选择多种语言。要查看其工作原理,请使用第二个消息目录进行一些实验。
$ cd locale/en_ca/lc_messages; msgfmt -o example.mo example.po
$ cd ../../..
$ python3 gettext_find.py
catalogs: ['locale/en_us/lc_messages/example.mo']
$ language=en_ca python3 gettext_find.py
catalogs: ['locale/en_ca/lc_messages/example.mo']
$ language=en_ca:en_us python3 gettext_find.py
catalogs: ['locale/en_ca/lc_messages/example.mo',
'locale/en_us/lc_messages/example.mo']
$ language=en_us:en_ca python3 gettext_find.py
catalogs: ['locale/en_us/lc_messages/example.mo',
'locale/en_ca/lc_messages/example.mo']
尽管find()
显示了目录的完整列表,但实际上仅加载序列中的第一个用于消息查找。
$ python3 gettext_example_corrected.py
this message is in the en_us catalog.
$ language=en_ca python3 gettext_example_corrected.py
this message is in the en_ca catalog.
$ language=en_ca:en_us python3 gettext_example_corrected.py
this message is in the en_ca catalog.
$ language=en_us:en_ca python3 gettext_example_corrected.py
this message is in the en_us catalog.
多个值
尽管简单的消息替换将满足大多数翻译需求,但gettext
会处理复数形式作为特殊情况。根据语言的不同,消息的单数形式和复数形式之间的差异可能仅因单个单词的结尾而有所不同,或者整个句子结构可能有所不同。取决于复数的水平,也可以有不同的形式。为了简化复数的管理(在某些情况下可能),有一组单独的函数用于请求消息的复数形式。
gettext_plural.py
from gettext import translation
import sys
t = translation('plural', 'locale', fallback=false)
num = int(sys.argv[1])
msg = t.ngettext('{num} means singular.',
'{num} means plural.',
num)
# 仍然需要自己将值添加到消息中。
print(msg.format(num=num))
使用ngettext()
访问消息的复数替换。参数是要翻译的消息和项目计数。
$ xgettext -l python -o plural.pot gettext_plural.py
由于存在要翻译的其他形式,因此替换形式在数组中列出。使用数组可以翻译具有多种复数形式的语言(例如,波兰语的不同形式表示相对数量)。
plural.pot
#一些描述性标题。
#江南app体育官方入口的版权所有(c)套餐的江南app体育官方入口的版权持有人
#此文件与package软件包使用相同的许可证分发。
#第一作者,年份。
#
#,模糊
msgid ""
msgstr ""
"project-id-version: package version."
"report-msgid-bugs-to: ."
"pot-creation-date: 2018-03-18 16:20-0400."
"po-revision-date: year-mo-da ho:mi zone."
"last-translator: full name ."
"language-team: language <[email protected]>."
"language: ."
"mime-version: 1.0."
"content-type: text/plain; charset=charset."
"content-transfer-encoding: 8bit."
"plural-forms: nplurals=integer; plural=expression;."
#: gettext_plural.py:15
#, python-brace-format
msgid "{num} means singular."
msgid_plural "{num} means plural."
msgstr[0] ""
msgstr[1] ""
除了填写翻译字符串外,还需要告知库复数的形成方式,以便知道如何为任何给定的计数值索引到数组中。 行“复数形式:nplurals = integer;“ plural = expression;”。
包含两个要手动替换的值。 nplurals
是一个整数,指示数组的大小(使用的翻译数),plural
是一种c语言表达式,用于在查找时将传入数量转换为数组中的索引译文。文字字符串n
被传递给ungettext()
的数量替换。
例如,英语包括两种复数形式。数量0
被视为复数(“ 0个香蕉”)。 复数形式
条目是:
plural-forms: nplurals=2; plural=n != 1;
然后,单数转换将在位置0处进行,而复数转换将在位置1处进行。
locale/en_us/lc_messages/plural.po
#来自gettext_plural.py的消息
#江南app体育官方入口的版权所有(c)2009 doug hellmann
#此文件在同一许可证下分发
#作为pymotw软件包。
#doug hellmann <[email protected]>,2016年。
#
#,模糊
msgid ""
msgstr ""
"project-id-version: pymotw-3."
"report-msgid-bugs-to: doug hellmann <[email protected]>."
"pot-creation-date: 2016-01-24 13:04-0500."
"po-revision-date: 2016-01-24 13:04-0500."
"last-translator: doug hellmann <[email protected]>."
"language-team: en_us <[email protected]>."
"mime-version: 1.0."
"content-type: text/plain; charset=utf-8."
"content-transfer-encoding: 8bit."
"plural-forms: nplurals=2; plural=n != 1;"
#: gettext_plural.py:15
#, python-format
msgid "{num} means singular."
msgid_plural "{num} means plural."
msgstr[0] "in en_us, {num} is singular."
msgstr[1] "in en_us, {num} is plural."
在目录编译后运行测试脚本几次将演示如何将不同的n值转换为转换字符串的索引。
$ cd locale/en_us/lc_messages/; msgfmt -o plural.mo plural.po
$ cd ../../..
$ python3 gettext_plural.py 0
in en_us, 0 is plural.
$ python3 gettext_plural.py 1
in en_us, 1 is singular.
$ python3 gettext_plural.py 2
in en_us, 2 is plural.
应用程序与模块本地化
转换工作的范围定义了gettext
的安装方式以及与代码体一起使用的方式。
应用程序本地化
对于应用程序范围的翻译,作者可以使用__ builtins __
命名空间在全局范围内安装ngettext()
之类的功能,因为它们可以控制应用程序的顶层码。
gettext_app_builtin.py
import gettext
gettext.install(
'example',
'locale',
names=['ngettext'],
)
print(_('this message is in the script.'))
install()
函数将gettext()
绑定到__ builtins __
命名空间中的名称_()
。它还添加了ngettext()
和名称
中列出的其他功能。
模块本地化
对于库或单个模块,修改__ builtins __
并不是一个好主意,因为它可能会导致与应用程序全局值冲突。相反,请在模块顶部手动导入或重新绑定翻译功能的名称。
gettext_module_global.py
import gettext
t = gettext.translation(
'example',
'locale',
fallback=false,
)
_ = t.gettext
ngettext = t.ngettext
print(_('this message is in the script.'))
切换翻译
较早的示例在程序执行期间都使用单个转换。某些情况,尤其是web应用程序,需要在不同时间使用不同的消息目录,而无需退出并重置环境。在这种情况下,gettext
中提供的基于类的api将更加方便。 api调用本质上与本节中描述的全局调用相同,但是消息目录对象是公开的,可以直接操作,因此可以使用多个目录。
另请参见
-
-[locale
](“ locale:posix文化本地化api”)–其他本地化工具。
-–此模块的消息目录格式,api等均基于gnu的原始gettext包。目录文件格式是兼容的,并且命令行脚本具有相似的选项(如果不相同)。 对文件格式进行了详细说明,并描述了使用它们的工具的gnu版本。
-–处理多种语言的单词和句子的复数形式。
-– martin vonlöwis撰写的有关python应用程序国际化技术的论文。
-–关于使用gettext的另一个很好的信息来源,包括实际示例。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 cc 协议,如果我们的工作有侵犯到您的权益,请及时联系江南app体育官方入口。