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)
Copyright (C) 2012-2017 Edgewall Software