Skip to content
This repository

Strings containing escape chars are not properly translated #133

wants to merge 2 commits into from

2 participants

Brian Sutherland Malthe Borch
Brian Sutherland

This currently fails because escaping is applied before translation. Meaning untranslated strings as the msgids in the ,po files don't match what gets sent to the translate function :(

Unfortunately I only have time right now to provide a failing test case, will look for the bug if time allows and no-one gets there first...

Brian Sutherland A test for translating strings containing escape chars
This test currently fails because escaping is applied
before translation.
Malthe Borch

Sorry, I haven't seen this one before now.

Malthe Borch

I don't agree: 48868c2.

I could be wrong, but this isn't how i18n:translate works. But note that in your example, ${text} means that whatever string is in text will be escaped. If you wanted this to be different, put ${structure: text}.

But i18n:translate is XML-agnostic. It doesn't know about it.

Brian Sutherland

I had another look at my test, I guess I wasn't being very clear. I've updated it with one that passes but still shows what I think is an inconsistency.

I had naively expected this template: <tal:tag i18n:translate="">hello <span i18n:name="world" tal:replace="world"/></tal:tag> to be exactly the same as <tal:tag i18n:translate="">hello ${world}</tal:tag>. It appears as if it they are not the same. That makes the second syntax something to avoid as the way it mixes with translations is not very intuitive.

Not sure this is a bug though, so feel free to close this pull request if you aren't going to take any action.

Malthe Borch
malthe commented May 15, 2013

In the default translation mode (explicit), the fact that your expression ${world} looks like an i18n:name (i.e. an identifier) does not mean that it's automatically turned into one.

But it could be that way. The problem is that e.g. ${world.upper()} isn't an identifier and then you'd have to explicitly assign it an i18n:name (such as "world"). While often times a tal:replace is simply an identifier (or variable), it's also often a non-trivial expression such as item.title.

There's such a thing as implicit translation mode with Chameleon. It's easy to enable:

implicit_i18n_translate = True

With implicit translation, you don't need i18n:translate. But it might make implicit choices you don't agree with.

Brian Sutherland
jinty commented May 15, 2013

I'm closing this pull as "wontfix" so it doesn't add to the clutter.

I understand the issue now and guess I'll just stick to the verbose tal:name syntax for translation heavy apps. I definitely prefer explicitness :)

Many thanks for taking the time to explain what's happening.

Brian Sutherland jinty closed this May 15, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 2 unique commits by 1 author.

Nov 08, 2012
Brian Sutherland A test for translating strings containing escape chars
This test currently fails because escaping is applied
before translation.
Jan 14, 2013
Brian Sutherland try make test clearer df984d1
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 27 additions and 0 deletions. Show diff stats Hide diff stats

  1. 27  src/chameleon/tests/
27  src/chameleon/tests/
@@ -306,6 +306,33 @@ def test_null_translate_function(self):
306 306
         rendered = template(test=object())
307 307
         self.assertTrue('object' in rendered)
308 308
+    def test_translate_escape_chars(self):
+        def translate(msgid, domain=None, mapping=None, context=None,
+                      target_language=None, default=None):
+            if msgid == 'hello ${world}':
+                return "translated: hello {world}".format(**mapping)
+            return msgid
+        # ZPT style
+        template = '<tal:tag i18n:translate="">hello <span i18n:name="world" tal:replace="world"/></tal:tag>'
+        template = self.from_string(template, translate=translate)
+        # test without escapes
+        rendered = template(world="worl'd")
+        self.assertEqual(rendered, "translated: hello worl'd")
+        # test with escapes (should also be translated, then ecaped)
+        rendered = template(world="&<>")
+        self.assertEqual(rendered, 'translated: hello &amp;&lt;&gt;')
+        # ${style} tags
+        template = '<tal:tag i18n:translate="">hello ${world}</tal:tag>'
+        template = self.from_string(template, translate=translate)
+        # test without escapes, no translation as substitution happens before
+        rendered = template(world="&<>")
+        self.assertEqual(rendered, "hello worl'd")
+        # test with escapes, no translation as substitution happens before
+        rendered = template(world=escapes)
+        self.assertEqual(rendered, 'hello &amp;&lt;&gt;')
309 336
     def test_object_substitution_coerce_to_str(self):
310 337
         template = self.from_string('${test}', translate=None)
311 338

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.