Created
March 20, 2014 11:03
-
-
Save bmihelac/9661427 to your computer and use it in GitHub Desktop.
blocktrans tag with asvar option (see https://code.djangoproject.com/ticket/21695)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
from __future__ import unicode_literals | |
from django.template import (Node, Variable, TemplateSyntaxError, | |
TokenParser, Library, TOKEN_TEXT, TOKEN_VAR) | |
from django.template.base import _render_value_in_context | |
from django.template.defaulttags import token_kwargs | |
from django.utils import translation | |
register = Library() | |
class BlockTranslateNode(Node): | |
def __init__(self, extra_context, singular, plural=None, countervar=None, | |
counter=None, message_context=None, asvar=None): | |
self.extra_context = extra_context | |
self.singular = singular | |
self.plural = plural | |
self.countervar = countervar | |
self.counter = counter | |
self.message_context = message_context | |
self.asvar = asvar | |
def render_token_list(self, tokens): | |
result = [] | |
vars = [] | |
for token in tokens: | |
if token.token_type == TOKEN_TEXT: | |
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, nested=False): | |
if self.message_context: | |
message_context = self.message_context.resolve(context) | |
else: | |
message_context = None | |
tmp_context = {} | |
for var, val in self.extra_context.items(): | |
tmp_context[var] = val.resolve(context) | |
# Update() works like a push(), so corresponding context.pop() is at | |
# the end of function | |
context.update(tmp_context) | |
singular, vars = self.render_token_list(self.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) | |
if message_context: | |
result = translation.npgettext(message_context, singular, | |
plural, count) | |
else: | |
result = translation.ungettext(singular, plural, count) | |
vars.extend(plural_vars) | |
else: | |
if message_context: | |
result = translation.pgettext(message_context, singular) | |
else: | |
result = translation.ugettext(singular) | |
data = dict([(v, _render_value_in_context(context.get(v, ''), context)) for v in vars]) | |
context.pop() | |
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, nested=True) | |
if self.asvar: | |
context[self.asvar] = result | |
return '' | |
else: | |
return result | |
@register.tag("blocktrans") | |
def do_block_translate(parser, token): | |
""" | |
This will translate a block of text with parameters. | |
Usage:: | |
{% blocktrans with bar=foo|filter boo=baz|filter %} | |
This is {{ bar }} and {{ boo }}. | |
{% endblocktrans %} | |
Additionally, this supports pluralization:: | |
{% blocktrans count count=var|length %} | |
There is {{ count }} object. | |
{% plural %} | |
There are {{ count }} objects. | |
{% endblocktrans %} | |
This is much like ngettext, only in template syntax. | |
The "var as value" legacy format is still supported:: | |
{% blocktrans with foo|filter as bar and baz|filter as boo %} | |
{% blocktrans count var|length as count %} | |
Contextual translations are supported:: | |
{% blocktrans with bar=foo|filter context "greeting" %} | |
This is {{ bar }}. | |
{% endblocktrans %} | |
It is possible to store the translated string into a variable:: | |
{% blocktrans with bar=foo|filter boo=baz|filter asvar var %} | |
This is {{ bar }} and {{ boo }}. | |
{% endblocktrans %} | |
{{ var }} | |
This is equivalent to calling pgettext/npgettext instead of | |
(u)gettext/(u)ngettext. | |
""" | |
bits = token.split_contents() | |
options = {} | |
remaining_bits = bits[1:] | |
asvar = None | |
if len(remaining_bits) >= 2 and remaining_bits[-2] == "asvar": | |
asvar = remaining_bits.pop() | |
remaining_bits.pop() | |
while remaining_bits: | |
option = remaining_bits.pop(0) | |
if option in options: | |
raise TemplateSyntaxError('The %r option was specified more ' | |
'than once.' % option) | |
if option == 'with': | |
value = token_kwargs(remaining_bits, parser, support_legacy=True) | |
if not value: | |
raise TemplateSyntaxError('"with" in %r tag needs at least ' | |
'one keyword argument.' % bits[0]) | |
elif option == 'count': | |
value = token_kwargs(remaining_bits, parser, support_legacy=True) | |
if len(value) != 1: | |
raise TemplateSyntaxError('"count" in %r tag expected exactly ' | |
'one keyword argument.' % bits[0]) | |
elif option == "context": | |
try: | |
value = remaining_bits.pop(0) | |
value = parser.compile_filter(value) | |
except Exception: | |
raise TemplateSyntaxError('"context" in %r tag expected ' | |
'exactly one argument.' % bits[0]) | |
else: | |
raise TemplateSyntaxError('Unknown argument for %r tag: %r.' % | |
(bits[0], option)) | |
options[option] = value | |
if 'count' in options: | |
countervar, counter = list(six.iteritems(options['count']))[0] | |
else: | |
countervar, counter = None, None | |
if 'context' in options: | |
message_context = options['context'] | |
else: | |
message_context = None | |
extra_context = options.get('with', {}) | |
singular = [] | |
plural = [] | |
while parser.tokens: | |
token = parser.next_token() | |
if token.token_type in (TOKEN_VAR, TOKEN_TEXT): | |
singular.append(token) | |
else: | |
break | |
if countervar and counter: | |
if token.contents.strip() != 'plural': | |
raise TemplateSyntaxError("'blocktrans' doesn't allow other block tags inside it") | |
while parser.tokens: | |
token = parser.next_token() | |
if token.token_type in (TOKEN_VAR, TOKEN_TEXT): | |
plural.append(token) | |
else: | |
break | |
if token.contents.strip() != 'endblocktrans': | |
raise TemplateSyntaxError("'blocktrans' doesn't allow other block tags (seen %r) inside it" % token.contents) | |
return BlockTranslateNode(extra_context, singular, plural, countervar, | |
counter, message_context, asvar) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% load blocktrans_as_tag %} | |
{% blocktrans with year=2013 asvar title %}News archive for {{year}}{% endblocktrans %} | |
{{ title }} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment