3
from django.template import Node, Variable, VariableNode, _render_value_in_context
3
from django.template import Node, Variable, VariableNode
4
4
from django.template import TemplateSyntaxError, TokenParser, Library
5
5
from django.template import TOKEN_TEXT, TOKEN_VAR
6
from django.template.base import _render_value_in_context
6
7
from django.utils import translation
7
8
from django.utils.encoding import force_unicode
9
from django.template.defaulttags import token_kwargs
9
11
register = Library()
17
19
context[self.variable] = [(k, translation.ugettext(v)) for k, v in settings.LANGUAGES]
22
class GetLanguageInfoNode(Node):
23
def __init__(self, lang_code, variable):
24
self.lang_code = Variable(lang_code)
25
self.variable = variable
27
def render(self, context):
28
lang_code = self.lang_code.resolve(context)
29
context[self.variable] = translation.get_language_info(lang_code)
32
class GetLanguageInfoListNode(Node):
33
def __init__(self, languages, variable):
34
self.languages = Variable(languages)
35
self.variable = variable
37
def get_language_info(self, language):
38
# ``language`` is either a language code string or a sequence
39
# with the language code as its first item
40
if len(language[0]) > 1:
41
return translation.get_language_info(language[0])
43
return translation.get_language_info(str(language))
45
def render(self, context):
46
langs = self.languages.resolve(context)
47
context[self.variable] = [self.get_language_info(lang) for lang in langs]
20
50
class GetCurrentLanguageNode(Node):
21
51
def __init__(self, variable):
22
52
self.variable = variable
68
98
def render(self, context):
70
100
for var, val in self.extra_context.items():
71
tmp_context[var] = val.render(context)
101
tmp_context[var] = val.resolve(context)
72
102
# Update() works like a push(), so corresponding context.pop() is at
73
103
# the end of function
74
104
context.update(tmp_context)
83
113
result = translation.ugettext(singular)
84
114
# Escape all isolated '%' before substituting in the context.
85
115
result = re.sub(u'%(?!\()', u'%%', result)
86
data = dict([(v, _render_value_in_context(context[v], context)) for v in vars])
116
data = dict([(v, _render_value_in_context(context.get(v, ''), context)) for v in vars])
88
118
return result % data
108
138
raise TemplateSyntaxError("'get_available_languages' requires 'as variable' (got %r)" % args)
109
139
return GetAvailableLanguagesNode(args[2])
141
def do_get_language_info(parser, token):
143
This will store the language information dictionary for the given language
144
code in a context variable.
148
{% get_language_info for LANGUAGE_CODE as l %}
152
{{ l.bidi|yesno:"bi-directional,uni-directional" }}
154
args = token.contents.split()
155
if len(args) != 5 or args[1] != 'for' or args[3] != 'as':
156
raise TemplateSyntaxError("'%s' requires 'for string as variable' (got %r)" % (args[0], args[1:]))
157
return GetLanguageInfoNode(args[2], args[4])
159
def do_get_language_info_list(parser, token):
161
This will store a list of language information dictionaries for the given
162
language codes in a context variable. The language codes can be specified
163
either as a list of strings or a settings.LANGUAGES style tuple (or any
164
sequence of sequences whose first items are language codes).
168
{% get_language_info_list for LANGUAGES as langs %}
173
{{ l.bidi|yesno:"bi-directional,uni-directional" }}
176
args = token.contents.split()
177
if len(args) != 5 or args[1] != 'for' or args[3] != 'as':
178
raise TemplateSyntaxError("'%s' requires 'for sequence as variable' (got %r)" % (args[0], args[1:]))
179
return GetLanguageInfoListNode(args[2], args[4])
181
def language_name(lang_code):
182
return translation.get_language_info(lang_code)['name']
184
def language_name_local(lang_code):
185
return translation.get_language_info(lang_code)['name_local']
187
def language_bidi(lang_code):
188
return translation.get_language_info(lang_code)['bidi']
111
190
def do_get_current_language(parser, token):
113
192
This will store the current language in the context.
209
{% blocktrans with foo|filter as bar and baz|filter as boo %}
288
{% blocktrans with bar=foo|filter boo=baz|filter %}
210
289
This is {{ bar }} and {{ boo }}.
211
290
{% endblocktrans %}
213
292
Additionally, this supports pluralization::
215
{% blocktrans count var|length as count %}
294
{% blocktrans count count=var|length %}
216
295
There is {{ count }} object.
218
297
There are {{ count }} objects.
219
298
{% endblocktrans %}
221
300
This is much like ngettext, only in template syntax.
302
The "var as value" legacy format is still supported::
304
{% blocktrans with foo|filter as bar and baz|filter as boo %}
305
{% blocktrans count var|length as count %}
223
class BlockTranslateParser(TokenParser):
230
if tag == 'with' or tag == 'and':
232
if self.tag() != 'as':
233
raise TemplateSyntaxError("variable bindings in 'blocktrans' must be 'with value as variable'")
234
extra_context[self.tag()] = VariableNode(
235
parser.compile_filter(value))
237
counter = parser.compile_filter(self.value())
238
if self.tag() != 'as':
239
raise TemplateSyntaxError("counter specification in 'blocktrans' must be 'count value as variable'")
240
countervar = self.tag()
242
raise TemplateSyntaxError("unknown subtag %s for 'blocktrans' found" % tag)
243
return (countervar, counter, extra_context)
245
countervar, counter, extra_context = BlockTranslateParser(token.contents).top()
307
bits = token.split_contents()
310
remaining_bits = bits[1:]
311
while remaining_bits:
312
option = remaining_bits.pop(0)
313
if option in options:
314
raise TemplateSyntaxError('The %r option was specified more '
315
'than once.' % option)
317
value = token_kwargs(remaining_bits, parser, support_legacy=True)
319
raise TemplateSyntaxError('"with" in %r tag needs at least '
320
'one keyword argument.' % bits[0])
321
elif option == 'count':
322
value = token_kwargs(remaining_bits, parser, support_legacy=True)
324
raise TemplateSyntaxError('"count" in %r tag expected exactly '
325
'one keyword argument.' % bits[0])
327
raise TemplateSyntaxError('Unknown argument for %r tag: %r.' %
329
options[option] = value
331
if 'count' in options:
332
countervar, counter = options['count'].items()[0]
334
countervar, counter = None, None
335
extra_context = options.get('with', {})
270
360
register.tag('get_available_languages', do_get_available_languages)
361
register.tag('get_language_info', do_get_language_info)
362
register.tag('get_language_info_list', do_get_language_info_list)
271
363
register.tag('get_current_language', do_get_current_language)
272
364
register.tag('get_current_language_bidi', do_get_current_language_bidi)
273
365
register.tag('trans', do_translate)
274
366
register.tag('blocktrans', do_block_translate)
368
register.filter(language_name)
369
register.filter(language_name_local)
370
register.filter(language_bidi)