]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
specify context for translation block 1559/head
authorDavid Lord <davidism@gmail.com>
Sun, 26 Dec 2021 18:29:39 +0000 (11:29 -0700)
committerDavid Lord <davidism@gmail.com>
Sun, 26 Dec 2021 18:51:54 +0000 (11:51 -0700)
CHANGES.rst
docs/templates.rst
src/jinja2/ext.py
tests/test_ext.py

index d641712db437004f9580da30c2e724e7532f3378..323fc80ddd78ad631017a89f65410f40f75b2251 100644 (file)
@@ -23,6 +23,9 @@ Unreleased
     -   ``unicode_urlencode`` is renamed to ``url_quote``.
 
 -   Add support for native types in macros. :issue:`1510`
+-   The ``{% trans %}`` tag can use ``pgettext`` and ``npgettext`` by
+    passing a context string as the first token in the tag, like
+    ``{% trans "title" %}``. :issue:`1430`
 
 
 Version 3.0.3
index 89958b86f6e6ac1212fc1549d2c4d98186d419d8..9071ad671884cd42a472260d0e62523a7aa8a8cf 100644 (file)
@@ -1732,11 +1732,35 @@ to disable it for a block.
 .. versionadded:: 2.10
    The ``trimmed`` and ``notrimmed`` modifiers have been added.
 
+If the translation depends on the context that the message appears in,
+the ``pgettext`` and ``npgettext`` functions take a ``context`` string
+as the first argument, which is used to select the appropriate
+translation. To specify a context with the ``{% trans %}`` tag, provide
+a string as the first token after ``trans``.
+
+.. code-block:: jinja
+
+    {% trans "fruit" %}apple{% endtrans %}
+    {% trans "fruit" trimmed count -%}
+        1 apple
+    {%- pluralize -%}
+        {{ count }} apples
+    {%- endtrans %}
+
+.. versionadded:: 3.1
+    A context can be passed to the ``trans`` tag to use ``pgettext`` and
+    ``npgettext``.
+
 It's possible to translate strings in expressions with these functions:
 
--   ``gettext``: translate a single string
--   ``ngettext``: translate a pluralizable string
--   ``_``: alias for ``gettext``
+-   ``_(message)``: Alias for ``gettext``.
+-   ``gettext(message)``: Translate a message.
+-   ``ngettext(singluar, plural, n)``: Translate a singular or plural
+    message based on a count variable.
+-   ``pgettext(context, message)``: Like ``gettext()``, but picks the
+    translation based on the context string.
+-   ``npgettext(context, singular, plural, n)``: Like ``npgettext()``,
+    but picks the translation based on the context string.
 
 You can print a translated string like this:
 
index d21b83aafef95bbe0a7f0ee5957e352a4b328030..d5550540cda01ea9da32747754d34603a7bbac0a 100644 (file)
@@ -354,13 +354,19 @@ class InternationalizationExtension(Extension):
     def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]:
         """Parse a translatable tag."""
         lineno = next(parser.stream).lineno
-        num_called_num = False
+
+        context = None
+        context_token = parser.stream.next_if("string")
+
+        if context_token is not None:
+            context = context_token.value
 
         # find all the variables referenced.  Additionally a variable can be
         # defined in the body of the trans block too, but this is checked at
         # a later state.
         plural_expr: t.Optional[nodes.Expr] = None
         plural_expr_assignment: t.Optional[nodes.Assign] = None
+        num_called_num = False
         variables: t.Dict[str, nodes.Expr] = {}
         trimmed = None
         while parser.stream.current.type != "block_end":
@@ -455,6 +461,7 @@ class InternationalizationExtension(Extension):
         node = self._make_node(
             singular,
             plural,
+            context,
             variables,
             plural_expr,
             bool(referenced),
@@ -510,6 +517,7 @@ class InternationalizationExtension(Extension):
         self,
         singular: str,
         plural: t.Optional[str],
+        context: t.Optional[str],
         variables: t.Dict[str, nodes.Expr],
         plural_expr: t.Optional[nodes.Expr],
         vars_referenced: bool,
@@ -526,21 +534,18 @@ class InternationalizationExtension(Extension):
             if plural:
                 plural = plural.replace("%%", "%")
 
-        # singular only:
-        if plural_expr is None:
-            gettext = nodes.Name("gettext", "load")
-            node = nodes.Call(gettext, [nodes.Const(singular)], [], None, None)
+        func_name = "gettext"
+        func_args: t.List[nodes.Expr] = [nodes.Const(singular)]
 
-        # singular and plural
-        else:
-            ngettext = nodes.Name("ngettext", "load")
-            node = nodes.Call(
-                ngettext,
-                [nodes.Const(singular), nodes.Const(plural), plural_expr],
-                [],
-                None,
-                None,
-            )
+        if context is not None:
+            func_args.insert(0, nodes.Const(context))
+            func_name = f"p{func_name}"
+
+        if plural_expr is not None:
+            func_name = f"n{func_name}"
+            func_args.extend((nodes.Const(plural), plural_expr))
+
+        node = nodes.Call(nodes.Name(func_name, "load"), func_args, [], None, None)
 
         # in case newstyle gettext is used, the method is powerful
         # enough to handle the variable expansion and autoescape
index b54e905ffd088a0948ba3b68f4960c2f5b2a95ab..2e842e0ab54a237118d1e4273b245aec4ff4f872 100644 (file)
@@ -43,6 +43,9 @@ newstyle_i18n_templates = {
     "pgettext.html": '{{ pgettext("fruit", "Apple") }}',
     "npgettext.html": '{{ npgettext("fruit", "%(num)s apple", "%(num)s apples",'
     " apples) }}",
+    "pgettext_block": "{% trans 'fruit' num=apples %}Apple{% endtrans %}",
+    "npgettext_block": "{% trans 'fruit' num=apples %}{{ num }} apple"
+    "{% pluralize %}{{ num }} apples{% endtrans %}",
     "transvars1.html": "{% trans %}User: {{ num }}{% endtrans %}",
     "transvars2.html": "{% trans num=count %}User: {{ num }}{% endtrans %}",
     "transvars3.html": "{% trans count=num %}User: {{ count }}{% endtrans %}",
@@ -593,11 +596,20 @@ class TestNewstyleInternationalization:
         tmpl = newstyle_i18n_env.get_template("pgettext.html")
         assert tmpl.render(LANGUAGE="de") == "Apple"
 
-    def test_context_newstyle_plural(self):
+    def test_context_plural(self):
         tmpl = newstyle_i18n_env.get_template("npgettext.html")
         assert tmpl.render(LANGUAGE="de", apples=1) == "1 Apple"
         assert tmpl.render(LANGUAGE="de", apples=5) == "5 Apples"
 
+    def test_context_block(self):
+        tmpl = newstyle_i18n_env.get_template("pgettext_block")
+        assert tmpl.render(LANGUAGE="de") == "Apple"
+
+    def test_context_plural_block(self):
+        tmpl = newstyle_i18n_env.get_template("npgettext_block")
+        assert tmpl.render(LANGUAGE="de", apples=1) == "1 Apple"
+        assert tmpl.render(LANGUAGE="de", apples=5) == "5 Apples"
+
 
 class TestAutoEscape:
     def test_scoped_setting(self):