当我现在想将 i18n 应用于该字符串时,我可能会转向gettext
或框架函数。因为我来自 PHP/ Joomla!世界,我以前用过JText::_
,它的行为与gettext
. 在 Python 中,我现在使用Babel。两者都有相同的问题,可能还有更多的语言。我在这里分享的所有代码都是我在 Python 中执行的方式,更明确地说,在我的Mako 模板中
当然,问题是:我们的字符串中有 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
所以作为一个结论,当我使用这个时,我很快就达到了我的极限。我的下一个想法是:
将文本分成三位
方法二:
_('Welcome to my site. Check out our cool ') + '<a href="/products">' +\
_('products') + '</a>' + _(' you should not miss.')
优点:
缺点:
- 将一个句子分成三个部分
- 翻译者必须知道哪些部分相互关联,否则他可能无法产生有意义的句子
- 代码不是很漂亮
- The
msgid
可能是一个单词,可能会导致问题(注意上下文),但可以修复。
我使用这种技术有一段时间了,因为我不知道printf
PHP 中的样式字符串(我当时使用过)。因为这看起来很丑,我尝试了一种不同的方法:
用变量包围链接词
方法3:
_('Welcome to my site. Check out our cool %sproducts%s you should not miss.' % \
('<a href="/products">', '</a>')
优点:
- 单串要翻译,一个完整的句子
- 翻译器直接从字符串中获取上下文
- 代码没那么难看
缺点:
- 译者必须注意不要
%s
遗漏(读起来可能会造成混淆sproducts
)
- 为每个 URL 引入两个格式字符串变量,一个仅
</a>
使用一个单独构建的变量
从这里我有一些不同的方法,但我最终选择了我目前使用的一种(这可能看起来有点矫枉过正,但我现在更喜欢它)。
方法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.')
这给翻译留下了插入的信息(即翻译字符串版本)。其次,我想确保我可以手动转义插入到 HTML 中的所有部分。虽然 Mako 提供了自动转义,但这在这样的语句中是没有意义的:
${'This is a <a href="/">url</a>'}
它会破坏 url,所以我必须应用|n
过滤器来删除任何转义。但是,如果用户提供了任何参数,它也会打开我想要阻止的 XSS。不冒任何风险,我可以转义任何输入(就像好的模板引擎默认做的一样),然后删除 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.TranslationStringmapping
)的关键字参数,但这结合了我想要/需要从翻译中获得的所有好处:translationstring
最后结果:
_('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 转义
- 全动态
- 非常
msgid
适合翻译
缺点:
- 模板中的一个极其丑陋的构造(或程序)
- 语言提取器没有捕获
_('products')
,所以我们必须手动提取它
就是这样,这结束了我解决这个问题的方法。也许我正在做一些复杂的事情,而您有很多更好的想法,或者这可能是一个取决于特定类型的可翻译文本的问题(并且必须选择正确的方法)。
我是否错过了任何解决方案或任何可以改进我的方法的东西?