Fixed a few problems with variable resolving inside of blocktrans tags. A couple of these were exposed by the auto-escaping changes, but I suspect the other one has been hiding in plain sight for a while.
Fixed #5952, #5953 git-svn-id: http://code.djangoproject.com/svn/django/trunk@6682 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
64c0bf8677
commit
adcec0885d
|
@ -1,9 +1,10 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.template import Node, Variable
|
from django.template import Node, Variable, VariableNode
|
||||||
from django.template import TemplateSyntaxError, TokenParser, Library
|
from django.template import TemplateSyntaxError, TokenParser, Library
|
||||||
from django.template import TOKEN_TEXT, TOKEN_VAR
|
from django.template import TOKEN_TEXT, TOKEN_VAR
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
|
@ -45,7 +46,8 @@ class TranslateNode(Node):
|
||||||
return translation.ugettext(value)
|
return translation.ugettext(value)
|
||||||
|
|
||||||
class BlockTranslateNode(Node):
|
class BlockTranslateNode(Node):
|
||||||
def __init__(self, extra_context, singular, plural=None, countervar=None, counter=None):
|
def __init__(self, extra_context, singular, plural=None, countervar=None,
|
||||||
|
counter=None):
|
||||||
self.extra_context = extra_context
|
self.extra_context = extra_context
|
||||||
self.singular = singular
|
self.singular = singular
|
||||||
self.plural = plural
|
self.plural = plural
|
||||||
|
@ -54,29 +56,32 @@ class BlockTranslateNode(Node):
|
||||||
|
|
||||||
def render_token_list(self, tokens):
|
def render_token_list(self, tokens):
|
||||||
result = []
|
result = []
|
||||||
|
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)
|
||||||
elif token.token_type == TOKEN_VAR:
|
elif token.token_type == TOKEN_VAR:
|
||||||
result.append('%%(%s)s' % token.contents)
|
result.append(u'%%(%s)s' % token.contents)
|
||||||
return ''.join(result)
|
vars.append(token.contents)
|
||||||
|
return ''.join(result), vars
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
context.push()
|
context.push()
|
||||||
for var,val in self.extra_context.items():
|
for var, val in self.extra_context.items():
|
||||||
context[var] = val.resolve(context)
|
context[var] = val.render(context)
|
||||||
singular = self.render_token_list(self.singular)
|
singular, vars = self.render_token_list(self.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 = self.render_token_list(self.plural)
|
plural = self.render_token_list(self.plural)[0]
|
||||||
result = translation.ungettext(singular, plural, count)
|
result = translation.ungettext(singular, plural, count)
|
||||||
else:
|
else:
|
||||||
result = translation.ugettext(singular)
|
result = translation.ugettext(singular)
|
||||||
# Escape all isolated '%' before substituting in the context.
|
# Escape all isolated '%' before substituting in the context.
|
||||||
result = re.sub('%(?!\()', '%%', result) % context
|
result = re.sub(u'%(?!\()', u'%%', result)
|
||||||
|
data = dict([(v, force_unicode(context[v])) for v in vars])
|
||||||
context.pop()
|
context.pop()
|
||||||
return result
|
return result % data
|
||||||
|
|
||||||
def do_get_available_languages(parser, token):
|
def do_get_available_languages(parser, token):
|
||||||
"""
|
"""
|
||||||
|
@ -198,7 +203,6 @@ def do_block_translate(parser, token):
|
||||||
This is much like ngettext, only in template syntax.
|
This is much like ngettext, only in template syntax.
|
||||||
"""
|
"""
|
||||||
class BlockTranslateParser(TokenParser):
|
class BlockTranslateParser(TokenParser):
|
||||||
|
|
||||||
def top(self):
|
def top(self):
|
||||||
countervar = None
|
countervar = None
|
||||||
counter = None
|
counter = None
|
||||||
|
@ -209,7 +213,8 @@ def do_block_translate(parser, token):
|
||||||
value = self.value()
|
value = self.value()
|
||||||
if self.tag() != 'as':
|
if self.tag() != 'as':
|
||||||
raise TemplateSyntaxError, "variable bindings in 'blocktrans' must be 'with value as variable'"
|
raise TemplateSyntaxError, "variable bindings in 'blocktrans' must be 'with value as variable'"
|
||||||
extra_context[self.tag()] = parser.compile_filter(value)
|
extra_context[self.tag()] = VariableNode(
|
||||||
|
parser.compile_filter(value))
|
||||||
elif tag == 'count':
|
elif tag == 'count':
|
||||||
counter = parser.compile_filter(self.value())
|
counter = parser.compile_filter(self.value())
|
||||||
if self.tag() != 'as':
|
if self.tag() != 'as':
|
||||||
|
@ -241,7 +246,8 @@ def do_block_translate(parser, token):
|
||||||
if token.contents.strip() != 'endblocktrans':
|
if token.contents.strip() != 'endblocktrans':
|
||||||
raise TemplateSyntaxError, "'blocktrans' doesn't allow other block tags (seen %r) inside it" % token.contents
|
raise TemplateSyntaxError, "'blocktrans' doesn't allow other block tags (seen %r) inside it" % token.contents
|
||||||
|
|
||||||
return BlockTranslateNode(extra_context, singular, plural, countervar, counter)
|
return BlockTranslateNode(extra_context, singular, plural, countervar,
|
||||||
|
counter)
|
||||||
|
|
||||||
register.tag('get_available_languages', do_get_available_languages)
|
register.tag('get_available_languages', do_get_available_languages)
|
||||||
register.tag('get_current_language', do_get_current_language)
|
register.tag('get_current_language', do_get_current_language)
|
||||||
|
|
|
@ -705,10 +705,10 @@ class Templates(unittest.TestCase):
|
||||||
'i18n02': ('{% load i18n %}{% trans "xxxyyyxxx" %}', {}, "xxxyyyxxx"),
|
'i18n02': ('{% load i18n %}{% trans "xxxyyyxxx" %}', {}, "xxxyyyxxx"),
|
||||||
|
|
||||||
# simple translation of a variable
|
# simple translation of a variable
|
||||||
'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': 'xxxyyyxxx'}, "xxxyyyxxx"),
|
'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': '\xc3\x85'}, u"Å"),
|
||||||
|
|
||||||
# simple translation of a variable and filter
|
# simple translation of a variable and filter
|
||||||
'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'XXXYYYXXX'}, "xxxyyyxxx"),
|
'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': '\xc3\x85'}, u'å'),
|
||||||
|
|
||||||
# simple translation of a string with interpolation
|
# simple translation of a string with interpolation
|
||||||
'i18n05': ('{% load i18n %}{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}', {'anton': 'yyy'}, "xxxyyyxxx"),
|
'i18n05': ('{% load i18n %}{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}', {'anton': 'yyy'}, "xxxyyyxxx"),
|
||||||
|
@ -740,6 +740,11 @@ class Templates(unittest.TestCase):
|
||||||
'i18n15': ('{{ absent|default:_("Password") }}', {'LANGUAGE_CODE': 'de', 'absent': ""}, 'Passwort'),
|
'i18n15': ('{{ absent|default:_("Password") }}', {'LANGUAGE_CODE': 'de', 'absent': ""}, 'Passwort'),
|
||||||
'i18n16': ('{{ _("<") }}', {'LANGUAGE_CODE': 'de'}, '<'),
|
'i18n16': ('{{ _("<") }}', {'LANGUAGE_CODE': 'de'}, '<'),
|
||||||
|
|
||||||
|
# Escaping inside blocktrans works as if it was directly in the
|
||||||
|
# template.
|
||||||
|
'i18n17': ('{% load i18n %}{% blocktrans with anton|escape as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'α & β'}, u'α & β'),
|
||||||
|
'i18n18': ('{% load i18n %}{% blocktrans with anton|force_escape as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'α & β'}, u'α & β'),
|
||||||
|
|
||||||
### HANDLING OF TEMPLATE_STRING_IF_INVALID ###################################
|
### HANDLING OF TEMPLATE_STRING_IF_INVALID ###################################
|
||||||
|
|
||||||
'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')),
|
'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')),
|
||||||
|
|
Loading…
Reference in New Issue