我想通过渲染变量而不是上下文中的值来扩展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
并不真正允许任何不同的处理(如果我错了,请纠正我)。理想情况下,我会定义另一个节点(对于变量),这个节点将处理它在编译过程中处理的方式,但我不知道这是如何实现的。我可能过于专注于此作为解决方案,所以也许有人可以提供替代方案。
答案 0 :(得分: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'}