【问题标题】:coding style for HTML i18n/l10n with variables带有变量的 HTML i18n/l10n 的编码样式
【发布时间】:2013-03-07 14:16:13
【问题描述】:

我从事网络开发已经有一段时间了,我一直在努力寻找一个干净的解决方案来解决我在 HTML 字符串(主要是锚标记)的 i18n 期间遇到的问题。

首先让我给你看一个典型的有问题的例子。这是 HTML 模板中经常遇到的字符串:

Welcome to my site. Check out our cool <a href="/products">products</a> 
you should not miss.

如何翻译此字符串同时仍具有以下属性:

  • 动态生成 URL(例如使用路由器)
  • 尽可能可读的可翻译字符串(因此翻译人员无需查看代码即可完成)
  • 因为字符串包含 HTML,我可能想转义我插入的某些部分(例如 URL),所以如果这个 URL 包含用户输入,我不会让自己容易受到 XSS 攻击
  • 它在代码中也应该看起来尽可能好

当您的字符串包含动态内容和 HTML 时,您如何翻译它们?

【问题讨论】:

  • 一个提示是不要硬编码你的网址
  • 我意识到这是解决方案的一部分(这就是我将其包含在下面的原因),但它并没有解决问题。

标签: php python html localization internationalization


【解决方案1】:

当我现在想将 i18n 应用于该字符串时,我可能会转向 gettext 或框架函数。由于我来自 PHP/Joomla! 世界,所以我之前使用过JText::_,它的作用与gettext 非常相似。在 Python 中,我现在使用 Babel。两者都有相同的问题,可能还有更多的语言。我在这里分享的所有代码都是我用 Python 做的,更明确地说,在我的Mako templates

当然,问题是:我们的字符串中有 HTML 需要翻译(还有一个 URL)。以下是我的选择,我将在后面逐一解释:

  • 将原始字符串传递给gettext
  • 将文本分成三位
  • 用变量包围链接词
  • 使用单独构建的一个变量

将原始字符串传递给gettext

这似乎是人们可能采取的第一种方法,如果不知道其中的含义的话。

方法一:

_('Welcome to my site. Check out our cool <a href="/products">products</a> \
you should not miss.')

对于这个msgid,您现在可以翻译它,保持 HTML 不变。

优点:

  • 这在代码中看起来很干净,很容易理解
  • 如果翻译器保持 HTML 完整,这不会产生任何问题

缺点:

  • 翻译者必须至少懂一点 HTML
  • 字符串完全不灵活,例如如果 URL 发生变化,则必须调整所有翻译
  • 它不允许使用类似路由器的东西动态生成 URL

因此,作为结论,当我使用它时,我很快就达到了我的极限。我的下一个想法是:

将文本分成三位

方法2:

_('Welcome to my site. Check out our cool ') + '<a href="/products">' +\
_('products') + '</a>' + _(' you should not miss.')

优点:

  • URL 现在完全灵活了
  • 仅为翻译人员提供实际文本

缺点:

  • 将一个句子分成三部分
  • 翻译者必须知道哪些部分相互关联,否则他可能无法产生有意义的句子
  • 代码不是很漂亮
  • msgid 可能是一个单词,可能会导致问题(注意上下文),但可以修复。

我使用这种技术有一段时间了,因为我不知道 PHP 中的 printf 样式字符串(我当时使用过)。因为这看起来很丑,所以我尝试了另一种方法:

用变量包围链接词

方法 3:

_('Welcome to my site. Check out our cool %sproducts%s you should not miss.' % \
('<a href="/products">', '</a>')

优点:

  • 要翻译的单个字符串,一个完整的句子
  • 翻译器直接从字符串中获取上下文
  • 代码并不那么

缺点:

  • 翻译人员必须注意不要丢失任何%s(可能会造成混淆,因为它看起来像sproducts
  • 为每个 URL 引入两个格式字符串变量,一个只有 &lt;/a&gt;

使用一个单独构建的变量

从这里开始,我有一些不同的方法,但我最终找到了我目前使用的那个(可能看起来有点过头了,但我现在更喜欢它)。

方法 4:

_('Welcome to my site. Check out our cool %s \
you should not miss.') % ('<a href="%s">%s</a>' % ('/products', _('products')))

让我花点时间来解释一下这种(看似疯狂的)方法。首先,实际的翻译字符串是这样的:

_('Welcome to my site. Checkout our cool ${product_url} \
you should not miss.')

这让翻译人员知道插入的信息(即translationstring 版本)。其次,我想确保我可以手动转义插入到 HTML 中的所有部分。虽然 Mako 提供了automatic escaping,但这在这样的声明中没有意义:

${'This is a <a href="/">url</a>'}

它会破坏 url,所以我必须应用 |n 过滤器来删除任何转义。但是,如果用户提供了任何参数,它也会打开我想要阻止的 XSS。不冒任何风险,我可以转义 any 输入(就像好的模板引擎默认做的那样),然后删除 Mako 对这个字符串的转义。所以

'<a href="%s">%s</a>' % ('/products', _('products'))

其实是这样的

'<a href="%s">%s</a>' % (escape('/products'), _('products'))

其中escape 是从markupsafe 导入的(参见Markupsafe)。

现在的最后一部分是通过路由器的动态 URL:request.route_url('products_view')

为了结合这些可能性,我必须产生一些非常丑陋的东西(注意,这使用了 translationstring (translationstring.TranslationString) 的 mapping 关键字参数,但这结合了我想要/需要从翻译中获得的所有好处:

最终结果:

_('Welcome to my site. Checkout our cool ${product_url} \
you should not miss.', mapping={'product_url': '<a href="%s">%s</a>' %\
(escape(request.route_url('products_view')), _('products'))})

优点:

  • 完整的 HTML 转义
  • 完全动态
  • 翻译非常好msgids

缺点:

  • 模板中的一个非常丑陋的构造(或程序)
  • 语言提取器无法捕获 _('products'),因此我们必须手动提取它

就是这样,我解决这个问题的方法到此结束。也许我正在做一些复杂的方式,而你有很多更好的想法,或者这可能是一个取决于特定类型的可翻译文本的问题(并且必须选择正确的方法)。

我是否错过了任何解决方案或任何可以改进我的方法的东西?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2011-05-31
    • 2016-01-06
    • 1970-01-01
    相关资源
    最近更新 更多