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

2024-03-18

使用 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] /cdn-cgi/l/email-protection\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] /cdn-cgi/l/email-protection>\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)"

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

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

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

printf("Bonjour, %s!");

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

我们假设代码如下所示:

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

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

好吧,如果软件的维护者使用标准的翻译工作流程,它就不会崩溃。在这种情况下,xgettext(在 Python 中,它可能类似于“pybabel extract”)会在.po file:

#: 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 支持的每种语言,都会实现一个格式检查器来准确检查该问题。它确保翻译不会导致运行时问题。

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

所以,理论上你说的没有道理。在实践中,您可能会拥有一个,因为有很多项目和软件都使用.po文件直接用于运行时翻译。这是一个坏主意,请参阅我的答案 https://stackoverflow.com/questions/53743208/benefits-of-compiling-po-files-to-mo/53819204#53819204类似的问题。

我不知道这在多大程度上适用于你的问题,因为你没有提到如何将字符串提取到你的.pot文件以及如何将其编译为二进制文件.mo文件。上面的解释应该清楚地表明这一点至关重要:提取步骤应该向.po关于所使用的字符串插值方法的文件,以及.po文件到一个.mo文件应启用格式字符串检查。如果你做不到这一点,那么你的构建系统就有缺陷。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 gettext 和 jinja2 以及金字塔翻译 %% 的相关文章

  • python ImportError:没有名为 Tkinter 的模块

    每次我尝试奔跑import matplotlib 我有错误ImportError No module named Tkinter 输出结果如下所示 Python 2 7 5 default Aug 2 2016 04 20 16 GCC 4
  • Python 谷歌语音

    我正在使用 google voice APIhere https pypi python org pypi pygooglevoice 0 5 并尝试从 Python 发送短信 但是 每当我尝试使用此代码登录时 我都会得到一些意想不到的信息
  • Jinja 安装 python

    我不经常使用 Python 但现在我必须使用 我应该运行一个需要 Jinja 的 python sctipt Python2 7 安装在我的 Windows XP 上并且可以工作 但我找不到如何安装 inja 包 有人愿意为我写一份分步安装
  • 快速实现单词的字符 n 元语法

    我编写了以下代码来计算字符二元组 输出就在下面 我的问题是 如何获得不包括最后一个字符 即 t 的输出 有没有更快 更有效的方法来计算字符 n 元语法 b student gt gt gt y gt gt gt for x in range
  • 如何将任何语言和字符集的字符串转换为 Java 中的有效文件名?

    我需要根据用户输入的名称生成文件名 这些名称可以是任何语言 例如 约翰 史密斯 高岡和子 我爱你 这些是使用输入的值 因此我不能保证名称不包含文件名中无效的字符 用户将从浏览器下载这些文件 因此我需要确保文件名在所有配置的所有操作系统上都有
  • Python 2.7 - statsmodels - 格式化和编写摘要输出

    我正在使用逻辑回归pandas 0 11 0 数据处理 和statsmodels 0 4 3在 Mac OSX Lion 上进行实际回归 我将运行约 2 900 个不同的逻辑回归模型 并需要将结果输出到 csv 文件并以特定方式格式化 目前
  • Python 类中的继承顺序

    我有课ExampleSim它继承自基类Physics class Physics object arg1 arg1 def physics method print physics method class ExampleSim Physi
  • 使用 Google App Engine 和 Django 将第三方库 (twilio) 添加到项目中

    每个人 我是这个领域的新手 我使用 django 框架使用 google 应用引擎开发 Web 应用程序 我有一个关于 python lib dir 问题的故障排除 导入错误 没有名为 的模块 我的 appengine config py
  • os.listdir 和 os.path.isdir 混淆,isdir 是随机的吗?

    我有下面这个简单的过程来列出文件夹的内容 def some process self dir3 os listdir Users somepath programming somepathanother Data samples for d
  • numpy.polyfit 给出有用的拟合,但协方差矩阵无限

    我正在尝试将多项式拟合到一组数据 有时可能会出现以下情况 返回的协方差矩阵numpy ployfit仅由inf 尽管拟合似乎很有用 没有numpy inf或数据中的 numpy nan Example import numpy as np
  • 在yaml中写入#(在字符串中)

    我是新使用 yml 文件 用于我的框架中的翻译 我试图在翻译中添加一个 将是一个推特分享 blabla 这可能吗 因为文件将其翻译为评论 只需将值放在单引号或双引号内 它就不会被视为注释 就像是 en twitter share hasht
  • python 2.7模块pandas未安装“无法导入名称哈希表”

    我尝试在论坛 谷歌上寻找这个问题的答案 但我找不到任何东西 我的问题是这样的 来自 python 控制台 gt gt gt import pandas cannot import name hashtable Traceback most
  • 不能在jinja2宏中使用current_user?

    我使用 Flask Login 它提供了current user模板中的对象 我想编写一个宏来显示评论表单或登录链接 具体取决于用户是否登录 如果我直接在模板中使用此代码 它会起作用 if current user is authentic
  • SQLAlchemy 与 celery 的会话问题

    我已经为我们的网络应用程序安排了一些使用 celerybeat 重复执行的任务 该应用程序本身是使用金字塔网络框架构建的 使用 zopetransaction 扩展来管理会话 在 celery 中 我将该应用程序用作库 我正在使用函数重新定
  • NameError:名称“urllib”未定义”

    CODE import networkx as net from urllib request import urlopen def read lj friends g name fetch the friend list from Liv
  • 无法将图形另存为 .eps [gswin32c 无法识别]

    我使用Pylab 64位 的Enth tough冠层 在我的报告中 我需要使用乳胶 Xelatex 并使用matplotlib完成图 为了获得第一个想法 我刚刚复制了第二个示例http matplotlib org users usetex
  • 使用 psycopg2 在 python 中执行查询时出现“编程错误:语法错误位于或附近”

    我正在运行 Python v 2 7 和 psycopg2 v 2 5 我有一个 postgresql 数据库函数 它将 SQL 查询作为文本字段返回 我使用以下代码来调用该函数并从文本字段中提取查询 cur2 execute SELECT
  • ipython/ pylab/ matplotlib安装和初始化错误

    我在 OS X El Captain 上安装了 matplotlib anaconda ipython 然而 即使在尝试以所有可能的方式设置环境变量之后 我仍无法启动 ipython shell pylab 版本 这是错误 ImportEr
  • 绘制与Fig.show()内联的IPython Notebook图形?

    我正在使用 IPython Notebook 调用内联模式 pylab inline 以下代码立即在单元格处绘制一个图形 fig plt figure axes fig add axes 0 0 1 1 不过 我想在一个单元格中创建绘图 轴
  • 从列表指向字典变量

    假设你有一个清单 a 3 4 1 我想用这些信息来指向字典 b 3 4 1 现在 我需要的是一个常规 看到该值后 在 b 的位置内读写一个值 我不喜欢复制变量 我想直接改变变量b的内容 假设b是一个嵌套字典 你可以这样做 reduce di

随机推荐