# HG changeset patch # User cmlenz # Date 1215549686 0 # Node ID fc0b704692669e8c2990cb00b3e50582f1634d84 # Parent 6aa9b14c68eb2f0e810c006e0508900930535eb8 Ported [899:902] to 0.5.x branch. diff --git a/doc/streams.txt b/doc/streams.txt --- a/doc/streams.txt +++ b/doc/streams.txt @@ -379,7 +379,7 @@ .. code-block:: python - START, (QName(u'p'), Attrs([(u'class', u'intro')])), pos + START, (QName(u'p'), Attrs([(QName(u'class'), u'intro')])), pos END --- diff --git a/genshi/filters/i18n.py b/genshi/filters/i18n.py --- a/genshi/filters/i18n.py +++ b/genshi/filters/i18n.py @@ -180,7 +180,10 @@ msgbuf.append(kind, data, pos) continue elif i18n_msg in attrs: - msgbuf = MessageBuffer() + params = attrs.get(i18n_msg) + if params and type(params) is list: # event tuple + params = params[0][1] + msgbuf = MessageBuffer(params) attrs -= i18n_msg yield kind, (tag, attrs), pos @@ -194,6 +197,9 @@ else: msgbuf.append(kind, data, pos) + elif msgbuf and kind is EXPR: + msgbuf.append(kind, data, pos) + elif not skip and msgbuf and kind is END: msgbuf.append(kind, data, pos) if not msgbuf.depth: @@ -301,7 +307,10 @@ if msgbuf: msgbuf.append(kind, data, pos) elif i18n_msg in attrs: - msgbuf = MessageBuffer(pos[1]) + params = attrs.get(i18n_msg) + if params and type(params) is list: # event tuple + params = params[0][1] + msgbuf = MessageBuffer(params, pos[1]) elif not skip and search_text and kind is TEXT: if not msgbuf: @@ -318,6 +327,8 @@ msgbuf = None elif kind is EXPR or kind is EXEC: + if msgbuf: + msgbuf.append(kind, data, pos) for funcname, strings in extract_from_code(data, gettext_functions): yield pos[1], funcname, strings @@ -337,15 +348,19 @@ :since: version 0.5 """ - def __init__(self, lineno=-1): + def __init__(self, params=u'', lineno=-1): """Initialize the message buffer. + :param params: comma-separated list of parameter names + :type params: `basestring` :param lineno: the line number on which the first stream event belonging to the message was found """ + self.params = [name.strip() for name in params.split(',')] self.lineno = lineno self.string = [] self.events = {} + self.values = {} self.depth = 1 self.order = 1 self.stack = [0] @@ -360,6 +375,11 @@ if kind is TEXT: self.string.append(data) self.events.setdefault(self.stack[-1], []).append(None) + elif kind is EXPR: + param = self.params.pop(0) + self.string.append('%%(%s)s' % param) + self.events.setdefault(self.stack[-1], []).append(None) + self.values[param] = (kind, data, pos) else: if kind is START: self.string.append(u'[%d:' % self.order) @@ -380,7 +400,7 @@ """ return u''.join(self.string).strip() - def translate(self, string): + def translate(self, string, regex=re.compile(r'%\((\w+)\)s')): """Interpolate the given message translation with the events in the buffer and return the translated stream. @@ -390,15 +410,19 @@ for order, string in parts: events = self.events[order] while events: - event = self.events[order].pop(0) - if not event: + event = events.pop(0) + if event: + yield event + else: if not string: break - yield TEXT, string, (None, -1, -1) + for idx, part in enumerate(regex.split(string)): + if idx % 2: + yield self.values[part] + elif part: + yield TEXT, part, (None, -1, -1) if not self.events[order] or not self.events[order][0]: break - else: - yield event def parse_msg(string, regex=re.compile(r'(?:\[(\d+)\:)|\]')): @@ -445,6 +469,7 @@ return parts + def extract_from_code(code, gettext_functions): """Extract strings from Python bytecode. @@ -488,6 +513,7 @@ yield funcname, strings return _walk(code.ast) + def extract(fileobj, keywords, comment_tags, options): """Babel extraction method for Genshi templates. diff --git a/genshi/filters/tests/i18n.py b/genshi/filters/tests/i18n.py --- a/genshi/filters/tests/i18n.py +++ b/genshi/filters/tests/i18n.py @@ -11,6 +11,7 @@ # individuals. For the exact contribution history, see the revision # history and logs, available at http://genshi.edgewall.org/log/. +from datetime import datetime import doctest from StringIO import StringIO import unittest @@ -262,6 +263,73 @@

Eintr\xc3\xa4ge pro Seite, beginnend auf Seite .

""", tmpl.generate().render()) + def test_extract_i18n_msg_with_param(self): + tmpl = MarkupTemplate(""" +

+ Hello, ${user.name}! +

+ """) + translator = Translator() + messages = list(translator.extract(tmpl.stream)) + self.assertEqual(1, len(messages)) + self.assertEqual('Hello, %(name)s!', messages[0][2]) + + def test_translate_i18n_msg_with_param(self): + tmpl = MarkupTemplate(""" +

+ Hello, ${user.name}! +

+ """) + gettext = lambda s: u"Hallo, %(name)s!" + tmpl.filters.insert(0, Translator(gettext)) + self.assertEqual(""" +

Hallo, Jim!

+ """, tmpl.generate(user=dict(name='Jim')).render()) + + def test_translate_i18n_msg_with_param_reordered(self): + tmpl = MarkupTemplate(""" +

+ Hello, ${user.name}! +

+ """) + gettext = lambda s: u"%(name)s, sei gegrüßt!" + tmpl.filters.insert(0, Translator(gettext)) + self.assertEqual(""" +

Jim, sei gegrüßt!

+ """, tmpl.generate(user=dict(name='Jim')).render()) + + def test_extract_i18n_msg_with_two_params(self): + tmpl = MarkupTemplate(""" +

+ Posted by ${post.author} at ${entry.time.strftime('%H:%m')} +

+ """) + translator = Translator() + messages = list(translator.extract(tmpl.stream)) + self.assertEqual(1, len(messages)) + self.assertEqual('Posted by %(name)s at %(time)s', messages[0][2]) + + def test_translate_i18n_msg_with_two_params(self): + tmpl = MarkupTemplate(""" +

+ Written by ${entry.author} at ${entry.time.strftime('%H:%M')} +

+ """) + gettext = lambda s: u"%(name)s schrieb dies um %(time)s" + tmpl.filters.insert(0, Translator(gettext)) + entry = { + 'author': 'Jim', + 'time': datetime(2008, 4, 1, 14, 30) + } + self.assertEqual(""" +

Jim schrieb dies um 14:30

+ """, tmpl.generate(entry=entry).render()) + def test_extract_i18n_msg_with_directive(self): tmpl = MarkupTemplate(""" diff --git a/genshi/template/loader.py b/genshi/template/loader.py --- a/genshi/template/loader.py +++ b/genshi/template/loader.py @@ -22,7 +22,8 @@ from genshi.template.base import TemplateError from genshi.util import LRUCache -__all__ = ['TemplateLoader', 'TemplateNotFound'] +__all__ = ['TemplateLoader', 'TemplateNotFound', 'directory', 'package', + 'prefixed'] __docformat__ = 'restructuredtext en'