diff --git a/CHANGES.rst b/CHANGES.rst index d6688e762..bced976e5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,6 +8,8 @@ Unreleased - Fix compiler error when checking if required blocks in parent templates are empty. :pr:`1858` - ``xmlattr`` filter does not allow keys with spaces. GHSA-h5c8-rqwp-cp95 +- Make error messages stemming from invalid nesting of ``{% trans %}`` blocks + more helpful. :pr:`1916` Version 3.1.2 diff --git a/src/jinja2/ext.py b/src/jinja2/ext.py index 354b4063d..fade1fa3b 100644 --- a/src/jinja2/ext.py +++ b/src/jinja2/ext.py @@ -495,16 +495,26 @@ def _parse_block( parser.stream.expect("variable_end") elif parser.stream.current.type == "block_begin": next(parser.stream) - if parser.stream.current.test("name:endtrans"): + block_name = ( + parser.stream.current.value + if parser.stream.current.type == "name" + else None + ) + if block_name == "endtrans": break - elif parser.stream.current.test("name:pluralize"): + elif block_name == "pluralize": if allow_pluralize: break parser.fail( "a translatable section can have only one pluralize section" ) + elif block_name == "trans": + parser.fail( + "trans blocks can't be nested; did you mean `endtrans`?" + ) parser.fail( - "control structures in translatable sections are not allowed" + f"control structures in translatable sections are not allowed; " + f"saw `{block_name}`" ) elif parser.stream.eos: parser.fail("unclosed translation block") diff --git a/tests/test_ext.py b/tests/test_ext.py index 2e842e0ab..0b48ca258 100644 --- a/tests/test_ext.py +++ b/tests/test_ext.py @@ -7,6 +7,7 @@ from jinja2 import Environment from jinja2 import nodes from jinja2 import pass_context +from jinja2 import TemplateSyntaxError from jinja2.exceptions import TemplateAssertionError from jinja2.ext import Extension from jinja2.lexer import count_newlines @@ -468,6 +469,18 @@ def test_extract_context(self): (3, "npgettext", ("babel", "%(users)s user", "%(users)s users", None), []), ] + def test_nested_trans_error(self): + s = "{% trans %}foo{% trans %}{% endtrans %}" + with pytest.raises(TemplateSyntaxError) as excinfo: + i18n_env.from_string(s) + assert "trans blocks can't be nested" in str(excinfo.value) + + def test_trans_block_error(self): + s = "{% trans %}foo{% wibble bar %}{% endwibble %}{% endtrans %}" + with pytest.raises(TemplateSyntaxError) as excinfo: + i18n_env.from_string(s) + assert "saw `wibble`" in str(excinfo.value) + class TestScope: def test_basic_scope_behavior(self):