– 多语言国际化服务 – 国际化(Python教程)(参考资料)
gettext
– 多语言国际化服务
源代码: Lib / gettext.py
gettext
模块为您的Python模块和应用程序提供国际化(I18N)和本地化(L10N)服务。它同时支持GNU gettext
消息目录API和更高级别的基于类的API,可能更适合Python文件。下面介绍的界面允许您用一种自然语言编写模块和应用程序消息,并提供已翻译消息的目录,以便在不同的自然语言下运行.
还给出了一些关于本地化你的Python模块和应用程序的提示.
GNU gettext API
gettext
模块定义了以下API,与GNU gettext的API。如果使用此API,则会影响整个应用程序的全局翻译。如果您的应用程序是单语的,那么这通常就是您想要的,语言的选择取决于您的用户的名称。如果要本地化Python模块,或者如果应用程序需要动态切换语言,则可能需要使用基于类的API .
gettext.
bindtextdomain
(domain, localedir=None)-
将domain绑定到语言环境目录localedir。更具体地说,
gettext
将使用路径(在Unix上)查找给定域的二进制.mo
文件:localedir/language/LC_MESSAGES/domain.mo
,其中languages在环境变量LANGUAGE
,LC_ALL
,LC_MESSAGES
和LANG
中分别搜索如果localedir被省略或
None
,则当前绑定为domain回复。[1]
gettext.
bind_textdomain_codeset
(domain, codeset=None)-
绑定domain到codeset,更改
lgettext()
,ldgettext()
,lngettext()
和ldngettext()
函数返回的字节字符串的编码。如果codeset被省略,则返回当前绑定.
gettext.
textdomain
(domain=None)-
更改或查询当前的全局域。如果domain是
None
,则返回当前全局域,否则全局域设置为domain,返回
gettext.
gettext
//(message)-
根据当前的globaldomain,language和locale目录返回message的本地化翻译。此函数通常在本地命名空间中别名为
_()
(参见下面的示例).
gettext.
dgettext
(domain, message)-
喜欢
gettext()
,但是在指定的domain.
gettext.
ngettext
(singular, plural, n)-
看看信息像
gettext()
,但考虑复数形式。如果找到翻译,请将复数公式应用于n,并返回结果消息(somelanguages有两个以上的复数形式)。如果没有找到翻译,如果singular为1则返回n;返回plural否则Plural公式取自目录标题。它是一个C或Pythonexpression有一个自由变量n;表达式求值为目录中复数的索引。请参阅GNU gettext文档,了解在
.po
文件中使用的精确语法以及各种语言的公式.
gettext.
dngettext
(domain, singular, plural, n)-
喜欢
ngettext()
,但在指定的domain.
gettext.
lgettext
(message)
gettext.
ldgettext
(domain, message)
gettext.
lngettext
(singular, plural, n)
gettext.
ldngettext
(domain, singular, plural, n)-
相当于没有
l
字首(gettext()
,dgettext()
,ngettext()
和dngettext()
),但如果没有使用bind_textdomain_codeset()
.警告
在Python 3中应该避免使用这些函数,因为它们返回了编码的字节。使用返回Unicode字符串的替代方法要好得多,因为大多数Python应用程序都希望将人类可读的文本操作为字符串而不是字节。此外,如果翻译的字符串存在编码问题,则可能会出现意外的与Unicode相关的异常。可能是
l*()
函数将在以后的Pythonversions中被弃用,因为它们存在固有的问题和限制.
注意GNU gettext 也定义了dcgettext()
方法,但这被认为没用,所以它目前没有实现.
以下是此API的典型用法示例:
import gettextgettext.bindtextdomain("myapplication", "/path/to/my/language/directory")gettext.textdomain("myapplication")_ = gettext.gettext# ...print(_("This is a translatable string."))
基于类的API
的基于类的APIgettext
模块比GNU gettext API提供更多的灵活性和更大的便利性。它是本地化Python应用程序和模块的推荐途径。gettext
定义实现GNU .mo
formatfiles,并具有返回字符串的方法。这个“翻译”类的实例也可以自己安装在内置的命名空间中作为函数_()
.
gettext.
find
(domain, localedir=None, languages=None, all=False)-
该函数实现了标准的
.mo
文件搜索算法。它domain,与textdomain()
相同。可选localedir如bindtextdomain()
可选languages是一个字符串列表,其中每个字符串是一个语言代码.如果没有给出localedir,则使用默认的系统区域设置目录。[2]如果提供languages没有给出,然后搜索以下环境变量:
LANGUAGE
,LC_ALL
,LC_MESSAGES
和LANG
。返回非空值的第一个用于languages变量。环境变量应该包含一个冒号分隔的语言列表,它将在冒号上拆分以产生预期的语言代码字符串列表.find()
然后扩展和规范化语言,然后迭代它们,搜索现有文件由这些组件构成:localedir/language/LC_MESSAGES/domain.mo
第一个这样的文件名由
find()
返回。如果没有找到这样的文件,则返回None
。如果给出all,则返回所有文件名的列表,按照它们出现在语言列表或环境变量中的顺序.
gettext.
translation
(domain, localedir=None, languages=None, class_=None, fallback=False, codeset=None)-
根据
Translations
和domain, localedir返回一个languages实例,首先传递给find()
以获取相关的列表.mo
文件路径。缓存具有相同.mo
文件名的实例。实例化的实例是class_,否则GNUTranslations
。类的构造函数必须使用单个文件对象参数。如果提供,codeset将改变用于编码lgettext()
和lngettext()
methods.如果找到多个文件,则后面的文件将用作早期文件的后备。要允许设置后备,
copy.copy()
用于从缓存中克隆每个翻译对象;实际的实例数据仍然与缓存共享.如果找不到
.mo
文件,这个函数会提升OSError
如果fallback是假的(这是默认值),如果NullTranslations
为真,则返回fallback实例.在版本3.3中更改:
IOError
曾经被提升代替OSError
.
gettext.
install
(domain, localedir=None, codeset=None, names=None)-
这个安装功能
_()
在Python的内置命名空间中,基于domain, localedir和codeset传递给函数translation()
.对于names参数,请参阅翻译对象的描述
install()
方法。如下所示,您通常会在应用程序中标记用于转换的字符串,通过将它们包装在对
_()
函数的调用中,如下所示:print(_("This string will be translated."))
为方便起见,您需要
_()
函数安装在Python’sbuiltins命名空间中,因此可以在你的应用程序的所有模块中轻松访问.
NullTranslations
class
翻译类实际上是将原始资源文件消息字符串转换为已翻译的消息字符串。所有翻译类使用的基类是NullTranslations
;这提供了可用于编写自己的专用翻译类的基本接口。这里的方法是NullTranslations
:
- class
gettext.
NullTranslations
(fp=None) -
带一个可选的文件对象 fp,被基类忽略。初始化“受保护”实例变量_info和_charset由派生类设置,以及_fallback,通过
add_fallback()
。然后它叫self._parse(fp)
如果fp不是None
._parse
(fp)-
在基类中没有操作,这个方法需要文件对象fp,并从文件中读取数据,初始化其消息目录。如果你有一个不支持的消息目录文件格式,你应该覆盖这个方法来解析你的格式.
add_fallback
(fallback )-
添加fallback作为当前翻译对象的后备对象。如果翻译对象无法为给定的消息提供翻译,则应查阅后备.
lgettext
(message )
lngettext
(singular, plural, n )-
等效于
gettext()
和ngettext()
,但是翻译作为在首选系统编码中编码的字节字符串返回如果在派生类中没有使用set_output_charset()
.Overridden显式设置编码.Warning
在Python 3中应避免使用这些方法。请参阅
lgettext()
功能。
info
()-
返回“受保护”
_info
变量。
charset
()-
返回消息目录文件的编码.
output_charset
()-
返回用于在
lgettext()
和lngettext()
.
set_output_charset
(charset)-
更改用于返回已翻译邮件的编码.
install
(names=None)-
这个方法安装
gettext()
进入内置命名空间,将其绑定到_
.如果names给定参数,它必须是一个包含你想要安装在内置命名空间中的函数名称的序列,而不是
_()
。支持的名称是"gettext"
,"ngettext"
,"lgettext"
和"lngettext"
.请注意,这只是制作
_()
功能可用于您的应用程序。因为它影响整个应用程序全局,特别是内置命名空间,本地化模块永远不应该安装_()
。相反,他们应该使用这个代码来制作_()
可用于他们的模块:import gettextt = gettext.translation("mymodule", ...)_ = t.gettext
这只将
_()
放在模块的全局命名空间中,因此只影响该模块中的调用.
GNUTranslations
class
gettext
模块提供了一个来自NullTranslations
:GNUTranslations
的附加类。这个类重写了_parse()
,能够以big-endian和little-endian格式读取GNU gettext 格式.mo
文件.
GNUTranslations
解析翻译目录中的可选元数据。与GNU gettext 的约定包括元数据作为空字符串的翻译。这个元数据在 RFC 822 – style key: value
对,并且应该包含Project-Id-Version
键。如果找到了密钥Content-Type
,那么charset
属性用于初始化“受保护的”_charset
实例变量,如果找不到则默认为None
。如果指定了charset编码,则使用此编码将从目录中读取的所有messageid和消息字符串转换为Unicode,否则假定为ASCII编码.
由于消息ID也被读作Unicode字符串,所有*gettext()
方法都会将消息ID假设为Unicode字符串,而不是字节字符串.
将整组键/值对放入字典并设置为“受保护”_info
实例变量
如果.mo
文件的幻数无效,主要版本号是否符合预期,或者在读取文件时出现其他问题,实例化GNUTranslations
类可以引发OSError
.
- class
gettext.
GNUTranslations
-
从基类实现中重写以下方法:
gettext
(message)-
查找message目录中的id并返回相应的messagestring,作为Unicode字符串。如果目录中没有messageid,并设置了后备,查找转发到thefallback的
gettext()
方法。否则,message id返回.
ngettext
(singular, plural, n )-
对消息ID进行复数形式查找。singular在目录中用作查找目的的消息id,而n用于确定要使用的是哪种形式。返回的消息字符串是Unicode字符串.
如果在目录中找不到消息ID,并且指定了回退,则请求将转发到回退的
ngettext()
方法。否则,当n为1 singular时,返回plural在所有其他情况下都会回复.这是一个例子:
n = len(os.listdir("."))cat = GNUTranslations(somefile)message = cat.ngettext( "There is %(num)d file in this directory", "There are %(num)d files in this directory", n) % {"num": n}
lgettext
(message)
国际化你的程序和模块
国际化(I18N)指的是操作通过该程序使多种语言成为可能。本地化(L10N)是指您的程序一旦国际化,就会适应当地语言和文化习惯。为了向您的Python程序提供多语言消息,您需要执行以下步骤:
- 准备您的程序或模块通过专门标记可翻译的字符串
- 在您标记的文件上运行一套工具来生成原始消息目录
- 创建消息目录的语言特定翻译
- 使用
gettext
模块以便正确翻译消息字符串
为了准备I18N的代码,你需要查看你文件中的所有字符串。任何需要翻译的字符串都应该用_("...")
中的包装标记 – 也就是调用函数_()
。例如:
filename = "mylog.txt"message = _("writing a log message")fp = open(filename, "w")fp.write(message)fp.close()
在这个例子中,字符串"writing a log message"
被标记为翻译候选者,而字符串"mylog.txt"
和"w"
不是.
有一些工具可以提取用于翻译的字符串。原始GNU gettext 仅支持C或C ++源代码,但其扩展版本为 xgettext 扫描用多种语言编写的代码,包括Python,以查找标记为可译的字符串。Babel是一个Pythoninternationalization库,包含pybabel
脚本提取和编译消息目录。FrançoisPinard的节目叫 xpot 做类似的工作,并作为po-utils包的一部分提供.
(Python还包括这些程序的纯Python版本,称为 pygettext.py和msgfmt.py;一些Python发行版会为你安装它们。pygettext.py类似于 xgettext ,但只能理解Python源代码,不能处理其他编程语言,如C或C ++。 pygettext.py支持类似于 xgettext的命令行界面;有关其使用的详细信息,运行pygettext.py--help
. msgfmt.py与GNU msgfmt 二进制兼容。有了这两个程序,你可能不需要GNU gettext 包来国际化你的Pythonapplications。)
xgettext , pygettext ,和类似的工具生成.po
作为消息目录的文件。它们是结构化的可读文件,包含源代码中的每个标记字符串,以及forsestrings的翻译版本的占位符.
这些副本.po
然后将文件移交给为自己支持的自然语言编写翻译的个人翻译。他们将已完成的语言版本发送回<language-name>.po
使用.mo
msgfmt 程序将文件编译成机器可读的二进制目录文件。.mo
使用gettext
用于实际翻译处理的模块atrun-time.
你如何使用gettext
代码中的模块取决于您是将单个模块还是整个应用程序进行国际化。接下来的两个部分将讨论每个案例.
定位你的模块
如果要本地化模块,则必须注意不要进行全局更改,例如:到内置命名空间。你不应该使用GNU gettext
API,而是使用基于类的API .
假设您的模块被称为“垃圾邮件”,模块的各种自然语言翻译.mo
文件位于/usr/share/locale
中的GNU gettext 格式。以下是您在模块顶部的内容:
import gettextt = gettext.translation("spam", "/usr/share/locale")_ = t.gettext
本地化您的应用程序
如果您正在本地化您的应用程序,您可以将_()
函数全局安装到内置命名空间中,通常在你的应用程序的主驱动文件中。这将使所有特定于应用程序的文件只使用_("...")
而无需在每个文件中明确安装它.
在简单的情况下,您只需要将以下代码添加到应用程序的maindriver文件:
import gettextgettext.install("myapplication")
如果需要设置locale目录,可以将其传递到install()
函数:
import gettextgettext.install("myapplication", "/usr/share/locale")
动态更改语言
如果您的程序需要同时支持多种语言,您可能需要创建多个翻译实例,然后在主题之间切换,如下所示:
import gettextlang1 = gettext.translation("myapplication", languages=["en"])lang2 = gettext.translation("myapplication", languages=["fr"])lang3 = gettext.translation("myapplication", languages=["de"])# start by using language1lang1.install()# ... time goes by, user selects language 2lang2.install()# ... more time goes by, user selects language 3lang3.install()
延迟翻译
在大多数编码情况下,字符串在它们被编码的位置被翻译。但是,有时候,您需要标记字符串以进行翻译,但是将实际翻译推迟到以后。一个典型的例子是:
animals = ["mollusk", "albatross", "rat", "penguin", "python", ]# ...for a in animals: print(a)
在这里,你想要将animals
列表中的字符串标记为可翻译,但实际上你并不想翻译它们直到它们被打印出来.
这是你可以处理这种情况的一种方法:
def _(message): return messageanimals = [_("mollusk"), _("albatross"), _("rat"), _("penguin"), _("python"), ]del _# ...for a in animals: print(_(a))
这是有效的,因为_()
的虚拟定义只返回stringunchanged。这个虚拟定义将暂时覆盖内置命名空间中的_()
的任何定义(直到del
命令)。Takecare,虽然如果你在localnamespace中有_()
的先前定义.
注意第二次使用_()
不会将“a”标识为可以转移给 gettext program,因为参数不是字符串文字.
处理此问题的另一种方法是使用以下示例:
def N_(message): return messageanimals = [N_("mollusk"), N_("albatross"), N_("rat"), N_("penguin"), N_("python"), ]# ...for a in animals: print(_(a))
在这种情况下,您使用函数N_()
标记可翻译字符串,这不会与_()
的任何定义冲突。但是,您需要教授您的消息提取程序,以便翻译字符串。标有N_()
. xgettext , pygettext , pybabel extract
和 xpot 通过使用-k
来支持命令行开关。这里N_()
的选择是完全随意的;它可能很容易被MarkThisStringForTranslation()
.
致谢
以下人员为本模块的创建贡献了代码,反馈,设计建议,以前的实现和宝贵的经验:
- Peter Funk
- James Henstridge
- JuanDavidIbáñezPalomar
- Marc-AndréLemburg
- MartinvonLüwis
- FrançoisPinard
- Barry Warsaw
- Gustavo Niemeyer
脚注
[1] | 默认的语言环境目录是系统相关的;例如,在RedHat Linuxit上是/usr/share/locale ,但在Solaris上它是/usr/lib/locale 。gettext 模块不会尝试支持这些系统相关的默认设置;相反它的默认值是sys.prefix/share/locale 。因此,最好拨打bindtextdomain() 在应用程序的开头有一个明确的绝对路径. |
[2] | 请参阅bindtextdomain() 以上。 |
评论被关闭。