Mercurial > genshi > genshi-test
comparison genshi/filters/i18n.py @ 916:872726bac135 experimental-py3k
add support for python 3 to genshi.filters:
* minor changes to track encoding=None API change in core genshi modules.
* renamed genshi/filters/tests/html.py to test_html.py to avoid clashes with Python 3 top-level html module when running tests subset.
* did not rename genshi/filters/html.py.
* i18n filters:
* ugettext and friends are gone in Python 3 (and only gettext and friends exist and they now handle unicode)
* Some \ line continuations inside doctests confused 2to3 and so were removed them.
* Testing picked up a problem (already present in trunk) where Translator.__call__ could end up defining gettext as an endlessly recursive function. Noted with a TODO.
author | hodgestar |
---|---|
date | Sun, 24 Oct 2010 22:21:28 +0000 |
parents | 85e4678337cf |
children |
comparison
equal
deleted
inserted
replaced
915:9fafb35032a1 | 916:872726bac135 |
---|---|
31 XML_NAMESPACE, _ensure, StreamEventKind | 31 XML_NAMESPACE, _ensure, StreamEventKind |
32 from genshi.template.eval import _ast | 32 from genshi.template.eval import _ast |
33 from genshi.template.base import DirectiveFactory, EXPR, SUB, _apply_directives | 33 from genshi.template.base import DirectiveFactory, EXPR, SUB, _apply_directives |
34 from genshi.template.directives import Directive, StripDirective | 34 from genshi.template.directives import Directive, StripDirective |
35 from genshi.template.markup import MarkupTemplate, EXEC | 35 from genshi.template.markup import MarkupTemplate, EXEC |
36 from genshi.compat import IS_PYTHON2 | |
36 | 37 |
37 __all__ = ['Translator', 'extract'] | 38 __all__ = ['Translator', 'extract'] |
38 __docformat__ = 'restructuredtext en' | 39 __docformat__ = 'restructuredtext en' |
39 | 40 |
40 | 41 |
286 an integer which will allow to choose the plural/singular form. If you also | 287 an integer which will allow to choose the plural/singular form. If you also |
287 have expressions inside the singular and plural version of the string you | 288 have expressions inside the singular and plural version of the string you |
288 also need to pass a name for those parameters. Consider the following | 289 also need to pass a name for those parameters. Consider the following |
289 examples: | 290 examples: |
290 | 291 |
291 >>> tmpl = MarkupTemplate('''\ | 292 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n"> |
292 <html xmlns:i18n="http://genshi.edgewall.org/i18n"> | |
293 ... <div i18n:choose="num; num"> | 293 ... <div i18n:choose="num; num"> |
294 ... <p i18n:singular="">There is $num coin</p> | 294 ... <p i18n:singular="">There is $num coin</p> |
295 ... <p i18n:plural="">There are $num coins</p> | 295 ... <p i18n:plural="">There are $num coins</p> |
296 ... </div> | 296 ... </div> |
297 ... </html>''') | 297 ... </html>''') |
299 >>> translator.setup(tmpl) | 299 >>> translator.setup(tmpl) |
300 >>> list(translator.extract(tmpl.stream)) #doctest: +NORMALIZE_WHITESPACE | 300 >>> list(translator.extract(tmpl.stream)) #doctest: +NORMALIZE_WHITESPACE |
301 [(2, 'ngettext', (u'There is %(num)s coin', | 301 [(2, 'ngettext', (u'There is %(num)s coin', |
302 u'There are %(num)s coins'), [])] | 302 u'There are %(num)s coins'), [])] |
303 | 303 |
304 >>> tmpl = MarkupTemplate('''\ | 304 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n"> |
305 <html xmlns:i18n="http://genshi.edgewall.org/i18n"> | |
306 ... <div i18n:choose="num; num"> | 305 ... <div i18n:choose="num; num"> |
307 ... <p i18n:singular="">There is $num coin</p> | 306 ... <p i18n:singular="">There is $num coin</p> |
308 ... <p i18n:plural="">There are $num coins</p> | 307 ... <p i18n:plural="">There are $num coins</p> |
309 ... </div> | 308 ... </div> |
310 ... </html>''') | 309 ... </html>''') |
322 </div> | 321 </div> |
323 </html> | 322 </html> |
324 | 323 |
325 When used as a element and not as an attribute: | 324 When used as a element and not as an attribute: |
326 | 325 |
327 >>> tmpl = MarkupTemplate('''\ | 326 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n"> |
328 <html xmlns:i18n="http://genshi.edgewall.org/i18n"> | |
329 ... <i18n:choose numeral="num" params="num"> | 327 ... <i18n:choose numeral="num" params="num"> |
330 ... <p i18n:singular="">There is $num coin</p> | 328 ... <p i18n:singular="">There is $num coin</p> |
331 ... <p i18n:plural="">There are $num coins</p> | 329 ... <p i18n:plural="">There are $num coins</p> |
332 ... </i18n:choose> | 330 ... </i18n:choose> |
333 ... </html>''') | 331 ... </html>''') |
490 class DomainDirective(I18NDirective): | 488 class DomainDirective(I18NDirective): |
491 """Implementation of the ``i18n:domain`` directive which allows choosing | 489 """Implementation of the ``i18n:domain`` directive which allows choosing |
492 another i18n domain(catalog) to translate from. | 490 another i18n domain(catalog) to translate from. |
493 | 491 |
494 >>> from genshi.filters.tests.i18n import DummyTranslations | 492 >>> from genshi.filters.tests.i18n import DummyTranslations |
495 >>> tmpl = MarkupTemplate('''\ | 493 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n"> |
496 <html xmlns:i18n="http://genshi.edgewall.org/i18n"> | |
497 ... <p i18n:msg="">Bar</p> | 494 ... <p i18n:msg="">Bar</p> |
498 ... <div i18n:domain="foo"> | 495 ... <div i18n:domain="foo"> |
499 ... <p i18n:msg="">FooBar</p> | 496 ... <p i18n:msg="">FooBar</p> |
500 ... <p>Bar</p> | 497 ... <p>Bar</p> |
501 ... <p i18n:domain="bar" i18n:msg="">Bar</p> | 498 ... <p i18n:domain="bar" i18n:msg="">Bar</p> |
661 if type(self.translate) is FunctionType: | 658 if type(self.translate) is FunctionType: |
662 gettext = self.translate | 659 gettext = self.translate |
663 if ctxt: | 660 if ctxt: |
664 ctxt['_i18n.gettext'] = gettext | 661 ctxt['_i18n.gettext'] = gettext |
665 else: | 662 else: |
666 gettext = self.translate.ugettext | 663 if IS_PYTHON2: |
667 ngettext = self.translate.ungettext | 664 gettext = self.translate.ugettext |
665 ngettext = self.translate.ungettext | |
666 else: | |
667 gettext = self.translate.gettext | |
668 ngettext = self.translate.ngettext | |
668 try: | 669 try: |
669 dgettext = self.translate.dugettext | 670 if IS_PYTHON2: |
670 dngettext = self.translate.dungettext | 671 dgettext = self.translate.dugettext |
672 dngettext = self.translate.dungettext | |
673 else: | |
674 dgettext = self.translate.dgettext | |
675 dngettext = self.translate.dngettext | |
671 except AttributeError: | 676 except AttributeError: |
672 dgettext = lambda _, y: gettext(y) | 677 dgettext = lambda _, y: gettext(y) |
673 dngettext = lambda _, s, p, n: ngettext(s, p, n) | 678 dngettext = lambda _, s, p, n: ngettext(s, p, n) |
674 if ctxt: | 679 if ctxt: |
675 ctxt['_i18n.gettext'] = gettext | 680 ctxt['_i18n.gettext'] = gettext |
676 ctxt['_i18n.ngettext'] = ngettext | 681 ctxt['_i18n.ngettext'] = ngettext |
677 ctxt['_i18n.dgettext'] = dgettext | 682 ctxt['_i18n.dgettext'] = dgettext |
678 ctxt['_i18n.dngettext'] = dngettext | 683 ctxt['_i18n.dngettext'] = dngettext |
679 | 684 |
680 if ctxt and ctxt.get('_i18n.domain'): | 685 if ctxt and ctxt.get('_i18n.domain'): |
686 # TODO: This can cause infinite recursion if dgettext is defined | |
687 # via the AttributeError case above! | |
681 gettext = lambda msg: dgettext(ctxt.get('_i18n.domain'), msg) | 688 gettext = lambda msg: dgettext(ctxt.get('_i18n.domain'), msg) |
682 | 689 |
683 for kind, data, pos in stream: | 690 for kind, data, pos in stream: |
684 | 691 |
685 # skip chunks that should not be localized | 692 # skip chunks that should not be localized |
1166 def _walk(node): | 1173 def _walk(node): |
1167 if isinstance(node, _ast.Call) and isinstance(node.func, _ast.Name) \ | 1174 if isinstance(node, _ast.Call) and isinstance(node.func, _ast.Name) \ |
1168 and node.func.id in gettext_functions: | 1175 and node.func.id in gettext_functions: |
1169 strings = [] | 1176 strings = [] |
1170 def _add(arg): | 1177 def _add(arg): |
1171 if isinstance(arg, _ast.Str) and isinstance(arg.s, basestring): | 1178 if isinstance(arg, _ast.Str) and isinstance(arg.s, unicode): |
1179 strings.append(arg.s) | |
1180 elif isinstance(arg, _ast.Str): | |
1172 strings.append(unicode(arg.s, 'utf-8')) | 1181 strings.append(unicode(arg.s, 'utf-8')) |
1173 elif arg: | 1182 elif arg: |
1174 strings.append(None) | 1183 strings.append(None) |
1175 [_add(arg) for arg in node.args] | 1184 [_add(arg) for arg in node.args] |
1176 _add(node.starargs) | 1185 _add(node.starargs) |