3 from django
.template
import Node
, Variable
, VariableNode
4 from django
.template
import TemplateSyntaxError
, TokenParser
, Library
5 from django
.template
import TOKEN_TEXT
, TOKEN_VAR
6 from django
.utils
import translation
7 from django
.utils
.encoding
import force_unicode
11 class GetAvailableLanguagesNode(Node
):
12 def __init__(self
, variable
):
13 self
.variable
= variable
15 def render(self
, context
):
16 from django
.conf
import settings
17 context
[self
.variable
] = [(k
, translation
.ugettext(v
)) for k
, v
in settings
.LANGUAGES
]
20 class GetCurrentLanguageNode(Node
):
21 def __init__(self
, variable
):
22 self
.variable
= variable
24 def render(self
, context
):
25 context
[self
.variable
] = translation
.get_language()
28 class GetCurrentLanguageBidiNode(Node
):
29 def __init__(self
, variable
):
30 self
.variable
= variable
32 def render(self
, context
):
33 context
[self
.variable
] = translation
.get_language_bidi()
36 class TranslateNode(Node
):
37 def __init__(self
, value
, noop
):
38 self
.value
= Variable(value
)
41 def render(self
, context
):
42 value
= self
.value
.resolve(context
)
46 return translation
.ugettext(value
)
48 class BlockTranslateNode(Node
):
49 def __init__(self
, extra_context
, singular
, plural
=None, countervar
=None,
51 self
.extra_context
= extra_context
52 self
.singular
= singular
54 self
.countervar
= countervar
55 self
.counter
= counter
57 def render_token_list(self
, tokens
):
61 if token
.token_type
== TOKEN_TEXT
:
62 result
.append(token
.contents
)
63 elif token
.token_type
== TOKEN_VAR
:
64 result
.append(u
'%%(%s)s' % token
.contents
)
65 vars.append(token
.contents
)
66 return ''.join(result
), vars
68 def render(self
, context
):
70 for var
, val
in self
.extra_context
.items():
71 tmp_context
[var
] = val
.render(context
)
72 # Update() works like a push(), so corresponding context.pop() is at
74 context
.update(tmp_context
)
75 singular
, vars = self
.render_token_list(self
.singular
)
76 if self
.plural
and self
.countervar
and self
.counter
:
77 count
= self
.counter
.resolve(context
)
78 context
[self
.countervar
] = count
79 plural
, vars = self
.render_token_list(self
.plural
)
80 result
= translation
.ungettext(singular
, plural
, count
)
82 result
= translation
.ugettext(singular
)
83 # Escape all isolated '%' before substituting in the context.
84 result
= re
.sub(u
'%(?!\()', u
'%%', result
)
85 data
= dict([(v
, force_unicode(context
[v
])) for v
in vars])
89 def do_get_available_languages(parser
, token
):
91 This will store a list of available languages
96 {% get_available_languages as languages %}
97 {% for language in languages %}
101 This will just pull the LANGUAGES setting from
102 your setting file (or the default settings) and
103 put it into the named variable.
105 args
= token
.contents
.split()
106 if len(args
) != 3 or args
[1] != 'as':
107 raise TemplateSyntaxError
, "'get_available_languages' requires 'as variable' (got %r)" % args
108 return GetAvailableLanguagesNode(args
[2])
110 def do_get_current_language(parser
, token
):
112 This will store the current language in the context.
116 {% get_current_language as language %}
118 This will fetch the currently active language and
119 put it's value into the ``language`` context
122 args
= token
.contents
.split()
123 if len(args
) != 3 or args
[1] != 'as':
124 raise TemplateSyntaxError
, "'get_current_language' requires 'as variable' (got %r)" % args
125 return GetCurrentLanguageNode(args
[2])
127 def do_get_current_language_bidi(parser
, token
):
129 This will store the current language layout in the context.
133 {% get_current_language_bidi as bidi %}
135 This will fetch the currently active language's layout and
136 put it's value into the ``bidi`` context variable.
137 True indicates right-to-left layout, otherwise left-to-right
139 args
= token
.contents
.split()
140 if len(args
) != 3 or args
[1] != 'as':
141 raise TemplateSyntaxError
, "'get_current_language_bidi' requires 'as variable' (got %r)" % args
142 return GetCurrentLanguageBidiNode(args
[2])
144 def do_translate(parser
, token
):
146 This will mark a string for translation and will
147 translate the string for the current language.
151 {% trans "this is a test" %}
153 This will mark the string for translation so it will
154 be pulled out by mark-messages.py into the .po files
155 and will run the string through the translation engine.
157 There is a second form::
159 {% trans "this is a test" noop %}
161 This will only mark for translation, but will return
162 the string unchanged. Use it when you need to store
163 values into forms that should be translated later on.
165 You can use variables instead of constant strings
166 to translate stuff you marked somewhere else::
170 This will just try to translate the contents of
171 the variable ``variable``. Make sure that the string
172 in there is something that is in the .po file.
174 class TranslateParser(TokenParser
):
178 if self
.tag() == 'noop':
181 raise TemplateSyntaxError
, "only option for 'trans' is 'noop'"
185 value
, noop
= TranslateParser(token
.contents
).top()
186 return TranslateNode(value
, noop
)
188 def do_block_translate(parser
, token
):
190 This will translate a block of text with parameters.
194 {% blocktrans with foo|filter as bar and baz|filter as boo %}
195 This is {{ bar }} and {{ boo }}.
198 Additionally, this supports pluralization::
200 {% blocktrans count var|length as count %}
201 There is {{ count }} object.
203 There are {{ count }} objects.
206 This is much like ngettext, only in template syntax.
208 class BlockTranslateParser(TokenParser
):
215 if tag
== 'with' or tag
== 'and':
217 if self
.tag() != 'as':
218 raise TemplateSyntaxError
, "variable bindings in 'blocktrans' must be 'with value as variable'"
219 extra_context
[self
.tag()] = VariableNode(
220 parser
.compile_filter(value
))
222 counter
= parser
.compile_filter(self
.value())
223 if self
.tag() != 'as':
224 raise TemplateSyntaxError
, "counter specification in 'blocktrans' must be 'count value as variable'"
225 countervar
= self
.tag()
227 raise TemplateSyntaxError
, "unknown subtag %s for 'blocktrans' found" % tag
228 return (countervar
, counter
, extra_context
)
230 countervar
, counter
, extra_context
= BlockTranslateParser(token
.contents
).top()
235 token
= parser
.next_token()
236 if token
.token_type
in (TOKEN_VAR
, TOKEN_TEXT
):
237 singular
.append(token
)
240 if countervar
and counter
:
241 if token
.contents
.strip() != 'plural':
242 raise TemplateSyntaxError
, "'blocktrans' doesn't allow other block tags inside it"
244 token
= parser
.next_token()
245 if token
.token_type
in (TOKEN_VAR
, TOKEN_TEXT
):
249 if token
.contents
.strip() != 'endblocktrans':
250 raise TemplateSyntaxError
, "'blocktrans' doesn't allow other block tags (seen %r) inside it" % token
.contents
252 return BlockTranslateNode(extra_context
, singular
, plural
, countervar
,
255 register
.tag('get_available_languages', do_get_available_languages
)
256 register
.tag('get_current_language', do_get_current_language
)
257 register
.tag('get_current_language_bidi', do_get_current_language_bidi
)
258 register
.tag('trans', do_translate
)
259 register
.tag('blocktrans', do_block_translate
)