使用 gettext 和 jinja2 以及金字塔翻译 %%

问题描述 投票:0回答:1

使用 Jinja2 和 Pyramid 与 Python 进行 i18n 工作。似乎不知道如何翻译%%。 我开始怀疑这个 bug 是在 Jinja2 中。


所以我做了更多的调查,看起来问题更多的是 gettext 而不是 jinja2,如 repl 所示

>>>gettext.gettext("98%% off %s sale") % ('holiday')
'98% off holiday sale'
>>>gettext.gettext("98%% off sale")
'98%% off sale'

>>>gettext.gettext("98% off %s sale") % ('holiday')
Traceback (most recent call last):
  Python Shell, prompt 13, line 1
TypeError: %o format: a number is required, not str

这似乎是一个先有鸡还是先有蛋的问题。

  • 如果 gettext 翻译 %% -> %,则格式化程序会在参数替换期间对其进行爆炸。
  • 如果 gettext 不翻译 %% -> %,那么当未调用格式化程序(没有要插入的参数)时,%% 会泄漏。

所有这些意味着翻译人员(其中大多数不是计算机程序员)必须非常小心地进行翻译,每个人都需要非常小心包含 % 的翻译。

似乎我们(不知何故)做错了,应该有一个更简单和统一的格式来做到这一点。现在我们通过简单地注入 % 作为格式参数来应对。

有没有更好的方法来做到这一点,或者这已经是最好的了吗?


底部有一个.po文件

单元测试几乎说明了一切,为什么最后一个断言失败了?这是 Jinja2 的错误吗,还是我需要以不同的方式处理这个问题。

class Jinja2Tests(TestCase):

    def test_percent_percent(self):
        """ i18n(gettext) expresses  98% as 98%% only in some versions of jinja2 that has not
            worked as expected.  This is to make sure that it is working. """
        env = Environment(extensions=['jinja2.ext.i18n'])
        lang = gettext.translation('messages', path.abspath(path.join(path.dirname(__file__), 'data')))
        env.install_gettext_translations(lang)

        template = env.from_string(source="{{ _('98%% off %(name)s sale') | format(name='holiday') }}")
        result = template.render()
        self.assertEqual('98% off holiday sale(translated)', result)

        template = env.from_string(source="{{ _('98%% off sale') }}")
        result = template.render()

        # THE LINE BELOW FAILS WITH:
        # AssertionError: '98% off sale(translated)' != u'98%% off sale(translated)'
        self.assertEqual('98% off sale(translated)', result)

您必须将 MO 文件编译为 PO 文件才能运行上述代码。

# This file is distributed under the same license as the Uniregistrar project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: Uniregistrar 1.0\n"
"Report-Msgid-Bugs-To: [email protected]\n"
"POT-Creation-Date: 2016-12-22 15:22-0500\n"
"PO-Revision-Date: 2016-11-14 16:42-0500\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n"
"Language-Team: en <[email protected]>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.3\n"

#: uniregistrar/constants.py:90
msgid "98%% off sale"
msgstr "98%% off sale(translated)"

#: uniregistrar/constants.py:90
msgid "98%% off %(name)s sale"
msgstr "98%% off %(name)s sale(translated)"
python-2.7 internationalization jinja2 pyramid gettext
1个回答
0
投票

据我了解这个问题,这是您主要关心的问题:

所有这些意味着翻译人员(其中大多数不是计算机程序员)必须非常小心地进行翻译,每个人都需要非常小心包含 % 的翻译。

tl;dr:这就是为什么

msgfmt
有一个选项
--check
。该选项使
msgfmt
检查翻译是否可以安全地通过目标语言的字符串插值工具运行。所有这些问题的根源是 C 的
printf()
,当使用错误的参数调用时,它很容易崩溃:

printf("Bonjour, %s!");

printf()
函数是一个可变参数函数。
%s
导致它从堆栈中弹出另一个参数。在上面的示例中,除了字符串文字之外没有其他参数。这意味着插入到
%s
中的字符串可以被认为来自任意地址,例如 0。在大多数现代语言中,这将是一个空指针异常。在 C 中,它是一个空指针取消引用,经常被利用来运行任意代码,这很糟糕。

我们假设代码如下所示:

printf(gettext("Hello, world!"));

只要

gettext()
给出的翻译不包含任何“%”字符,那就是安全的。但如果法语翻译翻译“你好,世界!”与“你好,%s!”程序会崩溃。

嗯,如果软件的维护者使用标准的翻译工作流程,它就不会崩溃。在这种情况下,

xgettext
(在 Python 中可能类似于“pybabel extract”)会在
.po
文件中生成此条目:

#: filename.c:1
#, c-format
msgid "Hello, world!"
msgstr ""

将“#, c-format”行读为“这是一个 printf 格式字符串”!

比如说,法语翻译者将其翻译成这个条目:

#: filename.c:1
#, c-format
msgid "Hello, world!"
msgstr "Bonjour, %s!"

如果您通过

msgfmt whatever.po
运行此操作,它将被接受。但这不是推荐的工作流程。您应该将其运行一遍
msgfmt --check whatever.po
。现在你得到一个错误:

messages.po:23: number of format specifications in 'msgid' and 'msgstr' does not match
msgfmt: found 1 fatal error

这是因为对于 GNU gettext 支持的每种语言,都实现了格式检查器来准确检查该问题。它确保翻译不会导致运行时问题。

您现在可能会争辩说,恶意翻译器会简单地从

.po
文件中删除“c-format”限定符。但是您的构建系统应该确保从外部源返回的翻译始终与当前的消息集合并,通常称为
YOURPROJECT.pot
,然后对
.po
文件的此类修改将被简单地丢弃。

所以,理论上你没有道理。实际上,您可能会有一个,因为有很多项目和软件直接使用

.po
文件进行运行时翻译。这是一个坏主意,请参阅我对类似问题的回答

我不知道在多大程度上适用于您的问题,因为您没有提到如何将字符串提取到

.pot
文件中以及如何将其编译到二进制
.mo
文件中。上面的解释应该清楚地表明这一点至关重要:提取步骤应向
.po
文件添加有关所使用的字符串插值方法的自动注释,并且将
.po
文件编译为
.mo
文件应启用格式字符串检查。如果你做不到这一点,你的构建系统就有缺陷。

© www.soinside.com 2019 - 2024. All rights reserved.