--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/django/templatetags/i18n.py Fri Jul 18 18:22:23 2008 +0000
@@ -0,0 +1,259 @@
+import re
+
+from django.template import Node, Variable, VariableNode
+from django.template import TemplateSyntaxError, TokenParser, Library
+from django.template import TOKEN_TEXT, TOKEN_VAR
+from django.utils import translation
+from django.utils.encoding import force_unicode
+
+register = Library()
+
+class GetAvailableLanguagesNode(Node):
+ def __init__(self, variable):
+ self.variable = variable
+
+ def render(self, context):
+ from django.conf import settings
+ context[self.variable] = [(k, translation.ugettext(v)) for k, v in settings.LANGUAGES]
+ return ''
+
+class GetCurrentLanguageNode(Node):
+ def __init__(self, variable):
+ self.variable = variable
+
+ def render(self, context):
+ context[self.variable] = translation.get_language()
+ return ''
+
+class GetCurrentLanguageBidiNode(Node):
+ def __init__(self, variable):
+ self.variable = variable
+
+ def render(self, context):
+ context[self.variable] = translation.get_language_bidi()
+ return ''
+
+class TranslateNode(Node):
+ def __init__(self, value, noop):
+ self.value = Variable(value)
+ self.noop = noop
+
+ def render(self, context):
+ value = self.value.resolve(context)
+ if self.noop:
+ return value
+ else:
+ return translation.ugettext(value)
+
+class BlockTranslateNode(Node):
+ def __init__(self, extra_context, singular, plural=None, countervar=None,
+ counter=None):
+ self.extra_context = extra_context
+ self.singular = singular
+ self.plural = plural
+ self.countervar = countervar
+ self.counter = counter
+
+ def render_token_list(self, tokens):
+ result = []
+ vars = []
+ for token in tokens:
+ if token.token_type == TOKEN_TEXT:
+ result.append(token.contents)
+ elif token.token_type == TOKEN_VAR:
+ result.append(u'%%(%s)s' % token.contents)
+ vars.append(token.contents)
+ return ''.join(result), vars
+
+ def render(self, context):
+ tmp_context = {}
+ for var, val in self.extra_context.items():
+ tmp_context[var] = val.render(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, vars = self.render_token_list(self.plural)
+ result = translation.ungettext(singular, plural, count)
+ else:
+ result = translation.ugettext(singular)
+ # Escape all isolated '%' before substituting in the context.
+ result = re.sub(u'%(?!\()', u'%%', result)
+ data = dict([(v, force_unicode(context[v])) for v in vars])
+ context.pop()
+ return result % data
+
+def do_get_available_languages(parser, token):
+ """
+ This will store a list of available languages
+ in the context.
+
+ Usage::
+
+ {% get_available_languages as languages %}
+ {% for language in languages %}
+ ...
+ {% endfor %}
+
+ This will just pull the LANGUAGES setting from
+ your setting file (or the default settings) and
+ put it into the named variable.
+ """
+ args = token.contents.split()
+ if len(args) != 3 or args[1] != 'as':
+ raise TemplateSyntaxError, "'get_available_languages' requires 'as variable' (got %r)" % args
+ return GetAvailableLanguagesNode(args[2])
+
+def do_get_current_language(parser, token):
+ """
+ This will store the current language in the context.
+
+ Usage::
+
+ {% get_current_language as language %}
+
+ This will fetch the currently active language and
+ put it's value into the ``language`` context
+ variable.
+ """
+ args = token.contents.split()
+ if len(args) != 3 or args[1] != 'as':
+ raise TemplateSyntaxError, "'get_current_language' requires 'as variable' (got %r)" % args
+ return GetCurrentLanguageNode(args[2])
+
+def do_get_current_language_bidi(parser, token):
+ """
+ This will store the current language layout in the context.
+
+ Usage::
+
+ {% get_current_language_bidi as bidi %}
+
+ This will fetch the currently active language's layout and
+ put it's value into the ``bidi`` context variable.
+ True indicates right-to-left layout, otherwise left-to-right
+ """
+ args = token.contents.split()
+ if len(args) != 3 or args[1] != 'as':
+ raise TemplateSyntaxError, "'get_current_language_bidi' requires 'as variable' (got %r)" % args
+ return GetCurrentLanguageBidiNode(args[2])
+
+def do_translate(parser, token):
+ """
+ This will mark a string for translation and will
+ translate the string for the current language.
+
+ Usage::
+
+ {% trans "this is a test" %}
+
+ This will mark the string for translation so it will
+ be pulled out by mark-messages.py into the .po files
+ and will run the string through the translation engine.
+
+ There is a second form::
+
+ {% trans "this is a test" noop %}
+
+ This will only mark for translation, but will return
+ the string unchanged. Use it when you need to store
+ values into forms that should be translated later on.
+
+ You can use variables instead of constant strings
+ to translate stuff you marked somewhere else::
+
+ {% trans variable %}
+
+ This will just try to translate the contents of
+ the variable ``variable``. Make sure that the string
+ in there is something that is in the .po file.
+ """
+ class TranslateParser(TokenParser):
+ def top(self):
+ value = self.value()
+ if self.more():
+ if self.tag() == 'noop':
+ noop = True
+ else:
+ raise TemplateSyntaxError, "only option for 'trans' is 'noop'"
+ else:
+ noop = False
+ return (value, noop)
+ value, noop = TranslateParser(token.contents).top()
+ return TranslateNode(value, noop)
+
+def do_block_translate(parser, token):
+ """
+ This will translate a block of text with parameters.
+
+ Usage::
+
+ {% blocktrans with foo|filter as bar and baz|filter as boo %}
+ This is {{ bar }} and {{ boo }}.
+ {% endblocktrans %}
+
+ Additionally, this supports pluralization::
+
+ {% blocktrans count var|length as count %}
+ There is {{ count }} object.
+ {% plural %}
+ There are {{ count }} objects.
+ {% endblocktrans %}
+
+ This is much like ngettext, only in template syntax.
+ """
+ class BlockTranslateParser(TokenParser):
+ def top(self):
+ countervar = None
+ counter = None
+ extra_context = {}
+ while self.more():
+ tag = self.tag()
+ if tag == 'with' or tag == 'and':
+ value = self.value()
+ if self.tag() != 'as':
+ raise TemplateSyntaxError, "variable bindings in 'blocktrans' must be 'with value as variable'"
+ extra_context[self.tag()] = VariableNode(
+ parser.compile_filter(value))
+ elif tag == 'count':
+ counter = parser.compile_filter(self.value())
+ if self.tag() != 'as':
+ raise TemplateSyntaxError, "counter specification in 'blocktrans' must be 'count value as variable'"
+ countervar = self.tag()
+ else:
+ raise TemplateSyntaxError, "unknown subtag %s for 'blocktrans' found" % tag
+ return (countervar, counter, extra_context)
+
+ countervar, counter, extra_context = BlockTranslateParser(token.contents).top()
+
+ 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)
+
+register.tag('get_available_languages', do_get_available_languages)
+register.tag('get_current_language', do_get_current_language)
+register.tag('get_current_language_bidi', do_get_current_language_bidi)
+register.tag('trans', do_translate)
+register.tag('blocktrans', do_block_translate)