summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2012-10-23 18:48:24 +0200
committerClaude Paroz <claude@2xlibre.net>2012-10-23 18:49:22 +0200
commit9fd2f9c5f3c008f524874fd7cf78237e65bf567e (patch)
tree048a0b9dcb02dad13751ab788c7c2b9d5491f8b0
parent3541a10d492db6d1f509f3a50a024568c16c5229 (diff)
Fixed #19088 -- Always escape % inside blocktrans tag
Thanks vlinhart for the report and Ɓukasz Rekucki for the patch.
-rw-r--r--django/templatetags/i18n.py13
-rw-r--r--tests/regressiontests/i18n/tests.py16
2 files changed, 21 insertions, 8 deletions
diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py
index 30eb6b5f76..5576beb4a3 100644
--- a/django/templatetags/i18n.py
+++ b/django/templatetags/i18n.py
@@ -110,13 +110,13 @@ class BlockTranslateNode(Node):
vars = []
for token in tokens:
if token.token_type == TOKEN_TEXT:
- result.append(token.contents)
+ result.append(token.contents.replace('%', '%%'))
elif token.token_type == TOKEN_VAR:
result.append('%%(%s)s' % token.contents)
vars.append(token.contents)
return ''.join(result), vars
- def render(self, context):
+ def render(self, context, nested=False):
if self.message_context:
message_context = self.message_context.resolve(context)
else:
@@ -128,13 +128,10 @@ class BlockTranslateNode(Node):
# the end of function
context.update(tmp_context)
singular, vars = self.render_token_list(self.singular)
- # Escape all isolated '%'
- singular = re.sub('%(?!\()', '%%', singular)
if self.plural and self.countervar and self.counter:
count = self.counter.resolve(context)
context[self.countervar] = count
plural, plural_vars = self.render_token_list(self.plural)
- plural = re.sub('%(?!\()', '%%', plural)
if message_context:
result = translation.npgettext(message_context, singular,
plural, count)
@@ -151,8 +148,12 @@ class BlockTranslateNode(Node):
try:
result = result % data
except (KeyError, ValueError):
+ if nested:
+ # Either string is malformed, or it's a bug
+ raise TemplateSyntaxError("'blocktrans' is unable to format "
+ "string returned by gettext: %r using %r" % (result, data))
with translation.override(None):
- result = self.render(context)
+ result = self.render(context, nested=True)
return result
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index 1346383f3d..4054f85ef0 100644
--- a/tests/regressiontests/i18n/tests.py
+++ b/tests/regressiontests/i18n/tests.py
@@ -269,7 +269,6 @@ class TranslationTests(TestCase):
(%(person)s is translated as %(personne)s in fr.po)
Refs #16516.
"""
- from django.template import Template, Context
with translation.override('fr'):
t = Template('{% load i18n %}{% blocktrans %}My name is {{ person }}.{% endblocktrans %}')
rendered = t.render(Context({'person': 'James'}))
@@ -282,7 +281,6 @@ class TranslationTests(TestCase):
(%(person) misses a 's' in fr.po, causing the string formatting to fail)
Refs #18393.
"""
- from django.template import Template, Context
with translation.override('fr'):
t = Template('{% load i18n %}{% blocktrans %}My other name is {{ person }}.{% endblocktrans %}')
rendered = t.render(Context({'person': 'James'}))
@@ -821,6 +819,20 @@ class MiscTests(TestCase):
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 1})), '42% stellt 1 Objekt dar')
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 4})), '42% stellt 4 Objekte dar')
+ @override_settings(LOCALE_PATHS=extended_locale_paths)
+ def test_percent_formatting_in_blocktrans(self):
+ """
+ Test that using Python's %-formatting is properly escaped in blocktrans,
+ singular or plural
+ """
+ t_sing = Template("{% load i18n %}{% blocktrans %}There are %(num_comments)s comments{% endblocktrans %}")
+ t_plur = Template("{% load i18n %}{% blocktrans count num as number %}%(percent)s% represents {{ num }} object{% plural %}%(percent)s% represents {{ num }} objects{% endblocktrans %}")
+ with translation.override('de'):
+ # Strings won't get translated as they don't match after escaping %
+ self.assertEqual(t_sing.render(Context({'num_comments': 42})), 'There are %(num_comments)s comments')
+ self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 1})), '%(percent)s% represents 1 object')
+ self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 4})), '%(percent)s% represents 4 objects')
+
class ResolutionOrderI18NTests(TestCase):