gettext
gettext — Multilingual internationalization services
源代码:
Lib / gettext.py
该gettext
模块为您的Python模块和应用程序提供国际化(I18N)和本地化(L10N)服务。它支持GNU gettext
消息目录API和更适合Python文件的更高级别的基于类的API。下面介绍的接口允许您使用一种自然语言编写模块和应用程序消息,并提供用不同自然语言运行的翻译消息目录。
还给出了一些关于本地化Python模块和应用程序的提示。
1. GNU gettext API
该gettext
模块定义了以下API,它与GNU gettext
API 非常相似。如果您使用此API,则会影响整个应用程序的全局翻译。如果您的应用程序是单语言的,通常这就是您想要的,并且语言的选择取决于用户的区域设置。如果您正在本地化Python模块,或者您的应用程序需要即时切换语言,则可能需要使用基于类的API。
gettext.bindtextdomain(domain[, localedir])
将域
绑定到locale目录localedir
。更具体地说,gettext
将寻找二进制.mo
使用路径(在UNIX上)定域
文件:localedir/language/LC_MESSAGES/domain.mo
,在语言
中搜索在环境变量LANGUAGE
,LC_ALL
,LC_MESSAGES
,和LANG
分别。
如果localedir
被省略None
,则返回当前的域
绑定。[1]
gettext.bind_textdomain_codeset(domain[, codeset])
将域
绑定到代码集
,更改gettext()
函数族返回的字符串的编码。如果代码集
被省略,则返回当前绑定。
2.4版本中的新功能。
gettext.textdomain([domain])
更改或查询当前全局域
。如果域
为None
,则返回当前全局域
,否则全局域
设置为返回的域
。
gettext.gettext(message)
根据当前全局域,语言和区域设置目录返回消息
的本地化转换。该函数通常_()
与本地名称空间中的别名一样(请参见下面的示例)。
gettext.lgettext(message)
等同于gettext()
,但如果没有使用其他明确的编码进行明确设置,则翻译将返回到首选系统编码中bind_textdomain_codeset()
。
2.4版本中的新功能。
gettext.dgettext(domain, message)
喜欢gettext()
,但在指定的域中
查看消息。
gettext.ldgettext(domain, message)
等同于dgettext()
,但如果没有使用其他明确的编码进行明确设置,则翻译将返回到首选系统编码中bind_textdomain_codeset()
。
2.4版本中的新功能。
gettext.ngettext(singular, plural, n)
喜欢gettext()
,但考虑复数
形式。如果找到翻译,则将复数
公式应用于n
,并返回结果信息(某些语言具有两个以上的复数
形式)。如果没有找到翻译,如果n
是1 ,则返回单数
; 否则返回复数
。
复制公式从目录标题中获取。它是一个C或Python
表达式,它有一个自由变量n
; 表达式评估为目录中复数的索引。有关在文件中使用的精确语法.po
以及各种语言的公式,请参阅GNU gettext文档。
2.3版本的新功能。
gettext.lngettext(singular, plural, n)
等同于ngettext()
,但如果没有使用其他明确的编码进行明确设置,则翻译将返回到首选系统编码中bind_textdomain_codeset()
。
2.4版本中的新功能。
gettext.dngettext(domain, singular, plural, n)
就像ngettext()
,但在指定的域中
查看消息。
2.3版本的新功能。
gettext.ldngettext(domain, singular, plural, n)
等同于dngettext()
,但如果没有使用其他明确的编码进行明确设置,则翻译将返回到首选系统编码中bind_textdomain_codeset()
。
2.4版本中的新功能。
请注意,GNU gettext
也定义了一种dcgettext()
方法,但这被认为没有用,所以它目前未实现。
以下是此API的典型用法示例:
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')
2.基于类的API
该gettext
模块的基于类的API 为您提供比GNU gettext
API 更多的灵活性和更大的便利。这是本地化您的Python应用程序和模块的推荐方式。gettext
定义了一个“翻译”类,它实现了对GNU .mo
格式文件的解析,并且具有返回标准8位字符串或Unicode字符串的方法。这个“翻译”类的实例也可以把它们自己安装在内置的名字空间中作为函数_()
。
gettext.find(domain[, localedir[, languages[, all]]])
该功能实现标准.mo
文件搜索算法。它需要一个域
,与需要的相同textdomain()
。可选localedir
与bindtextdomain()
可选语言一样
是一个字符串列表,其中每个字符串都是一个语言代码。
如果未指定localedir
,则使用默认的系统区域设置目录。[2]如果语言
没有给出,那么下面的环境变量中搜索:LANGUAGE
,LC_ALL
,LC_MESSAGES
,和LANG
。返回非空值的第一个用于语言
变量。环境变量应该包含一个以冒号分隔的语言
列表,这些语言
将在冒号上分开以产生预期的语言
代码字符串列表。
find()
然后扩展和规范化语言,然后遍历它们,搜索由这些组件构建的现有文件:
localedir/language/LC_MESSAGES/domain.mo
存在的第一个这样的文件名由返回find()
。如果没有找到这样的文件,则None
返回。如果全部
给出,它将按照它们出现在语言列表或环境变量中的顺序返回所有文件名的列表。
gettext.translation(domain[, localedir[, languages[, class_[, fallback[, codeset]]]]])
返回Translations
基于域
,localedir
和语言
的实例,这些实例首先传递find()
给获取关联.mo
文件路径的列表。.mo
缓存具有相同文件名的实例。实例化的实际类可以是_class_(如果提供),否则GNUTranslations。该类的构造函数必须采用单个文件对象参数。如果提供,_codeset
将更改用于对翻译的字符串进行编码的字符集。
如果找到多个文件,则以后的文件将用作早期文件的后备文件。允许设置回退,copy.copy()
用于从缓存中克隆每个翻译对象; 实际的实例数据仍然与缓存共享。
如果没有.mo
找到文件,这个功能引起了IOError
,如果回退
是假的(这是默认值),并返回NullTranslations
如果实例的回退
是真实的。
在版本2.4中更改:添加了代码集
参数。
gettext.install(domain[, localedir[, unicode[, codeset[, names]]]])
这将_()
根据传递给该函数的域
,localedir
和代码集
在Python的builtins名称空间中安装该函数translation()
。该统一
标志传递给所产生的翻译对象的install()
方法。
有关names
参数,请参阅翻译对象install()
方法的描述。
如下所示,通常在应用程序中标记可作为翻译候选对象的字符串,方法是将它们包装在_()
函数调用中,如下所示:
print _('This string will be translated.')
为了方便起见,您希望将_()
函数安装在Python的builtins名称空间中,以便在应用程序的所有模块中轻松访问它。
在版本2.4中更改:添加了代码集
参数。
在版本2.5中进行了更改:添加了names
参数。
2.1。该NullTranslations类
翻译类实际上是将原始源文件消息字符串转换为翻译的消息字符串。所有翻译类使用的基类是NullTranslations
; 这提供了您可以用来编写自己的专业翻译课程的基本界面。以下是这些方法NullTranslations
:
class gettext.NullTranslations([fp])
获取可选的文件对象fp
,该对象被基类忽略。初始化派生类设置的“protected”实例变量_info
和_charset
,以及通过设置的_fallback
add_fallback()
。然后,它调用self._parse(fp)
如果FP
不是None
。
_parse(fp)
在基类中没有操作,该方法使用文件对象fp
,并从文件读取数据,初始化其消息目录。如果您的消息目录文件格式不受支持,则应该重写此方法来解析您的格式。
add_fallback(fallback)
将后备
作为当前翻译对象的后备
对象添加。如果翻译对象无法为给定的消息提供翻译,则应该查阅翻译对象。
gettext(message)
如果已设置回退,则转发gettext()
至回退。否则,返回翻译的消息。在派生类中重写。
lgettext(message)
如果已设置回退,则转发lgettext()
至回退。否则,返回翻译的消息。在派生类中重写。
2.4版本中的新功能。
ugettext(message)
如果已设置回退,则转发ugettext()
至回退。否则,将翻译的消息作为Unicode字符串返回。在派生类中重写。
ngettext(singular, plural, n)
如果已设置回退,则转发ngettext()
至回退。否则,返回翻译的消息。在派生类中重写。
2.3版本的新功能。
lngettext(singular, plural, n)
如果已设置回退,则转发lngettext()
至回退。否则,返回翻译的消息。在派生类中重写。
2.4版本中的新功能。
ungettext(singular, plural, n)
如果已设置回退,则转发ungettext()
至回退。否则,将翻译的消息作为Unicode字符串返回。在派生类中重写。
2.3版本的新功能。
info()
返回“受保护的” _info
变量。
charset()
返回“受保护的” _charset
变量。
output_charset()
返回“protected” _output_charset
变量,该变量定义用于返回已翻译消息的编码。
2.4版本中的新功能。
set_output_charset(charset)
更改“受保护” _output_charset
变量,该变量定义用于返回已翻译消息的编码。
2.4版本中的新功能。
install([unicode[, names]])
如果unicode
标志为false,则此方法将安装self.gettext()
到内置命名空间中,并将其绑定到_
。如果unicode
是真的,它会绑定self.ugettext()
。默认情况下,unicode
为false。
如果给出了names
参数,那么它必须是一个包含您想要在内建命名空间中安装的函数名称的序列_()
。受支持的名称'gettext'
(绑定到self.gettext()
或self.ugettext()
根据unicode
标志),'ngettext'
(绑定到self.ngettext()
或self.ungettext()
根据unicode
标志)'lgettext'
和'lngettext'
。
请注意,这只是一种方法,尽管这是最方便的方式,可以使_()
您的应用程序可以使用该功能。因为它影响整个应用程序全局,特别是内置命名空间,本地化模块不应该安装_()
。相反,他们应该使用此代码使其_()
模块可用:
import gettext
t = gettext.translation('mymodule', ...)
_ = t.gettext
这_()
只会放在模块的全局名称空间中,因此只会影响此模块中的调用。
在版本2.5中进行了更改:添加了names
参数。
2.2。该GNUTranslations类
该gettext
模块提供了一个来自以下的附加类NullTranslations
:GNUTranslations
。这个类覆盖了_parse()
以big-endian和little-endian格式读取GNU gettext
格式.mo
文件。它还将消息ID和消息字符串强制为Unicode。
GNUTranslations
将可选的元数据从翻译目录中解析出来。GNU gettext
约定包含元数据作为空字符串的翻译。这个元数据是RFC 822
风格key: value
对,并且应该包含Project-Id-Version
密钥。如果Content-Type
找到密钥,则该charset
属性用于初始化“受保护的” _charset
实例变量,None
如果未找到则默认为该实例变量。如果指定了字符集编码,则使用此编码将从目录中读取的所有消息ID和消息字符串转换为Unicode。该ugettext()
方法总是返回一个Unicode,而gettext()
返回一个编码的8位字符串。对于这两种方法的消息ID参数,可以接受Unicode字符串或仅包含US-ASCII字符的8位字符串。请注意,Unicode版本的方法(即ugettext()
和ungettext()
)是用于国际化Python程序的推荐接口。
整组键/值对被放置在字典中并被设置为“受保护的” _info
实例变量。
如果.mo
文件的幻数无效,或者在读取文件时发生其他问题,则GNUTranslations
可以引发实例化类IOError
。
基类实现覆盖了以下方法:
GNUTranslations.gettext(message)
查找目录中的消息
ID并返回相应的消息
字符串,如果已知,则使用目录的字符集编码编码的8位字符串。如果消息
标识的目录中没有条目,并且已设置回退,则查找会转发到回退的gettext()
方法。否则,返回消息
ID。
GNUTranslations.lgettext(message)
等同于gettext()
,但如果没有使用其他明确的编码进行明确设置,则翻译将返回到首选系统编码中set_output_charset()
。
2.4版本中的新功能。
GNUTranslations.ugettext(message)
在目录中查找消息
ID并返回相应的消息
字符串,作为Unicode字符串。如果消息
标识的目录中没有条目,并且已设置回退,则查找会转发到回退的ugettext()
方法。否则,返回消息
ID。
GNUTranslations.ngettext(singular, plural, n)
做一个消息ID的复数形式查找。单数
用作目录中查找消息的消息ID,而n
用于确定使用哪种复数形式。返回的消息字符串是用目录的字符集编码(如果已知)编码的8位字符串。
如果在目录中找不到消息标识,并且指定了回退,则将请求转发到回退的ngettext()
方法。否则,当n
是1时,返回单数
,并且在所有其他情况下返回复数
。
2.3版本的新功能。
GNUTranslations.lngettext(singular, plural, n)
等同于gettext()
,但如果没有使用其他明确的编码进行明确设置,则翻译将返回到首选系统编码中set_output_charset()
。
2.4版本中的新功能。
GNUTranslations.ungettext(singular, plural, n)
做一个消息ID的复数形式查找。单数
用作目录中查找消息的消息ID,而n
用于确定使用哪种复数形式。返回的消息字符串是一个Un
icode字符串。
如果在目录中找不到消息标识,并且指定了回退,则将请求转发到回退的ungettext()
方法。否则,当n
是1时,返回单数
,并且在所有其他情况下返回复数
。
这里是一个例子:
n = len(os.listdir('.'))
cat = GNUTranslations(somefile)
message = cat.ungettext(
'There is %(num)d file in this directory',
'There are %(num)d files in this directory',
n) % {'num': n}
2.3版本的新功能。
2.3。Solaris消息目录支持
Solaris操作系统定义了它自己的二进制.mo
文件格式,但由于此格式没有文档可用,目前尚不支持。
2.4。Catalog构造函数
GNOME使用gettext
James Henstridge 的模块版本,但是这个版本有一个稍微不同的API。其记录的使用情况是:
import gettext
cat = gettext.Catalog(domain, localedir)
_ = cat.gettext
print _('hello world')
为了与这个旧模块兼容,该函数Catalog()
是上述函数的别名translation()
。
这个模块和Henstridge之间的一个区别是:他的目录对象支持通过映射API进行访问,但这似乎是未使用的,所以目前不支持。
3.国际化您的程序和模块
国际化(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'
而不是。
Python发行版带有两个工具,可帮助您在准备好源代码后生成消息目录。这些可能或不可以从二进制发行版中获得,但它们可以在Tools/i18n
目录中的源代码发行版中找到。
该pygettext
[3]程序扫描所有的Python源代码找你之前标记为可翻译的字符串。它类似于GNU gettext
程序,只是它理解Python源代码的所有复杂性,但对C或C ++源代码一无所知。gettext
除非你也要翻译C代码(比如C扩展模块),否则你不需要GNU 。
pygettext
生成文本Uniforum风格的人类可读消息目录.pot
文件,本质上是结构化的可读文件,其中包含源代码中的每个标记字符串以及转换字符串的占位符。pygettext
是一个命令行脚本,它支持与xgettext
类似的命令行界面; 有关其使用的详细信息,请运行:
pygettext.py --help
.pot
然后将这些文件副本交给为每种支持的自然语言编写语言特定版本的个人翻译人员。他们会将填入的语言特定版本作为.po
文件发回给您。使用msgfmt.py
[4]程序(在Tools/i18n
目录中),.po
从转换程序获取文件并生成机器可读的.mo
二进制目录文件。这些.mo
文件是gettext
模块在运行时用于实际翻译处理的内容。
gettext
在代码中如何使用模块取决于您是将单个模块还是整个应用程序国际化。接下来的两节将讨论每个案例。
3.1。本地化您的模块
如果您正在本地化您的模块,则必须注意不要进行全局更改,例如对内置名称空间进行更改。你不应该使用GNU gettext
API,而应该使用基于类的API。
假设您的模块被称为“垃圾邮件”,并且模块的各种自然语言翻译.mo
文件驻留/usr/share/locale
在GNU gettext
格式中。以下是您将放在模块顶部的内容:
import gettext
t = gettext.translation('spam', '/usr/share/locale')
_ = t.lgettext
如果您的翻译人员在他们的.po
文件中提供了Unicode字符串,那么您应该这样做:
import gettext
t = gettext.translation('spam', '/usr/share/locale')
_ = t.ugettext
3.2。本地化您的应用程序
如果您正在本地化应用程序,则可以将该_()
函数全局安装到内置命名空间中,通常位于应用程序的主驱动程序文件中。这将让所有应用程序特定的文件都可以使用,_('...')
而无需将其明确安装到每个文件中。
在简单情况下,您只需将以下代码添加到应用程序的主驱动程序文件中:
import gettext
gettext.install('myapplication')
如果您需要设置语言环境目录或unicode
标志,可以将它们传递给install()
函数:
import gettext
gettext.install('myapplication', '/usr/share/locale', unicode=1)
3.3。即时更改语言
如果您的程序需要同时支持多种语言,则可能需要创建多个翻译实例,然后明确切换它们,如下所示:
import gettext
lang1 = gettext.translation('myapplication', languages=['en'])
lang2 = gettext.translation('myapplication', languages=['fr'])
lang3 = gettext.translation('myapplication', languages=['de'])
# start by using language1
lang1.install()
# ... time goes by, user selects language 2
lang2.install()
# ... more time goes by, user selects language 3
lang3.install()
3.4。推迟翻译
在大多数编码情况下,字符串在被编码的地方被翻译。然而,有时候,您需要标记字符串进行翻译,但推迟实际翻译。一个典型的例子是:
animals = ['mollusk',
'albatross',
'rat',
'penguin',
'python', ]
# ...
for a in animals:
print a
在这里,您想要将animals
列表中的字符串标记为可翻译的,但您实际上并不想在打印之前翻译它们。
以下是您可以处理这种情况的一种方法:
def _(message): return message
animals = [_('mollusk'),
_('albatross'),
_('rat'),
_('penguin'),
_('python'), ]
del _
# ...
for a in animals:
print _(a)
这是可行的,因为虚拟定义_()
只是简单地返回字符串。这个伪定义将暂时覆盖_()
内置命名空间的任何定义(直到del
命令)。小心,但如果你有一个_()
在本地命名空间的先前定义。
请注意,第二次使用_()
不会将“a”标识为可转换为pygettext
程序,因为它不是字符串。
下面的例子是处理这个问题的另一种方法:
def N_(message): return message
animals = [N_('mollusk'),
N_('albatross'),
N_('rat'),
N_('penguin'),
N_('python'), ]
# ...
for a in animals:
print _(a)
在这种情况下,您使用函数N_()
[5] 标记可翻译的字符串,该函数不会与任何定义冲突_()
。但是,您需要教您的消息提取程序以查找标有的可翻译字符串N_()
。pygettext
和xpot
都通过使用命令行开关来支持这一点。
3.5. gettext() vs. lgettext()
在Python 2.4 lgettext()
中引入了函数族。这些函数的意图是提供一种更符合当前GNU gettext实现的替代方案。与gettext()
返回的字符串不同,该字符串使用在翻译文件中使用的相同代码集进行lgettext()
编码,将返回使用首选系统编码进行编码的字符串,如返回的locale.getpreferredencoding()
。另外请注意,Python 2.4引入了新的函数来显式选择翻译后的字符串中使用的代码集。如果明确设置了代码集,甚至lgettext()
会在请求的代码集中返回翻译后的字符串,正如GNU gettext实现中预期的那样。
4.致谢
以下人员为此模块的创建提供了代码,反馈,设计建议,以前的实施和宝贵的经验:
- Peter Funk
- James Henstridge
- Juan David Ibáñez Palomar
- Marc-André Lemburg
- Martin von Löwis
- François Pinard
- Barry Warsaw
- Gustavo Niemeyer
注
1 | 缺省的语言环境目录是依赖于系统的; 例如,在RedHat Linux上它是/ usr / share / locale,但在Solaris上它是/ usr / lib / locale。gettext模块不会尝试支持这些系统相关的默认值; 相反,它的默认值是sys.prefix / share / locale。出于这个原因,最好在应用程序的开始时用显式绝对路径调用bindtextdomain()。 |
---|---|
2 | 请参阅上面的bindtextdomain()的脚注。 |
3 | FrançoisPinard写了一个名为xpot的程序,它做了类似的工作。它可以作为他的po-utils软件包的一部分。 |
4 | msgfmt.py与GNU msgfmt二进制兼容,只是它提供了一个更简单的全Python实现。有了这个和pygettext.py,你通常不需要安装GNU gettext包来国际化你的Python应用程序。 |
5 | 这里N_()的选择完全是任意的; 它可以像MarkThisStringForTranslation()一样简单。 |