| 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:: |
| |
| <h1>_(Welcome)</h1> |
| <p>_(This is a paragraph)</p> |
| |
| 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 1: |
| 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, |
| ) |