From: Armin Ronacher Date: Sat, 29 May 2010 20:31:17 +0000 (+0200) Subject: Added a small improvement for the code generation of newstyle gettext X-Git-Tag: 2.5~3 X-Git-Url: http://git.tremily.us/?p=jinja2.git;a=commitdiff_plain;h=b98dad9808784b392f0fe9e20ef0a9d89dbad760 Added a small improvement for the code generation of newstyle gettext calls. --HG-- branch : trunk --- diff --git a/jinja2/ext.py b/jinja2/ext.py index 21a7858..e46287b 100644 --- a/jinja2/ext.py +++ b/jinja2/ext.py @@ -139,9 +139,9 @@ def _make_new_gettext(func): def _make_new_ngettext(func): @contextfunction - def ngettext(__context, __singular, __plural, num, **variables): - variables.setdefault('num', num) - rv = __context.call(func, __singular, __plural, num) + def ngettext(__context, __singular, __plural, __num, **variables): + variables.setdefault('num', __num) + rv = __context.call(func, __singular, __plural, __num) if __context.eval_ctx.autoescape: rv = Markup(rv) return rv % variables @@ -210,6 +210,7 @@ class InternationalizationExtension(Extension): def parse(self, parser): """Parse a translatable tag.""" lineno = next(parser.stream).lineno + num_called_num = False # find all the variables referenced. Additionally a variable can be # defined in the body of the trans block too, but this is checked at @@ -236,8 +237,10 @@ class InternationalizationExtension(Extension): variables[name.value] = var = parser.parse_expression() else: variables[name.value] = var = nodes.Name(name.value, 'load') + if plural_expr is None: plural_expr = var + num_called_num = name.value == 'num' parser.stream.expect('block_end') @@ -251,6 +254,7 @@ class InternationalizationExtension(Extension): referenced.update(singular_names) if plural_expr is None: plural_expr = nodes.Name(singular_names[0], 'load') + num_called_num = singular_names[0] == 'num' # if we have a pluralize block, we parse that too if parser.stream.current.test('name:pluralize'): @@ -263,6 +267,7 @@ class InternationalizationExtension(Extension): name.value, name.lineno, exc=TemplateAssertionError) plural_expr = variables[name.value] + num_called_num = name.value == 'num' parser.stream.expect('block_end') plural_names, plural = self._parse_block(parser, False) next(parser.stream) @@ -281,7 +286,7 @@ class InternationalizationExtension(Extension): parser.fail('pluralize without variables', lineno) node = self._make_node(singular, plural, variables, plural_expr, - bool(referenced)) + bool(referenced), num_called_num) node.set_lineno(lineno) return node @@ -318,7 +323,7 @@ class InternationalizationExtension(Extension): return referenced, concat(buf) def _make_node(self, singular, plural, variables, plural_expr, - vars_referenced): + vars_referenced, num_called_num): """Generates a useful node from the data provided.""" # no variables referenced? no need to escape for old style # gettext invocations @@ -347,6 +352,10 @@ class InternationalizationExtension(Extension): # handling itself if self.environment.newstyle_gettext: for key, value in variables.iteritems(): + # the function adds that later anyways in case num was + # called num, so just skip it. + if num_called_num and key == 'num': + continue node.kwargs.append(nodes.Keyword(key, value)) # otherwise do that here diff --git a/jinja2/testsuite/ext.py b/jinja2/testsuite/ext.py index f97853d..338308c 100644 --- a/jinja2/testsuite/ext.py +++ b/jinja2/testsuite/ext.py @@ -38,7 +38,7 @@ i18n_templates = { '{% trans %}watch out{% endtrans %}{% endblock %}', 'plural.html': '{% trans user_count %}One user online{% pluralize %}' '{{ user_count }} users online{% endtrans %}', - 'stringformat.html': '{{ _("User: %(num)d")|format(num=user_count) }}' + 'stringformat.html': '{{ _("User: %(num)s")|format(num=user_count) }}' } newstyle_i18n_templates = { @@ -48,8 +48,10 @@ newstyle_i18n_templates = { '{% trans %}watch out{% endtrans %}{% endblock %}', 'plural.html': '{% trans user_count %}One user online{% pluralize %}' '{{ user_count }} users online{% endtrans %}', - 'stringformat.html': '{{ _("User: %(num)d", num=user_count) }}', - 'ngettext.html': '{{ ngettext("%(num)d apple", "%(num)d apples", apples) }}' + 'stringformat.html': '{{ _("User: %(num)s", num=user_count) }}', + 'ngettext.html': '{{ ngettext("%(num)s apple", "%(num)s apples", apples) }}', + 'ngettext_long.html': '{% trans num=apples %}{{ num }} apple{% pluralize %}' + '{{ num }} apples{% endtrans %}' } @@ -59,9 +61,9 @@ languages = { 'watch out': u'pass auf', 'One user online': u'Ein Benutzer online', '%(user_count)s users online': u'%(user_count)s Benutzer online', - 'User: %(num)d': u'Benutzer: %(num)d', - '%(num)d apple': u'%(num)d Apfel', - '%(num)d apples': u'%(num)d Äpfel' + 'User: %(num)s': u'Benutzer: %(num)s', + '%(num)s apple': u'%(num)s Apfel', + '%(num)s apples': u'%(num)s Äpfel' } } @@ -327,6 +329,22 @@ class NewstyleInternationalizationTestCase(JinjaTestCase): assert t.render(ae=True) == 'Wert: <test>' assert t.render(ae=False) == 'Wert: ' + def test_num_used_twice(self): + tmpl = newstyle_i18n_env.get_template('ngettext_long.html') + assert tmpl.render(apples=5, LANGUAGE='de') == u'5 Äpfel' + + def test_num_called_num(self): + source = newstyle_i18n_env.compile(''' + {% trans num=3 %}{{ num }} apple{% pluralize + %}{{ num }} apples{% endtrans %} + ''', raw=True) + # quite hacky, but the only way to properly test that. The idea is + # that the generated code does not pass num twice (although that + # would work) for better performance. This only works on the + # newstyle gettext of course + assert re.search(r"l_ngettext, u?'\%\(num\)s apple', u?'\%\(num\)s " + r"apples', 3", source) is not None + class AutoEscapeTestCase(JinjaTestCase):