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_tagtrans的django实现:

分析的重要部分是:

    使用simple_tagtrans,两者最终将具有相同的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 中描述 - 也许文档字符串可能更明确一点。

使用transblocktrans,您基本上可以双向使用,无论是否预先填充。

您仍然可以使用tag 代替simple_tag 并以不同的方式实现它。

我还没有找到任何关于遵循 jinja2-filters 逻辑的指南。这是我的错误假设。

【讨论】:

以上是关于django trans 标签内的过滤器:首先翻译然后应用过滤器;不像其他标签的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 模板中使用带有 blocktrans 的 urlize 过滤器的惯用方式

法语语言环境正在破坏按钮功能

django特殊的标签和过滤器

我如何在Django模板标签中使用模板上下文变量的值? [重复]

我将如何在 Django 模板标签中使用模板上下文变量的值? [复制]

Django的文本国际化