Fixed #19088 -- Always escape % inside blocktrans tag
Thanks vlinhart for the report and Łukasz Rekucki for the patch.
This commit is contained in:
parent
3541a10d49
commit
9fd2f9c5f3
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue