如何在您的应用程序或库中使用 oslo.i18n

安装

在命令行

$ pip install oslo.i18n

创建集成模块

要在项目中使用 oslo.i18n(例如 myapp),您需要创建一个小的集成模块来保存 TranslatorFactory 的实例以及工厂创建的标记函数引用。

注意

库可能不希望将新的集成模块作为其公共 API 的一部分公开,因此,与其将其命名为 myapp.i18n,不如将其命名为 myapp._i18n,以表明它是一个私有实现细节,不应在库自身代码之外使用。

注意

从 Pike 系列开始,OpenStack 不再支持日志翻译。无需在新代码中添加翻译说明,并且可以从旧代码中删除这些说明。有关更多详细信息,请参阅邮件列表上的邮件线程 理解日志域更改 openstack-dev。

# myapp/_i18n.py

import oslo_i18n

DOMAIN = "myapp"

_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN)

# The primary translation function using the well-known name "_"
_ = _translators.primary

# The contextual translation function using the name "_C"
# requires oslo.i18n >=2.1.0
_C = _translators.contextual_form

# The plural translation function using the name "_P"
# requires oslo.i18n >=2.1.0
_P = _translators.plural_form

def get_available_languages():
    return oslo_i18n.get_available_languages(DOMAIN)

然后,在您的代码的其余部分,为每个消息使用适当的标记函数

from myapp._i18n import _

# ...

variable = "openstack"
some_object.name_msg = _('my name is: %s') % variable

# ...

try:

    # ...

except AnException1:

    # Log only, log messages are no longer translated
    LOG.exception('exception message')

except AnException2:

    # Raise only
    raise RuntimeError(_('exception message'))

else:

    # Log and Raise
    msg = _('Unexpected error message')
    LOG.exception(msg)
    raise RuntimeError(msg)

注意

在 _i18n 中导入多个模块的单行代码是 OpenStack 风格指南 中导入语句的一个有效例外。

使用标记函数(例如 _)非常重要,而不是名称的较长形式,因为扫描源代码以查找可翻译字符串的工具会查找标记函数名称。

警告

在内置命名空间中安装 _() 的旧方法已被弃用。修改全局命名空间会影响库以及应用程序,因此可能会干扰正确的消息目录查找。对 gettextutils.install() 的调用应替换为此处描述的应用程序或库集成模块。

处理对导入的 Hacking 反对

OpenStack 风格指南 倾向于导入模块并在导入后从这些模块访问名称,而不是直接导入名称。例如

# WRONG
from foo import bar

bar()

# RIGHT

import foo

foo.bar()

linting 工具 hacking 通常会抱怨从模块内导入名称。可以接受绕过对翻译标记函数的检查,因为它们必须具有特定的名称,并且其使用模式由消息目录提取工具而不是我们的风格指南决定。要绕过此集成模块导入的 hacking 检查,请在 tox.ini 中添加导入异常。

例如

# tox.ini
[hacking]
import_exceptions = myapp._i18n

延迟翻译

延迟翻译会尽可能延迟将消息字符串转换为翻译形式,包括如果消息未记录或以其他方式传递给用户,则可能永远不会转换。它还支持通过配置单独的日志处理程序来记录多种语言的翻译消息。

延迟翻译是通过从翻译函数返回一个特殊对象来实现的,而不是 Unicode 字符串。该特殊消息对象支持某些,但不是全部,字符串操作 API。例如,不支持使用加法进行连接,但支持变量插值。根据翻译字符串在应用程序中的使用方式,这些限制可能意味着无法使用延迟翻译,因此默认情况下未启用它。

要启用延迟翻译,请调用 enable_lazy()

import oslo_i18n

oslo_i18n.enable_lazy()

翻译消息

使用 translate() 将字符串翻译为特定语言环境。 translate() 处理延迟翻译和已经立即翻译的字符串。它应在已知要使用的语言环境的点使用,通常是在将消息返回或发出日志消息之前。

import oslo_i18n

trans_msg = oslo_i18n.translate(msg, my_locale)

如果未指定语言环境,则使用默认语言环境。

可用语言

只有提供翻译的语言才可用于翻译。要确定可用的语言,提供了 get_available_languages()

import myapp._i18n

languages = myapp._i18n.get_available_languages()

显示翻译的消息

需要进行一些准备才能在正在运行的应用程序中显示翻译的消息。

首选语言

您需要通过环境变量指定首选语言。可以通过 LANGUAGELC_ALLLC_MESSAGESLANGUAGE(前者具有优先级)指定首选语言。

oslo_i18n.translate() 可用于翻译字符串以覆盖首选语言。

注意

您需要使用 enable_lazy() 通过使用 oslo_i18n.translate() 覆盖首选语言。

语言环境目录

Python gettext 使用路径 <localedir>/<language>/LC_MESSAGES/<domain>.mo 查找给定域的二进制 mo 文件。默认语言环境目录因发行版而异,并且在大多数情况下为 /usr/share/locale

如果将消息目录存储在不同的位置,您需要通过名为 <DOMAIN>_LOCALEDIR 的环境变量指定位置,其中 <DOMAIN> 是一个大写域名称,用 - 替换 _.。例如,对于域 neutron 使用 NEUTRON_LOCALEDIR,对于域 oslo_i18n 使用 OSLO_I18N_LOCALEDIR

注意

当您通过 <DOMAIN>_LOCALEDIR 环境变量指定语言环境目录时,需要为每个域指定一个环境变量。更具体地说,如果您的应用程序使用域 myapp` 使用 oslo.policy, 需要 指定 ``MYAPP_LOCALEDIROSLO_POLICY_LOCALEDIR,以确保显示来自您的应用程序和 oslo.policy 的翻译消息。