import re from jinja2.exceptions import TemplateSyntaxError from jinja2.ext import Extension from jinja2.lexer import count_newlines from jinja2.lexer import Token _outside_re = re.compile(r"\\?(gettext|_)\(") _inside_re = re.compile(r"\\?[()]") class InlineGettext(Extension): """This extension implements support for inline gettext blocks::

_(Welcome)

_(This is a paragraph)

Requires the i18n extension to be loaded and configured. """ def filter_stream(self, stream): paren_stack = 0 for token in stream: if token.type != "data": yield token continue pos = 0 lineno = token.lineno while True: if not paren_stack: match = _outside_re.search(token.value, pos) else: match = _inside_re.search(token.value, pos) if match is None: break new_pos = match.start() if new_pos > pos: preval = token.value[pos:new_pos] yield Token(lineno, "data", preval) lineno += count_newlines(preval) gtok = match.group() if gtok[0] == "\\": yield Token(lineno, "data", gtok[1:]) elif not paren_stack: yield Token(lineno, "block_begin", None) yield Token(lineno, "name", "trans") yield Token(lineno, "block_end", None) paren_stack = 1 else: if gtok == "(" or paren_stack > 1: yield Token(lineno, "data", gtok) paren_stack += -1 if gtok == ")" else 1 if not paren_stack: yield Token(lineno, "block_begin", None) yield Token(lineno, "name", "endtrans") yield Token(lineno, "block_end", None) pos = match.end() if pos < len(token.value): yield Token(lineno, "data", token.value[pos:]) if paren_stack: raise TemplateSyntaxError( "unclosed gettext expression", token.lineno, stream.name, stream.filename, )