changeset 777:4ca0e1e43ce0 stable-0.5.x

Ported [899:902] to 0.5.x branch.
author cmlenz
date Tue, 08 Jul 2008 20:41:26 +0000
parents cf0a0a066aec
children dd65de931e1f
files doc/streams.txt genshi/filters/i18n.py genshi/filters/tests/i18n.py genshi/template/loader.py
diffstat 4 files changed, 106 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- 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
 ---
--- 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.
     
--- 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 @@
           <p><input type="text" name="num"/> Eintr\xc3\xa4ge pro Seite, beginnend auf Seite <input type="text" name="num"/>.</p>
         </html>""", tmpl.generate().render())
 
+    def test_extract_i18n_msg_with_param(self):
+        tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
+            xmlns:i18n="http://genshi.edgewall.org/i18n">
+          <p i18n:msg="name">
+            Hello, ${user.name}!
+          </p>
+        </html>""")
+        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("""<html xmlns:py="http://genshi.edgewall.org/"
+            xmlns:i18n="http://genshi.edgewall.org/i18n">
+          <p i18n:msg="name">
+            Hello, ${user.name}!
+          </p>
+        </html>""")
+        gettext = lambda s: u"Hallo, %(name)s!"
+        tmpl.filters.insert(0, Translator(gettext))
+        self.assertEqual("""<html>
+          <p>Hallo, Jim!</p>
+        </html>""", tmpl.generate(user=dict(name='Jim')).render())
+
+    def test_translate_i18n_msg_with_param_reordered(self):
+        tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
+            xmlns:i18n="http://genshi.edgewall.org/i18n">
+          <p i18n:msg="name">
+            Hello, ${user.name}!
+          </p>
+        </html>""")
+        gettext = lambda s: u"%(name)s, sei gegrüßt!"
+        tmpl.filters.insert(0, Translator(gettext))
+        self.assertEqual("""<html>
+          <p>Jim, sei gegrüßt!</p>
+        </html>""", tmpl.generate(user=dict(name='Jim')).render())
+
+    def test_extract_i18n_msg_with_two_params(self):
+        tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
+            xmlns:i18n="http://genshi.edgewall.org/i18n">
+          <p i18n:msg="name, time">
+            Posted by ${post.author} at ${entry.time.strftime('%H:%m')}
+          </p>
+        </html>""")
+        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("""<html xmlns:py="http://genshi.edgewall.org/"
+            xmlns:i18n="http://genshi.edgewall.org/i18n">
+          <p i18n:msg="name, time">
+            Written by ${entry.author} at ${entry.time.strftime('%H:%M')}
+          </p>
+        </html>""")
+        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("""<html>
+          <p>Jim schrieb dies um 14:30</p>
+        </html>""", tmpl.generate(entry=entry).render())
+
     def test_extract_i18n_msg_with_directive(self):
         tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
             xmlns:i18n="http://genshi.edgewall.org/i18n">
--- 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'
 
 
Copyright (C) 2012-2017 Edgewall Software