Repository: pallets/jinja
Pull request #1918 (2023-12-15 14:27:49)

Make nested-trans-block exceptions nicer
* Refs: https://github.com/python-babel/babel/issues/1049

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [ ] Add or update relevant docs, in the docs folder and in code.
  - Not relevant IMO. 
- [x] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [ ] Add `.. versionchanged::` entries in any relevant code docs.
  - Not relevant IMO. 
- [x] Run `pre-commit` hooks and fix any issues.
  - There is an unrelated `flake8` failure. 
- [x] Run `pytest` and `tox`, no tests failed.


davidism: Nice idea, thanks for making this error message clearer! I'm not sure when this will get merged in, but it's on the list.

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index d6688e76..bced976e 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 354b4063..fade1fa3 100644
--- a/src/jinja2/ext.py
+++ b/src/jinja2/ext.py
@@ -495,16 +495,26 @@ class InternationalizationExtension(Extension):
                 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")


Test patch:
diff --git a/tests/test_ext.py b/tests/test_ext.py
index 2e842e0a..0b48ca25 100644
--- a/tests/test_ext.py
+++ b/tests/test_ext.py
@@ -7,6 +7,7 @@ from jinja2 import DictLoader
 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 @@ class TestInternationalization:
             (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):