django trans 标签内的过滤器:首先翻译然后应用过滤器;不像其他标签
Posted
技术标签:
【中文标题】django trans 标签内的过滤器:首先翻译然后应用过滤器;不像其他标签【英文标题】:filters inside django trans tag : first translates then applies filters; unlike other tags 【发布时间】:2020-06-30 22:22:59 【问题描述】:我遇到了来自 django trans
标签的奇怪行为。如您所知,每当我们在标签内使用过滤器时,过滤器首先应用,然后将结果作为输入提供给标签。但这与 trans 标签的顺序相反。
例子:
假设我有这个 django.po 文件:
msgid "msgid-world"
msgstr "world"
msgid "msgid-"
msgstr "message"
现在看看这些标签的结果:
% trans "msgid-"|add:"world" %
result: messageworld (first translate then concat)
预期结果:“world”(先concat然后翻译key)
更新:
我的问题是关于一致性。与其他标签(如“if”)的行为相反!
此外,如果我为自己编写一个自定义标签,如下所示:
@register.simple_tag
def customtrans(a):
return _(str(a))
那么它将表现得像其他标签一样。本例的结果(如上例):
% customtrans "msgid-"|add:"world" %
将是“世界”。
这就是我想了解的奥秘!
【问题讨论】:
【参考方案1】:根据jinja2 documentation
变量可以通过过滤器进行修改。过滤器通过管道符号 (|) 与变量分隔,并且可以在括号中包含可选参数。可以链接多个过滤器。一个过滤器的输出应用于下一个过滤器
所以它做了描述的事情:
-
使用参数“msgid-”评估
trans
将结果传递给下一个过滤器并添加“世界”
我建议您使用blocktrans 来实现您的目的
% load i18n %
% blocktrans %
msgid-world
% endblocktrans %
或者你可以使用 with 语句:
% with variable="msgid-"|add:"world"
% trans variable %
% endwith%
还可以查看https://docs.djangoproject.com/en/3.0/topics/i18n/translation/,了解如何解决问题的大量选项
【讨论】:
【参考方案2】:是的你是对的,我分析了simple_tag
和trans
的django实现:
分析的重要部分是:
使用simple_tag
和trans
,两者最终将具有相同的FilterExpression
https://github.com/django/django/blob/e3d546a1d986f83d8698c32e13afd048b65d06eb/django/template/library.py#L123
(Pdb) l
119 args, kwargs = parse_bits(
120 parser, bits, params, varargs, varkw, defaults,
121 kwonly, kwonly_defaults, takes_context, function_name,
122 )
123 -> return SimpleNode(func, takes_context, args, kwargs, target_var)
(Pdb) print(args)
[<django.template.base.FilterExpression object at 0x1061e5cf8>]
(Pdb) print(args[0].__dict__)
'token': '"msgid-"|add:"world"', 'filters': [(<function add at 0x10c2369d8>, [(False, 'world')])], 'var': 'msgid-'
(Pdb) l
368 message_context = None
369 seen = set()
370 invalid_context = 'as', 'noop'
371
372 -> while remaining:
373 option = remaining.pop(0)
374 if option in seen:
376 raise TemplateSyntaxError(
377 "The '%s' option was specified more than once." %
(Pdb) message_string.__dict__
'token': '"msgid-"|add:"world"', 'filters': [(<function add at 0x1112a79d8>, [(False, 'world')])], 'var': 'msgid-'
但现在实现不同了
simple_tag
使用 SimpleNode
,它在传递给你的函数之前首先解析参数 (https://github.com/django/django/blob/e3d546a1d986f83d8698c32e13afd048b65d06eb/django/template/library.py#L191),trans
使用它自己的 TranslationNode
(https://github.com/django/django/blob/e3d546a1d986f83d8698c32e13afd048b65d06eb/django/templatetags/i18n.py#L68) 实现,其行为不同.
一致性 首先,这很有趣,因为我不知道不同的行为。
最后是一个实现细节,这是基于作者的品味。
simple_tag
是这样实现的,它也在代码 https://github.com/django/django/commit/655f52491505932ef04264de2bce21a03f3a7cd0#diff-258b66ed22ebadbcfec255f802c95bdfR173-R176 中描述 - 也许文档字符串可能更明确一点。
使用trans
和blocktrans
,您基本上可以双向使用,无论是否预先填充。
您仍然可以使用tag
代替simple_tag
并以不同的方式实现它。
我还没有找到任何关于遵循 jinja2-filters 逻辑的指南。这是我的错误假设。
【讨论】:
以上是关于django trans 标签内的过滤器:首先翻译然后应用过滤器;不像其他标签的主要内容,如果未能解决你的问题,请参考以下文章
在 Django 模板中使用带有 blocktrans 的 urlize 过滤器的惯用方式
我如何在Django模板标签中使用模板上下文变量的值? [重复]