【问题标题】:Extending Jinja's {% trans %} to use JavaScript variables扩展 Jinja 的 {% trans %} 以使用 JavaScript 变量
【发布时间】:2016-01-22 05:18:26
【问题描述】:

我想扩展trans 的行为,将变量呈现为不是来自上下文的值,而是呈现为html(不使用上下文)。我的目标是能够通过 JavaScript 在客户端上填充这些变量。

Jinja 似乎不允许进行大量此类自定义,否则我就是找不到合适的钩子。

这是我想要实现的目标:

{% etrans name=username %}
My name is {{ name }}
{% endetrans %}

这应该呈现到:

My name is <span id='#username'></span>

当然,我可以只使用普通的 {% trans %} 指令并将我的 html 代码传递给 template.render(html_code_params),但这需要在模板中定义它们以及我想避免的呈现代码。

这是我目前得到的(不多),它允许一个新的etrans 标签和使用InternationalizationExtension 提供的任何好东西的能力。

from jinja2.ext import InternationalizationExtension
from jinja2.runtime import concat


class JavaScriptVariableExtension(InternationalizationExtension):
    tagname = 'etrans'
    tags = set([tagname])

    def _parse_block(self, parser, allow_pluralize):
        """Parse until the next block tag with a given name.

        Copy from InternationalizationExtension, as this uses hardcoded
        `name:endtrans` instead of relying on tag name
        """
        referenced = []
        buf = []
        while 1:
            if parser.stream.current.type == 'data':
                buf.append(parser.stream.current.value.replace('%', '%%'))
                next(parser.stream)
            elif parser.stream.current.type == 'variable_begin':
                next(parser.stream)
                name = parser.stream.expect('name').value
                referenced.append(name)
                buf.append('%%(%s)s' % name)
                parser.stream.expect('variable_end')
            elif parser.stream.current.type == 'block_begin':
                next(parser.stream)
                # can't use hardcoded "endtrans"
                # if parser.stream.current.test('name:endtrans'):
                if parser.stream.current.test('name:end%s' % self.tagname):
                    break
                elif parser.stream.current.test('name:pluralize'):
                    if allow_pluralize:
                        break
                    parser.fail('a translatable section can have only one '
                                'pluralize section')
                parser.fail('control structures in translatable sections are '
                            'not allowed')
            elif parser.stream.eos:
                parser.fail('unclosed translation block')
            else:
                assert False, 'internal parser error'

        return referenced, concat(buf)


i18n_extended = JavaScriptVariableExtension

我不介意重载更多方法(尽管上述方法的原因可能应该在上游修复)。

单步调试代码是一次非常有趣的冒险。但是,我遇到了一个障碍,如果有人可以提供一些建议,我很感兴趣。

我看到的问题是,在编译过程中,函数 context.resolve() 被烘焙到编译后的代码中。 jinja2.jinja2.compiler.CodeGenerator 确实不允许在这里进行任何不同的处理(如果我错了,请纠正我)。理想情况下,我会定义另一个节点(用于变量),这个节点将处理它在编译期间的处理方式,但我不明白这是怎么可能的。我可能过于关注这个作为解决方案,所以也许有人可以提供替代方案。

【问题讨论】:

  • 你有没有想过一个函数来生成所需的 HTML,用法如下:My name is {{ slug("username") }}
  • 不,我没有。那将是另一种解决方案。如果我找不到更接近我的想法的东西,我会解决这个问题。
  • 试过了,但似乎不起作用。作为宏 slug{% trans %} 环境中无法识别(但在外部有效)。
  • 将函数传递到渲染环境是可行的(也可以在 trans 标头中使用宏并将其分配给变量)。
  • 优秀 - 如果您找到了可行的解决方案,请随时将其转化为答案

标签: python compilation jinja2 python-babel


【解决方案1】:

正如@Garrett 的评论所建议的,一个更简单的解决方案是将一个函数传递给插入变量的模板渲染器。就我而言,我的目标客户端框架是 Angular,但这也适用于您想在 {% trans %} 环境中使用的任何 JS 变量。以下是构建块:

def text_to_javascript(string):
    # modify as needed... 
    return "<span>{{ %s }}</span>" % string

def render():
    tmpl = jinja_env.get_template(template_filename)
    return tmpl.render({'js': text_to_javascript})

这就是我在模板文件中使用它的方式:

{% trans username=js('user.name') %}
  My name is {{ username }}
{% endtrans %}

在 Angular 控制器中,变量 user 绑定到 $scope,如下所示:

$scope.user = {'name': 'Bugs Bunny'}

【讨论】:

    猜你喜欢
    • 2011-06-19
    • 2018-11-03
    • 1970-01-01
    • 2015-12-13
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 2018-08-20
    • 1970-01-01
    相关资源
    最近更新 更多