blob: 1b19321e08b83b151adfe702e72846216ff395bc [file] [log] [blame]
# -*- coding: utf-8 -*-
"""
jinja2.i18n
~~~~~~~~~~~
i18n support for Jinja.
:copyright: Copyright 2008 by Armin Ronacher.
:license: BSD.
"""
from jinja2 import nodes
from jinja2.parser import _statement_end_tokens
from jinja2.exceptions import TemplateAssertionError
def parse_trans(parser):
"""Parse a translatable tag."""
lineno = parser.stream.expect('trans').lineno
# skip colon for python compatibility
if parser.stream.current.type is 'colon':
parser.stream.next()
# find all the variables referenced. Additionally a variable can be
# defined in the body of the trans block too, but this is checked at
# a later state.
plural_expr = None
variables = {}
while parser.stream.current.type is not 'block_end':
if variables:
parser.stream.expect('comma')
name = parser.stream.expect('name')
if name.value in variables:
raise TemplateAssertionError('translatable variable %r defined '
'twice.' % name.value, name.lineno,
parser.filename)
# expressions
if parser.stream.current.type is 'assign':
parser.stream.next()
variables[name.value] = var = parser.parse_expression()
else:
variables[name.value] = var = nodes.Name(name.value, 'load')
if plural_expr is None:
plural_expr = var
parser.stream.expect('block_end')
plural = plural_names = None
have_plural = False
referenced = set()
# now parse until endtrans or pluralize
singular_names, singular = _parse_block(parser, True)
if singular_names:
referenced.update(singular_names)
if plural_expr is None:
plural_expr = nodes.Name(singular_names[0], 'load')
# if we have a pluralize block, we parse that too
if parser.stream.current.type is 'pluralize':
have_plural = True
parser.stream.next()
if parser.stream.current.type is not 'block_end':
plural_expr = parser.parse_expression()
parser.stream.expect('block_end')
plural_names, plural = _parse_block(parser, False)
parser.stream.next()
referenced.update(plural_names)
else:
parser.stream.next()
parser.end_statement()
# register free names as simple name expressions
for var in referenced:
if var not in variables:
variables[var] = nodes.Name(var, 'load')
# no variables referenced? no need to escape
if not referenced:
singular = singular.replace('%%', '%')
if plural:
plural = plural.replace('%%', '%')
if not have_plural:
if plural_expr is None:
raise TemplateAssertionError('pluralize without variables',
lineno, parser.filename)
plural_expr = None
if variables:
variables = nodes.Dict([nodes.Pair(nodes.Const(x, lineno=lineno), y)
for x, y in variables.items()])
else:
vairables = None
node = _make_node(singular, plural, variables, plural_expr)
node.set_lineno(lineno)
return node
def _parse_block(parser, allow_pluralize):
"""Parse until the next block tag with a given name."""
referenced = []
buf = []
while 1:
if parser.stream.current.type is 'data':
buf.append(parser.stream.current.value.replace('%', '%%'))
parser.stream.next()
elif parser.stream.current.type is 'variable_begin':
parser.stream.next()
referenced.append(parser.stream.expect('name').value)
buf.append('%s')
parser.stream.expect('variable_end')
elif parser.stream.current.type is 'block_begin':
parser.stream.next()
if parser.stream.current.type is 'endtrans':
break
elif parser.stream.current.type is 'pluralize':
if allow_pluralize:
break
raise TemplateSyntaxError('a translatable section can have '
'only one pluralize section',
parser.stream.current.lineno,
parser.filename)
raise TemplateSyntaxError('control structures in translatable '
'sections are not allowed.',
parser.stream.current.lineno,
parser.filename)
else:
assert False, 'internal parser error'
return referenced, u''.join(buf)
def _make_node(singular, plural, variables, plural_expr):
"""Generates a useful node from the data provided."""
# singular only:
if plural_expr is None:
gettext = nodes.Name('gettext', 'load')
node = nodes.Call(gettext, [nodes.Const(singular)],
[], None, None)
if variables:
node = nodes.Mod(node, variables)
# singular and plural
else:
ngettext = nodes.Name('ngettext', 'load')
node = nodes.Call(ngettext, [
nodes.Const(singular),
nodes.Const(plural),
plural_expr
], [], None, None)
if variables:
node = nodes.Mod(node, variables)
return nodes.Output([node])