Repository: pypi/warehouse

Issue:
All trans tags should be trimmed by default
Having translation strings not be trimmed always results in ugly things for translators.

We can approach this in 2 ways:
- The simple but inelegant way: add `trimmed` to all existing trans tags and a CI check to ensure it's added to future tags too
- The elegant way: tell jinja2/gettext to trim by default and subsequently remove all `trimmed` parameters.

The problem for solution number 2 is that it requires a way to access the [policies on the Jinja2 environment](https://jinja.palletsprojects.com/en/2.11.x/api/#ext-i18n-trimmed), and I haven't been able to find how to do so using `pyramid_jinja2`.

If anyone finds how to do so...


Discussion:

Resolving patch:
diff --git a/warehouse/config.py b/warehouse/config.py
--- a/warehouse/config.py
+++ b/warehouse/config.py
@@ -410,7 +410,11 @@ def configure(settings=None):
 
     # We need to enable our Client Side Include extension
     config.get_settings().setdefault(
-        "jinja2.extensions", ["warehouse.utils.html.ClientSideIncludeExtension"]
+        "jinja2.extensions",
+        [
+            "warehouse.utils.html.ClientSideIncludeExtension",
+            "warehouse.i18n.extensions.TrimmedTranslatableTagsExtension",
+        ],
     )
 
     # We'll want to configure some filters for Jinja2 as well.
diff --git a/warehouse/i18n/extensions.py b/warehouse/i18n/extensions.py
new file mode 100644
--- /dev/null
+++ b/warehouse/i18n/extensions.py
@@ -0,0 +1,22 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from jinja2.ext import Extension
+
+
+class TrimmedTranslatableTagsExtension(Extension):
+    """
+    This extension ensures all {% trans %} tags are trimmed by default.
+    """
+
+    def __init__(self, environment):
+        environment.policies["ext.i18n.trimmed"] = True


Test patch:
diff --git a/tests/functional/test_templates.py b/tests/functional/test_templates.py
--- a/tests/functional/test_templates.py
+++ b/tests/functional/test_templates.py
@@ -48,6 +48,7 @@ def test_templates_for_empty_titles():
         extensions=[
             "jinja2.ext.i18n",
             "warehouse.utils.html.ClientSideIncludeExtension",
+            "warehouse.i18n.extensions.TrimmedTranslatableTagsExtension",
         ],
         cache_size=0,
     )
@@ -85,6 +86,7 @@ def test_render_templates():
         extensions=[
             "jinja2.ext.i18n",
             "warehouse.utils.html.ClientSideIncludeExtension",
+            "warehouse.i18n.extensions.TrimmedTranslatableTagsExtension",
         ],
         cache_size=0,
     )
diff --git a/tests/unit/i18n/test_extensions.py b/tests/unit/i18n/test_extensions.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/i18n/test_extensions.py
@@ -0,0 +1,40 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import pytest
+
+from jinja2 import Environment
+
+
+@pytest.mark.parametrize(
+    "ext, result",
+    [
+        # Just a sanity check: test that when we do nothing, text is not trimmed.
+        ([], "   hey   "),
+        # Now test that with our extension, text is trimmed.
+        (["warehouse.i18n.extensions.TrimmedTranslatableTagsExtension"], "hey"),
+    ],
+)
+def test_trim_trans_tags(ext, result):
+    env = Environment(
+        extensions=["jinja2.ext.i18n"] + ext,
+    )
+
+    class Faketext:
+        # Every method is identity
+        def __getattribute__(self, _: str):
+            return lambda x: x
+
+    env.install_gettext_translations(Faketext())
+
+    # Result is trimmed
+    assert env.from_string("{% trans %}   hey   {% endtrans %}").render() == result