Fixed #19088 -- Always escape % inside blocktrans tag

Thanks vlinhart for the report and Łukasz Rekucki for the patch.
This commit is contained in:
Claude Paroz 2012-10-23 18:48:24 +02:00
parent 3541a10d49
commit 9fd2f9c5f3
2 changed files with 21 additions and 8 deletions

View File

@ -110,13 +110,13 @@ class BlockTranslateNode(Node):
vars = [] vars = []
for token in tokens: for token in tokens:
if token.token_type == TOKEN_TEXT: if token.token_type == TOKEN_TEXT:
result.append(token.contents) result.append(token.contents.replace('%', '%%'))
elif token.token_type == TOKEN_VAR: elif token.token_type == TOKEN_VAR:
result.append('%%(%s)s' % token.contents) result.append('%%(%s)s' % token.contents)
vars.append(token.contents) vars.append(token.contents)
return ''.join(result), vars return ''.join(result), vars
def render(self, context): def render(self, context, nested=False):
if self.message_context: if self.message_context:
message_context = self.message_context.resolve(context) message_context = self.message_context.resolve(context)
else: else:
@ -128,13 +128,10 @@ class BlockTranslateNode(Node):
# the end of function # the end of function
context.update(tmp_context) context.update(tmp_context)
singular, vars = self.render_token_list(self.singular) singular, vars = self.render_token_list(self.singular)
# Escape all isolated '%'
singular = re.sub('%(?!\()', '%%', singular)
if self.plural and self.countervar and self.counter: if self.plural and self.countervar and self.counter:
count = self.counter.resolve(context) count = self.counter.resolve(context)
context[self.countervar] = count context[self.countervar] = count
plural, plural_vars = self.render_token_list(self.plural) plural, plural_vars = self.render_token_list(self.plural)
plural = re.sub('%(?!\()', '%%', plural)
if message_context: if message_context:
result = translation.npgettext(message_context, singular, result = translation.npgettext(message_context, singular,
plural, count) plural, count)
@ -151,8 +148,12 @@ class BlockTranslateNode(Node):
try: try:
result = result % data result = result % data
except (KeyError, ValueError): 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): with translation.override(None):
result = self.render(context) result = self.render(context, nested=True)
return result return result

View File

@ -269,7 +269,6 @@ class TranslationTests(TestCase):
(%(person)s is translated as %(personne)s in fr.po) (%(person)s is translated as %(personne)s in fr.po)
Refs #16516. Refs #16516.
""" """
from django.template import Template, Context
with translation.override('fr'): with translation.override('fr'):
t = Template('{% load i18n %}{% blocktrans %}My name is {{ person }}.{% endblocktrans %}') t = Template('{% load i18n %}{% blocktrans %}My name is {{ person }}.{% endblocktrans %}')
rendered = t.render(Context({'person': 'James'})) 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) (%(person) misses a 's' in fr.po, causing the string formatting to fail)
Refs #18393. Refs #18393.
""" """
from django.template import Template, Context
with translation.override('fr'): with translation.override('fr'):
t = Template('{% load i18n %}{% blocktrans %}My other name is {{ person }}.{% endblocktrans %}') t = Template('{% load i18n %}{% blocktrans %}My other name is {{ person }}.{% endblocktrans %}')
rendered = t.render(Context({'person': 'James'})) 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': 1})), '42% stellt 1 Objekt dar')
self.assertEqual(t_plur.render(Context({'percent': 42, 'num': 4})), '42% stellt 4 Objekte 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): class ResolutionOrderI18NTests(TestCase):