annotate 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
rev   line source
531
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
1 # -*- coding: utf-8 -*-
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
2 #
897
85e4678337cf Update changelog and copyright years.
cmlenz
parents: 895
diff changeset
3 # Copyright (C) 2007-2010 Edgewall Software
531
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
4 # All rights reserved.
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
5 #
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
6 # This software is licensed as described in the file COPYING, which
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
7 # you should have received as part of this distribution. The terms
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
8 # are also available at http://genshi.edgewall.org/wiki/License.
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
9 #
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
10 # This software consists of voluntary contributions made by many
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
11 # individuals. For the exact contribution history, see the revision
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
12 # history and logs, available at http://genshi.edgewall.org/log/.
6bb05c0480fe Add missing copyright header to i18n.py.
cmlenz
parents: 528
diff changeset
13
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
14 """Directives and utilities for internationalization and localization of
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
15 templates.
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 565
diff changeset
16
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 565
diff changeset
17 :since: version 0.4
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
18 :note: Directives support added since version 0.6
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 565
diff changeset
19 """
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
20
856
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
21 try:
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
22 any
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
23 except NameError:
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
24 from genshi.util import any
788
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
25 from gettext import NullTranslations
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
26 import os
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
27 import re
788
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
28 from types import FunctionType
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
29
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
30 from genshi.core import Attrs, Namespace, QName, START, END, TEXT, \
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
31 XML_NAMESPACE, _ensure, StreamEventKind
794
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
32 from genshi.template.eval import _ast
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
33 from genshi.template.base import DirectiveFactory, EXPR, SUB, _apply_directives
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
34 from genshi.template.directives import Directive, StripDirective
528
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
35 from genshi.template.markup import MarkupTemplate, EXEC
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
36 from genshi.compat import IS_PYTHON2
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
37
528
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
38 __all__ = ['Translator', 'extract']
501
3073ac688651 Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents: 493
diff changeset
39 __docformat__ = 'restructuredtext en'
3073ac688651 Added new markup transformation filter contributed by Alec Thomas (#122). This provides gorgeous jQuery-inspired stream transformation capabilities based on XPath expressions.
cmlenz
parents: 493
diff changeset
40
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
41
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
42 I18N_NAMESPACE = Namespace('http://genshi.edgewall.org/i18n')
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
43
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
44 MSGBUF = StreamEventKind('MSGBUF')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
45 SUB_START = StreamEventKind('SUB_START')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
46 SUB_END = StreamEventKind('SUB_END')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
47
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
48 GETTEXT_FUNCTIONS = ('_', 'gettext', 'ngettext', 'dgettext', 'dngettext',
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
49 'ugettext', 'ungettext')
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
50
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
51
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
52 class I18NDirective(Directive):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
53 """Simple interface for i18n directives to support messages extraction."""
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
54
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
55 def __call__(self, stream, directives, ctxt, **vars):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
56 return _apply_directives(stream, directives, ctxt, vars)
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
57
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
58
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
59 class ExtractableI18NDirective(I18NDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
60 """Simple interface for directives to support messages extraction."""
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
61
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
62 def extract(self, translator, stream, gettext_functions=GETTEXT_FUNCTIONS,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
63 search_text=True, comment_stack=None):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
64 raise NotImplementedError
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
65
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
66
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
67 class CommentDirective(I18NDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
68 """Implementation of the ``i18n:comment`` template directive which adds
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
69 translation comments.
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
70
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
71 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
72 ... <p i18n:comment="As in Foo Bar">Foo</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
73 ... </html>''')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
74 >>> translator = Translator()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
75 >>> translator.setup(tmpl)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
76 >>> list(translator.extract(tmpl.stream))
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
77 [(2, None, u'Foo', [u'As in Foo Bar'])]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
78 """
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
79 __slots__ = ['comment']
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
80
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
81 def __init__(self, value, template=None, namespaces=None, lineno=-1,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
82 offset=-1):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
83 Directive.__init__(self, None, template, namespaces, lineno, offset)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
84 self.comment = value
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
85
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
86
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
87 class MsgDirective(ExtractableI18NDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
88 r"""Implementation of the ``i18n:msg`` directive which marks inner content
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
89 as translatable. Consider the following examples:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
90
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
91 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
92 ... <div i18n:msg="">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
93 ... <p>Foo</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
94 ... <p>Bar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
95 ... </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
96 ... <p i18n:msg="">Foo <em>bar</em>!</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
97 ... </html>''')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
98
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
99 >>> translator = Translator()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
100 >>> translator.setup(tmpl)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
101 >>> list(translator.extract(tmpl.stream))
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
102 [(2, None, u'[1:Foo]\n [2:Bar]', []), (6, None, u'Foo [1:bar]!', [])]
853
4376010bb97e Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents: 850
diff changeset
103 >>> print(tmpl.generate().render())
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
104 <html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
105 <div><p>Foo</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
106 <p>Bar</p></div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
107 <p>Foo <em>bar</em>!</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
108 </html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
109
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
110 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
111 ... <div i18n:msg="fname, lname">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
112 ... <p>First Name: ${fname}</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
113 ... <p>Last Name: ${lname}</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
114 ... </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
115 ... <p i18n:msg="">Foo <em>bar</em>!</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
116 ... </html>''')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
117 >>> translator.setup(tmpl)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
118 >>> list(translator.extract(tmpl.stream)) #doctest: +NORMALIZE_WHITESPACE
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
119 [(2, None, u'[1:First Name: %(fname)s]\n [2:Last Name: %(lname)s]', []),
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
120 (6, None, u'Foo [1:bar]!', [])]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
121
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
122 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
123 ... <div i18n:msg="fname, lname">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
124 ... <p>First Name: ${fname}</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
125 ... <p>Last Name: ${lname}</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
126 ... </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
127 ... <p i18n:msg="">Foo <em>bar</em>!</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
128 ... </html>''')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
129 >>> translator.setup(tmpl)
853
4376010bb97e Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents: 850
diff changeset
130 >>> print(tmpl.generate(fname='John', lname='Doe').render())
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
131 <html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
132 <div><p>First Name: John</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
133 <p>Last Name: Doe</p></div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
134 <p>Foo <em>bar</em>!</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
135 </html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
136
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
137 Starting and ending white-space is stripped of to make it simpler for
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
138 translators. Stripping it is not that important since it's on the html
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
139 source, the rendered output will remain the same.
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
140 """
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
141 __slots__ = ['params', 'lineno']
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
142
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
143 def __init__(self, value, template=None, namespaces=None, lineno=-1,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
144 offset=-1):
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
145 Directive.__init__(self, None, template, namespaces, lineno, offset)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
146 self.params = [param.strip() for param in value.split(',') if param]
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
147 self.lineno = lineno
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
148
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
149 @classmethod
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
150 def attach(cls, template, stream, value, namespaces, pos):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
151 if type(value) is dict:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
152 value = value.get('params', '').strip()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
153 return super(MsgDirective, cls).attach(template, stream, value.strip(),
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
154 namespaces, pos)
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
155
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
156 def __call__(self, stream, directives, ctxt, **vars):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
157 gettext = ctxt.get('_i18n.gettext')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
158 if ctxt.get('_i18n.domain'):
891
b40dbfee9ba6 Removed some obsolete/unused code from the i18n filter.
cmlenz
parents: 888
diff changeset
159 dgettext = ctxt.get('_i18n.dgettext')
854
0d9e87c6cf6e More work on reducing the size of the diff produced by 2to3.
cmlenz
parents: 853
diff changeset
160 assert hasattr(dgettext, '__call__'), \
0d9e87c6cf6e More work on reducing the size of the diff produced by 2to3.
cmlenz
parents: 853
diff changeset
161 'No domain gettext function passed'
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
162 gettext = lambda msg: dgettext(ctxt.get('_i18n.domain'), msg)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
163
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
164 def _generate():
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
165 msgbuf = MessageBuffer(self)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
166 previous = stream.next()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
167 if previous[0] is START:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
168 yield previous
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
169 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
170 msgbuf.append(*previous)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
171 previous = stream.next()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
172 for kind, data, pos in stream:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
173 msgbuf.append(*previous)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
174 previous = kind, data, pos
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
175 if previous[0] is not END:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
176 msgbuf.append(*previous)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
177 previous = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
178 for event in msgbuf.translate(gettext(msgbuf.format())):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
179 yield event
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
180 if previous:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
181 yield previous
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
182
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
183 return _apply_directives(_generate(), directives, ctxt, vars)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
184
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
185 def extract(self, translator, stream, gettext_functions=GETTEXT_FUNCTIONS,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
186 search_text=True, comment_stack=None):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
187 msgbuf = MessageBuffer(self)
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
188 strip = False
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
189
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
190 stream = iter(stream)
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
191 previous = stream.next()
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
192 if previous[0] is START:
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
193 for message in translator._extract_attrs(previous,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
194 gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
195 search_text=search_text):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
196 yield message
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
197 previous = stream.next()
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
198 strip = True
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
199 for event in stream:
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
200 if event[0] is START:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
201 for message in translator._extract_attrs(event,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
202 gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
203 search_text=search_text):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
204 yield message
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
205 msgbuf.append(*previous)
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
206 previous = event
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
207 if not strip:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
208 msgbuf.append(*previous)
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
209
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
210 yield self.lineno, None, msgbuf.format(), comment_stack[-1:]
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
211
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
212
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
213 class ChooseBranchDirective(I18NDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
214 __slots__ = ['params']
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
215
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
216 def __call__(self, stream, directives, ctxt, **vars):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
217 self.params = ctxt.get('_i18n.choose.params', [])[:]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
218 msgbuf = MessageBuffer(self)
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
219 stream = _apply_directives(stream, directives, ctxt, vars)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
220
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
221 previous = stream.next()
871
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
222 if previous[0] is START:
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
223 yield previous
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
224 else:
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
225 msgbuf.append(*previous)
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
226
871
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
227 try:
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
228 previous = stream.next()
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
229 except StopIteration:
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
230 # For example <i18n:singular> or <i18n:plural> directives
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
231 yield MSGBUF, (), -1 # the place holder for msgbuf output
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
232 ctxt['_i18n.choose.%s' % self.tagname] = msgbuf
871
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
233 return
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
234
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
235 for event in stream:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
236 msgbuf.append(*previous)
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
237 previous = event
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
238 yield MSGBUF, (), -1 # the place holder for msgbuf output
871
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
239
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
240 if previous[0] is END:
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
241 yield previous # the outer end tag
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
242 else:
7eb6f506bb54 Allow the use of `i18n:singular` and `i18n:plural` as directives and not just as attributes.
palgarvio
parents: 869
diff changeset
243 msgbuf.append(*previous)
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
244 ctxt['_i18n.choose.%s' % self.tagname] = msgbuf
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
245
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
246 def extract(self, translator, stream, gettext_functions=GETTEXT_FUNCTIONS,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
247 search_text=True, comment_stack=None, msgbuf=None):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
248 stream = iter(stream)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
249 previous = stream.next()
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
250
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
251 if previous[0] is START:
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
252 # skip the enclosing element
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
253 for message in translator._extract_attrs(previous,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
254 gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
255 search_text=search_text):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
256 yield message
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
257 previous = stream.next()
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
258
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
259 for event in stream:
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
260 if previous[0] is START:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
261 for message in translator._extract_attrs(previous,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
262 gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
263 search_text=search_text):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
264 yield message
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
265 msgbuf.append(*previous)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
266 previous = event
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
267
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
268 if previous[0] is not END:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
269 msgbuf.append(*previous)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
270
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
271
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
272 class SingularDirective(ChooseBranchDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
273 """Implementation of the ``i18n:singular`` directive to be used with the
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
274 ``i18n:choose`` directive."""
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
275
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
276
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
277 class PluralDirective(ChooseBranchDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
278 """Implementation of the ``i18n:plural`` directive to be used with the
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
279 ``i18n:choose`` directive."""
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
280
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
281
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
282 class ChooseDirective(ExtractableI18NDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
283 """Implementation of the ``i18n:choose`` directive which provides plural
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
284 internationalisation of strings.
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
285
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
286 This directive requires at least one parameter, the one which evaluates to
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
287 an integer which will allow to choose the plural/singular form. If you also
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
288 have expressions inside the singular and plural version of the string you
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
289 also need to pass a name for those parameters. Consider the following
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
290 examples:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
291
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
292 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
293 ... <div i18n:choose="num; num">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
294 ... <p i18n:singular="">There is $num coin</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
295 ... <p i18n:plural="">There are $num coins</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
296 ... </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
297 ... </html>''')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
298 >>> translator = Translator()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
299 >>> translator.setup(tmpl)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
300 >>> list(translator.extract(tmpl.stream)) #doctest: +NORMALIZE_WHITESPACE
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
301 [(2, 'ngettext', (u'There is %(num)s coin',
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
302 u'There are %(num)s coins'), [])]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
303
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
304 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
305 ... <div i18n:choose="num; num">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
306 ... <p i18n:singular="">There is $num coin</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
307 ... <p i18n:plural="">There are $num coins</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
308 ... </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
309 ... </html>''')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
310 >>> translator.setup(tmpl)
853
4376010bb97e Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents: 850
diff changeset
311 >>> print(tmpl.generate(num=1).render())
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
312 <html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
313 <div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
314 <p>There is 1 coin</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
315 </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
316 </html>
853
4376010bb97e Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents: 850
diff changeset
317 >>> print(tmpl.generate(num=2).render())
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
318 <html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
319 <div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
320 <p>There are 2 coins</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
321 </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
322 </html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
323
888
18dee397f8e1 More i18n doc improvements.
cmlenz
parents: 882
diff changeset
324 When used as a element and not as an attribute:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
325
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
326 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
327 ... <i18n:choose numeral="num" params="num">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
328 ... <p i18n:singular="">There is $num coin</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
329 ... <p i18n:plural="">There are $num coins</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
330 ... </i18n:choose>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
331 ... </html>''')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
332 >>> translator.setup(tmpl)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
333 >>> list(translator.extract(tmpl.stream)) #doctest: +NORMALIZE_WHITESPACE
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
334 [(2, 'ngettext', (u'There is %(num)s coin',
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
335 u'There are %(num)s coins'), [])]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
336 """
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
337 __slots__ = ['numeral', 'params', 'lineno']
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
338
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
339 def __init__(self, value, template=None, namespaces=None, lineno=-1,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
340 offset=-1):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
341 Directive.__init__(self, None, template, namespaces, lineno, offset)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
342 params = [v.strip() for v in value.split(';')]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
343 self.numeral = self._parse_expr(params.pop(0), template, lineno, offset)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
344 self.params = params and [name.strip() for name in
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
345 params[0].split(',') if name] or []
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
346 self.lineno = lineno
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
347
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
348 @classmethod
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
349 def attach(cls, template, stream, value, namespaces, pos):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
350 if type(value) is dict:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
351 numeral = value.get('numeral', '').strip()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
352 assert numeral is not '', "at least pass the numeral param"
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
353 params = [v.strip() for v in value.get('params', '').split(',')]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
354 value = '%s; ' % numeral + ', '.join(params)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
355 return super(ChooseDirective, cls).attach(template, stream, value,
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
356 namespaces, pos)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
357
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
358 def __call__(self, stream, directives, ctxt, **vars):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
359 ctxt.push({'_i18n.choose.params': self.params,
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
360 '_i18n.choose.singular': None,
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
361 '_i18n.choose.plural': None})
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
362
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
363 ngettext = ctxt.get('_i18n.ngettext')
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
364 assert hasattr(ngettext, '__call__'), 'No ngettext function available'
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
365 dngettext = ctxt.get('_i18n.dngettext')
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
366 if not dngettext:
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
367 dngettext = lambda d, s, p, n: ngettext(s, p, n)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
368
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
369 new_stream = []
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
370 singular_stream = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
371 singular_msgbuf = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
372 plural_stream = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
373 plural_msgbuf = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
374
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
375 numeral = self.numeral.evaluate(ctxt)
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
376 is_plural = self._is_plural(numeral, ngettext)
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
377
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
378 for event in stream:
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
379 if event[0] is SUB and any(isinstance(d, ChooseBranchDirective)
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
380 for d in event[1][0]):
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
381 subdirectives, substream = event[1]
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
382
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
383 if isinstance(subdirectives[0], SingularDirective):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
384 singular_stream = list(_apply_directives(substream,
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
385 subdirectives,
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
386 ctxt, vars))
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
387 new_stream.append((MSGBUF, None, (None, -1, -1)))
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
388
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
389 elif isinstance(subdirectives[0], PluralDirective):
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
390 if is_plural:
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
391 plural_stream = list(_apply_directives(substream,
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
392 subdirectives,
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
393 ctxt, vars))
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
394
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
395 else:
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
396 new_stream.append(event)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
397
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
398 if ctxt.get('_i18n.domain'):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
399 ngettext = lambda s, p, n: dngettext(ctxt.get('_i18n.domain'),
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
400 s, p, n)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
401
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
402 singular_msgbuf = ctxt.get('_i18n.choose.singular')
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
403 if is_plural:
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
404 plural_msgbuf = ctxt.get('_i18n.choose.plural')
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
405 msgbuf, choice = plural_msgbuf, plural_stream
873
9786aa263217 Any `py:strip` involved on `i18n:singular` or `i18n:plural` is now handled separately, ie, if one has `py:strip` on a `i18n:singular` element or directive and the plural form is the one chosen, no stripping will be performed. Refs #371.
palgarvio
parents: 872
diff changeset
406 else:
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
407 msgbuf, choice = singular_msgbuf, singular_stream
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
408 plural_msgbuf = MessageBuffer(self)
873
9786aa263217 Any `py:strip` involved on `i18n:singular` or `i18n:plural` is now handled separately, ie, if one has `py:strip` on a `i18n:singular` element or directive and the plural form is the one chosen, no stripping will be performed. Refs #371.
palgarvio
parents: 872
diff changeset
409
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
410 for kind, data, pos in new_stream:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
411 if kind is MSGBUF:
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
412 for event in choice:
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
413 if event[0] is MSGBUF:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
414 translation = ngettext(singular_msgbuf.format(),
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
415 plural_msgbuf.format(),
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
416 numeral)
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
417 for subevent in msgbuf.translate(translation):
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
418 yield subevent
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
419 else:
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
420 yield event
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
421 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
422 yield kind, data, pos
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
423
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
424 ctxt.pop()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
425
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
426 def extract(self, translator, stream, gettext_functions=GETTEXT_FUNCTIONS,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
427 search_text=True, comment_stack=None):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
428 strip = False
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
429 stream = iter(stream)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
430 previous = stream.next()
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
431
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
432 if previous[0] is START:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
433 # skip the enclosing element
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
434 for message in translator._extract_attrs(previous,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
435 gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
436 search_text=search_text):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
437 yield message
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
438 previous = stream.next()
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
439 strip = True
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
440
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
441 singular_msgbuf = MessageBuffer(self)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
442 plural_msgbuf = MessageBuffer(self)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
443
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
444 for event in stream:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
445 if previous[0] is SUB:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
446 directives, substream = previous[1]
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
447 for directive in directives:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
448 if isinstance(directive, SingularDirective):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
449 for message in directive.extract(translator,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
450 substream, gettext_functions, search_text,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
451 comment_stack, msgbuf=singular_msgbuf):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
452 yield message
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
453 elif isinstance(directive, PluralDirective):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
454 for message in directive.extract(translator,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
455 substream, gettext_functions, search_text,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
456 comment_stack, msgbuf=plural_msgbuf):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
457 yield message
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
458 elif not isinstance(directive, StripDirective):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
459 singular_msgbuf.append(*previous)
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
460 plural_msgbuf.append(*previous)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
461 else:
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
462 if previous[0] is START:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
463 for message in translator._extract_attrs(previous,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
464 gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
465 search_text):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
466 yield message
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
467 singular_msgbuf.append(*previous)
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
468 plural_msgbuf.append(*previous)
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
469 previous = event
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
470
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
471 if not strip:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
472 singular_msgbuf.append(*previous)
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
473 plural_msgbuf.append(*previous)
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
474
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
475 yield self.lineno, 'ngettext', \
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
476 (singular_msgbuf.format(), plural_msgbuf.format()), \
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
477 comment_stack[-1:]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
478
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
479 def _is_plural(self, numeral, ngettext):
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
480 # XXX: should we test which form was chosen like this!?!?!?
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
481 # There should be no match in any catalogue for these singular and
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
482 # plural test strings
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
483 singular = u'O\x85\xbe\xa9\xa8az\xc3?\xe6\xa1\x02n\x84\x93'
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
484 plural = u'\xcc\xfb+\xd3Pn\x9d\tT\xec\x1d\xda\x1a\x88\x00'
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
485 return ngettext(singular, plural, numeral) == plural
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
486
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
487
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
488 class DomainDirective(I18NDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
489 """Implementation of the ``i18n:domain`` directive which allows choosing
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
490 another i18n domain(catalog) to translate from.
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
491
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
492 >>> from genshi.filters.tests.i18n import DummyTranslations
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
493 >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
494 ... <p i18n:msg="">Bar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
495 ... <div i18n:domain="foo">
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
496 ... <p i18n:msg="">FooBar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
497 ... <p>Bar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
498 ... <p i18n:domain="bar" i18n:msg="">Bar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
499 ... <p i18n:domain="">Bar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
500 ... </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
501 ... <p>Bar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
502 ... </html>''')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
503
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
504 >>> translations = DummyTranslations({'Bar': 'Voh'})
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
505 >>> translations.add_domain('foo', {'FooBar': 'BarFoo', 'Bar': 'foo_Bar'})
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
506 >>> translations.add_domain('bar', {'Bar': 'bar_Bar'})
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
507 >>> translator = Translator(translations)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
508 >>> translator.setup(tmpl)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
509
853
4376010bb97e Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents: 850
diff changeset
510 >>> print(tmpl.generate().render())
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
511 <html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
512 <p>Voh</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
513 <div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
514 <p>BarFoo</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
515 <p>foo_Bar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
516 <p>bar_Bar</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
517 <p>Voh</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
518 </div>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
519 <p>Voh</p>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
520 </html>
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
521 """
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
522 __slots__ = ['domain']
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
523
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
524 def __init__(self, value, template=None, namespaces=None, lineno=-1,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
525 offset=-1):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
526 Directive.__init__(self, None, template, namespaces, lineno, offset)
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
527 self.domain = value and value.strip() or '__DEFAULT__'
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
528
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
529 @classmethod
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
530 def attach(cls, template, stream, value, namespaces, pos):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
531 if type(value) is dict:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
532 value = value.get('name')
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
533 return super(DomainDirective, cls).attach(template, stream, value,
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
534 namespaces, pos)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
535
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
536 def __call__(self, stream, directives, ctxt, **vars):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
537 ctxt.push({'_i18n.domain': self.domain})
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
538 for event in _apply_directives(stream, directives, ctxt, vars):
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
539 yield event
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
540 ctxt.pop()
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
541
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
542
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
543 class Translator(DirectiveFactory):
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
544 """Can extract and translate localizable strings from markup streams and
450
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
545 templates.
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
546
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
547 For example, assume the following template:
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
548
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
549 >>> tmpl = MarkupTemplate('''<html xmlns:py="http://genshi.edgewall.org/">
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
550 ... <head>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
551 ... <title>Example</title>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
552 ... </head>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
553 ... <body>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
554 ... <h1>Example</h1>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
555 ... <p>${_("Hello, %(name)s") % dict(name=username)}</p>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
556 ... </body>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
557 ... </html>''', filename='example.html')
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
558
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
559 For demonstration, we define a dummy ``gettext``-style function with a
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
560 hard-coded translation table, and pass that to the `Translator` initializer:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
561
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
562 >>> def pseudo_gettext(string):
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
563 ... return {
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
564 ... 'Example': 'Beispiel',
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
565 ... 'Hello, %(name)s': 'Hallo, %(name)s'
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
566 ... }[string]
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
567 >>> translator = Translator(pseudo_gettext)
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
568
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
569 Next, the translator needs to be prepended to any already defined filters
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
570 on the template:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
571
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
572 >>> tmpl.filters.insert(0, translator)
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
573
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
574 When generating the template output, our hard-coded translations should be
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
575 applied as expected:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
576
853
4376010bb97e Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents: 850
diff changeset
577 >>> print(tmpl.generate(username='Hans', _=pseudo_gettext))
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
578 <html>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
579 <head>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
580 <title>Beispiel</title>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
581 </head>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
582 <body>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
583 <h1>Beispiel</h1>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
584 <p>Hallo, Hans</p>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
585 </body>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
586 </html>
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
587
522
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
588 Note that elements defining ``xml:lang`` attributes that do not contain
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
589 variable expressions are ignored by this filter. That can be used to
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
590 exclude specific parts of a template from being extracted and translated.
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
591 """
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
592
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
593 directives = [
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
594 ('domain', DomainDirective),
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
595 ('comment', CommentDirective),
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
596 ('msg', MsgDirective),
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
597 ('choose', ChooseDirective),
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
598 ('singular', SingularDirective),
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
599 ('plural', PluralDirective)
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
600 ]
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
601
450
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
602 IGNORE_TAGS = frozenset([
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
603 QName('script'), QName('http://www.w3.org/1999/xhtml}script'),
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
604 QName('style'), QName('http://www.w3.org/1999/xhtml}style')
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
605 ])
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
606 INCLUDE_ATTRS = frozenset([
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
607 'abbr', 'alt', 'label', 'prompt', 'standby', 'summary', 'title'
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
608 ])
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
609 NAMESPACE = I18N_NAMESPACE
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
610
788
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
611 def __init__(self, translate=NullTranslations(), ignore_tags=IGNORE_TAGS,
594
0fb43dc2e165 Add option to I18n filter to only extract strings in gettext function calls.
cmlenz
parents: 576
diff changeset
612 include_attrs=INCLUDE_ATTRS, extract_text=True):
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
613 """Initialize the translator.
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
614
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
615 :param translate: the translation function, for example ``gettext`` or
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
616 ``ugettext``.
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
617 :param ignore_tags: a set of tag names that should not be localized
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
618 :param include_attrs: a set of attribute names should be localized
594
0fb43dc2e165 Add option to I18n filter to only extract strings in gettext function calls.
cmlenz
parents: 576
diff changeset
619 :param extract_text: whether the content of text nodes should be
0fb43dc2e165 Add option to I18n filter to only extract strings in gettext function calls.
cmlenz
parents: 576
diff changeset
620 extracted, or only text in explicit ``gettext``
0fb43dc2e165 Add option to I18n filter to only extract strings in gettext function calls.
cmlenz
parents: 576
diff changeset
621 function calls
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
622
788
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
623 :note: Changed in 0.6: the `translate` parameter can now be either
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
624 a ``gettext``-style function, or an object compatible with the
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
625 ``NullTransalations`` or ``GNUTranslations`` interface
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
626 """
450
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
627 self.translate = translate
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
628 self.ignore_tags = ignore_tags
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
629 self.include_attrs = include_attrs
594
0fb43dc2e165 Add option to I18n filter to only extract strings in gettext function calls.
cmlenz
parents: 576
diff changeset
630 self.extract_text = extract_text
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
631
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
632 def __call__(self, stream, ctxt=None, translate_text=True,
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
633 translate_attrs=True):
448
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
634 """Translate any localizable strings in the given stream.
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
635
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
636 This function shouldn't be called directly. Instead, an instance of
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
637 the `Translator` class should be registered as a filter with the
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
638 `Template` or the `TemplateLoader`, or applied as a regular stream
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
639 filter. If used as a template filter, it should be inserted in front of
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
640 all the default filters.
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
641
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
642 :param stream: the markup event stream
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
643 :param ctxt: the template context (not used)
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
644 :param translate_text: whether text nodes should be translated (used
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
645 internally)
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
646 :param translate_attrs: whether attribute values should be translated
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
647 (used internally)
448
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
648 :return: the localized stream
0407937b2853 Add support for HTML5 doctype.
cmlenz
parents: 446
diff changeset
649 """
450
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
650 ignore_tags = self.ignore_tags
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
651 include_attrs = self.include_attrs
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
652 skip = 0
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
653 xml_lang = XML_NAMESPACE['lang']
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
654 if not self.extract_text:
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
655 translate_text = False
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
656 translate_attrs = False
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
657
788
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
658 if type(self.translate) is FunctionType:
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
659 gettext = self.translate
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
660 if ctxt:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
661 ctxt['_i18n.gettext'] = gettext
788
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
662 else:
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
663 if IS_PYTHON2:
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
664 gettext = self.translate.ugettext
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
665 ngettext = self.translate.ungettext
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
666 else:
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
667 gettext = self.translate.gettext
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
668 ngettext = self.translate.ngettext
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
669 try:
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
670 if IS_PYTHON2:
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
671 dgettext = self.translate.dugettext
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
672 dngettext = self.translate.dungettext
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
673 else:
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
674 dgettext = self.translate.dgettext
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
675 dngettext = self.translate.dngettext
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
676 except AttributeError:
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
677 dgettext = lambda _, y: gettext(y)
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
678 dngettext = lambda _, s, p, n: ngettext(s, p, n)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
679 if ctxt:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
680 ctxt['_i18n.gettext'] = gettext
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
681 ctxt['_i18n.ngettext'] = ngettext
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
682 ctxt['_i18n.dgettext'] = dgettext
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
683 ctxt['_i18n.dngettext'] = dngettext
787
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
684
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
685 if ctxt and ctxt.get('_i18n.domain'):
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
686 # TODO: This can cause infinite recursion if dgettext is defined
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
687 # via the AttributeError case above!
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
688 gettext = lambda msg: dgettext(ctxt.get('_i18n.domain'), msg)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
689
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
690 for kind, data, pos in stream:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
691
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
692 # skip chunks that should not be localized
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
693 if skip:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
694 if kind is START:
522
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
695 skip += 1
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
696 elif kind is END:
522
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
697 skip -= 1
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
698 yield kind, data, pos
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
699 continue
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
700
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
701 # handle different events that can be localized
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
702 if kind is START:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
703 tag, attrs = data
522
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
704 if tag in self.ignore_tags or \
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
705 isinstance(attrs.get(xml_lang), basestring):
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
706 skip += 1
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
707 yield kind, data, pos
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
708 continue
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
709
493
abe6e4ab7ecf Fix another bug in the translation filter: translated attributes were getting added instead of replaced.
cmlenz
parents: 485
diff changeset
710 new_attrs = []
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
711 changed = False
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
712
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
713 for name, value in attrs:
483
dabb9e1e2ba1 Fix for handling of interpolated attribute values in translation filter.
cmlenz
parents: 481
diff changeset
714 newval = value
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
715 if isinstance(value, basestring):
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
716 if translate_attrs and name in include_attrs:
788
09531799bac2 Change `Translator` class to accept either a `gettext`-style function, or an object compatible with the `NullTranslations` / `GNUTranslations` interface.
cmlenz
parents: 787
diff changeset
717 newval = gettext(value)
483
dabb9e1e2ba1 Fix for handling of interpolated attribute values in translation filter.
cmlenz
parents: 481
diff changeset
718 else:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
719 newval = list(
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
720 self(_ensure(value), ctxt, translate_text=False)
483
dabb9e1e2ba1 Fix for handling of interpolated attribute values in translation filter.
cmlenz
parents: 481
diff changeset
721 )
dabb9e1e2ba1 Fix for handling of interpolated attribute values in translation filter.
cmlenz
parents: 481
diff changeset
722 if newval != value:
dabb9e1e2ba1 Fix for handling of interpolated attribute values in translation filter.
cmlenz
parents: 481
diff changeset
723 value = newval
dabb9e1e2ba1 Fix for handling of interpolated attribute values in translation filter.
cmlenz
parents: 481
diff changeset
724 changed = True
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
725 new_attrs.append((name, value))
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
726 if changed:
667
077c9142dca0 Fix case where attributes weren't properly wrapped in an `Attrs` instance if one or more of them were translated by the I18n filter, potentially breaking things further down the chain. Closes #162.
cmlenz
parents: 600
diff changeset
727 attrs = Attrs(new_attrs)
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
728
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
729 yield kind, (tag, attrs), pos
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
730
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
731 elif translate_text and kind is TEXT:
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
732 text = data.strip()
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
733 if text:
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
734 data = data.replace(text, unicode(gettext(text)))
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
735 yield kind, data, pos
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
736
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
737 elif kind is SUB:
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
738 directives, substream = data
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
739 current_domain = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
740 for idx, directive in enumerate(directives):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
741 # Organize directives to make everything work
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
742 # FIXME: There's got to be a better way to do this!
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
743 if isinstance(directive, DomainDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
744 # Grab current domain and update context
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
745 current_domain = directive.domain
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
746 ctxt.push({'_i18n.domain': current_domain})
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
747 # Put domain directive as the first one in order to
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
748 # update context before any other directives evaluation
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
749 directives.insert(0, directives.pop(idx))
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
750
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
751 # If this is an i18n directive, no need to translate text
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
752 # nodes here
856
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
753 is_i18n_directive = any([
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
754 isinstance(d, ExtractableI18NDirective)
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
755 for d in directives
1e2be9fb3348 Add a couple of fallback imports for Python 3.0.
cmlenz
parents: 854
diff changeset
756 ])
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
757 substream = list(self(substream, ctxt,
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
758 translate_text=not is_i18n_directive,
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
759 translate_attrs=translate_attrs))
790
1b6968d31089 Merged the custom-directives branch back into trunk.
cmlenz
parents: 788
diff changeset
760 yield kind, (directives, substream), pos
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
761
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
762 if current_domain:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
763 ctxt.pop()
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
764 else:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
765 yield kind, data, pos
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
766
485
770ba8556940 Follow-up to [583]: Don't extract strings from interpolated attribute values for attributes that shouldn't be included.
cmlenz
parents: 483
diff changeset
767 def extract(self, stream, gettext_functions=GETTEXT_FUNCTIONS,
891
b40dbfee9ba6 Removed some obsolete/unused code from the i18n filter.
cmlenz
parents: 888
diff changeset
768 search_text=True, comment_stack=None):
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
769 """Extract localizable strings from the given template stream.
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
770
450
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
771 For every string found, this function yields a ``(lineno, function,
787
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
772 message, comments)`` tuple, where:
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
773
450
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
774 * ``lineno`` is the number of the line on which the string was found,
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
775 * ``function`` is the name of the ``gettext`` function used (if the
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
776 string was extracted from embedded Python code), and
469
5eae4a5c42ac The I18n extraction now returns a tuple of strings for `ngettext` and similar functions.
cmlenz
parents: 467
diff changeset
777 * ``message`` is the string itself (a ``unicode`` object, or a tuple
787
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
778 of ``unicode`` objects for functions with multiple string
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
779 arguments).
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
780 * ``comments`` is a list of comments related to the message, extracted
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
781 from ``i18n:comment`` attributes found in the markup
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
782
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
783 >>> tmpl = MarkupTemplate('''<html xmlns:py="http://genshi.edgewall.org/">
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
784 ... <head>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
785 ... <title>Example</title>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
786 ... </head>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
787 ... <body>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
788 ... <h1>Example</h1>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
789 ... <p>${_("Hello, %(name)s") % dict(name=username)}</p>
469
5eae4a5c42ac The I18n extraction now returns a tuple of strings for `ngettext` and similar functions.
cmlenz
parents: 467
diff changeset
790 ... <p>${ngettext("You have %d item", "You have %d items", num)}</p>
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
791 ... </body>
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
792 ... </html>''', filename='example.html')
787
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
793 >>> for line, func, msg, comments in Translator().extract(tmpl.stream):
853
4376010bb97e Convert a bunch of print statements to py3k compatible syntax.
cmlenz
parents: 850
diff changeset
794 ... print('%d, %r, %r' % (line, func, msg))
450
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
795 3, None, u'Example'
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
796 6, None, u'Example'
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
797 7, '_', u'Hello, %(name)s'
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
798 8, 'ngettext', (u'You have %d item', u'You have %d items', None)
469
5eae4a5c42ac The I18n extraction now returns a tuple of strings for `ngettext` and similar functions.
cmlenz
parents: 467
diff changeset
799
450
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
800 :param stream: the event stream to extract strings from; can be a
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
801 regular stream or a template stream
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
802 :param gettext_functions: a sequence of function names that should be
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
803 treated as gettext-style localization
d2fdcd320743 Extend the I18n extraction to also yield function names if applicable.
cmlenz
parents: 448
diff changeset
804 functions
485
770ba8556940 Follow-up to [583]: Don't extract strings from interpolated attribute values for attributes that shouldn't be included.
cmlenz
parents: 483
diff changeset
805 :param search_text: whether the content of text nodes should be
770ba8556940 Follow-up to [583]: Don't extract strings from interpolated attribute values for attributes that shouldn't be included.
cmlenz
parents: 483
diff changeset
806 extracted (used internally)
469
5eae4a5c42ac The I18n extraction now returns a tuple of strings for `ngettext` and similar functions.
cmlenz
parents: 467
diff changeset
807
5eae4a5c42ac The I18n extraction now returns a tuple of strings for `ngettext` and similar functions.
cmlenz
parents: 467
diff changeset
808 :note: Changed in 0.4.1: For a function with multiple string arguments
5eae4a5c42ac The I18n extraction now returns a tuple of strings for `ngettext` and similar functions.
cmlenz
parents: 467
diff changeset
809 (such as ``ngettext``), a single item with a tuple of strings is
5eae4a5c42ac The I18n extraction now returns a tuple of strings for `ngettext` and similar functions.
cmlenz
parents: 467
diff changeset
810 yielded, instead an item for each string argument.
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
811 :note: Changed in 0.6: The returned tuples now include a fourth
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
812 element, which is a list of comments for the translator.
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
813 """
594
0fb43dc2e165 Add option to I18n filter to only extract strings in gettext function calls.
cmlenz
parents: 576
diff changeset
814 if not self.extract_text:
0fb43dc2e165 Add option to I18n filter to only extract strings in gettext function calls.
cmlenz
parents: 576
diff changeset
815 search_text = False
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
816 if comment_stack is None:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
817 comment_stack = []
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
818 skip = 0
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
819
522
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
820 xml_lang = XML_NAMESPACE['lang']
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
821
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
822 for kind, data, pos in stream:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
823 if skip:
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
824 if kind is START:
522
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
825 skip += 1
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
826 if kind is END:
522
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
827 skip -= 1
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
828
549
da5cbf6d134d The I18n filter now extracts text from translation functions in ignored tags. Fixes #132.
cmlenz
parents: 535
diff changeset
829 if kind is START and not skip:
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
830 tag, attrs = data
522
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
831 if tag in self.ignore_tags or \
c1738dec04d9 The I18n filter now skips the content of elements that have an `xml:lang` attribute with a fixed string value. Basically, `xml:lang` can now be used as a flag to mark specific sections as not needing localization.
cmlenz
parents: 501
diff changeset
832 isinstance(attrs.get(xml_lang), basestring):
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
833 skip += 1
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
834 continue
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
835
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
836 for message in self._extract_attrs((kind, data, pos),
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
837 gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
838 search_text=search_text):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
839 yield message
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
840
549
da5cbf6d134d The I18n filter now extracts text from translation functions in ignored tags. Fixes #132.
cmlenz
parents: 535
diff changeset
841 elif not skip and search_text and kind is TEXT:
891
b40dbfee9ba6 Removed some obsolete/unused code from the i18n filter.
cmlenz
parents: 888
diff changeset
842 text = data.strip()
b40dbfee9ba6 Removed some obsolete/unused code from the i18n filter.
cmlenz
parents: 888
diff changeset
843 if text and [ch for ch in text if ch.isalpha()]:
b40dbfee9ba6 Removed some obsolete/unused code from the i18n filter.
cmlenz
parents: 888
diff changeset
844 yield pos[1], None, text, comment_stack[-1:]
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
845
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
846 elif kind is EXPR or kind is EXEC:
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
847 for funcname, strings in extract_from_code(data,
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
848 gettext_functions):
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
849 # XXX: Do we need to grab i18n:comment from comment_stack ???
787
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
850 yield pos[1], funcname, strings, []
446
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
851
90f5908cd10a Add basic I18n/L10n functionality, based on GenshiRecipes/Localization.
cmlenz
parents:
diff changeset
852 elif kind is SUB:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
853 directives, substream = data
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
854 in_comment = False
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
855
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
856 for idx, directive in enumerate(directives):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
857 # Do a first loop to see if there's a comment directive
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
858 # If there is update context and pop it from directives
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
859 if isinstance(directive, CommentDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
860 in_comment = True
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
861 comment_stack.append(directive.comment)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
862 if len(directives) == 1:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
863 # in case we're in the presence of something like:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
864 # <p i18n:comment="foo">Foo</p>
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
865 for message in self.extract(
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
866 substream, gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
867 search_text=search_text and not skip,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
868 comment_stack=comment_stack):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
869 yield message
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
870 directives.pop(idx)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
871 elif not isinstance(directive, I18NDirective):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
872 # Remove all other non i18n directives from the process
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
873 directives.pop(idx)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
874
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
875 if not directives and not in_comment:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
876 # Extract content if there's no directives because
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
877 # strip was pop'ed and not because comment was pop'ed.
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
878 # Extraction in this case has been taken care of.
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
879 for message in self.extract(
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
880 substream, gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
881 search_text=search_text and not skip):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
882 yield message
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
883
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
884 for directive in directives:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
885 if isinstance(directive, ExtractableI18NDirective):
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
886 for message in directive.extract(self,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
887 substream, gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
888 search_text=search_text and not skip,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
889 comment_stack=comment_stack):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
890 yield message
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
891 else:
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
892 for message in self.extract(
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
893 substream, gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
894 search_text=search_text and not skip,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
895 comment_stack=comment_stack):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
896 yield message
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
897
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
898 if in_comment:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
899 comment_stack.pop()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
900
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
901 def get_directive_index(self, dir_cls):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
902 total = len(self._dir_order)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
903 if dir_cls in self._dir_order:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
904 return self._dir_order.index(dir_cls) - total
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
905 return total
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
906
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
907 def setup(self, template):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
908 """Convenience function to register the `Translator` filter and the
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
909 related directives with the given template.
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
910
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
911 :param template: a `Template` instance
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
912 """
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
913 template.filters.insert(0, self)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
914 if hasattr(template, 'add_directives'):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
915 template.add_directives(Translator.NAMESPACE, self)
528
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
916
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
917 def _extract_attrs(self, event, gettext_functions, search_text):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
918 for name, value in event[1][1]:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
919 if search_text and isinstance(value, basestring):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
920 if name in self.include_attrs:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
921 text = value.strip()
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
922 if text:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
923 yield event[2][1], None, text, []
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
924 else:
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
925 for message in self.extract(_ensure(value), gettext_functions,
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
926 search_text=False):
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
927 yield message
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
928
528
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
929
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
930 class MessageBuffer(object):
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
931 """Helper class for managing internationalized mixed content.
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 565
diff changeset
932
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 565
diff changeset
933 :since: version 0.5
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 565
diff changeset
934 """
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
935
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
936 def __init__(self, directive=None):
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
937 """Initialize the message buffer.
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
938
882
6f49c23045b1 Fix regression in [1099]: templates must not have an implicit loader during message extraction.
cmlenz
parents: 873
diff changeset
939 :param directive: the directive owning the buffer
6f49c23045b1 Fix regression in [1099]: templates must not have an implicit loader during message extraction.
cmlenz
parents: 873
diff changeset
940 :type directive: I18NDirective
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
941 """
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
942 # params list needs to be copied so that directives can be evaluated
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
943 # more than once
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
944 self.orig_params = self.params = directive.params[:]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
945 self.directive = directive
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
946 self.string = []
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
947 self.events = {}
775
f0f1416a814f Support for parameters in internationalized `i18n:msg` content. See #129.
cmlenz
parents: 762
diff changeset
948 self.values = {}
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
949 self.depth = 1
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
950 self.order = 1
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
951 self.stack = [0]
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
952 self.subdirectives = {}
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
953
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
954 def append(self, kind, data, pos):
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
955 """Append a stream event to the buffer.
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
956
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
957 :param kind: the stream event kind
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
958 :param data: the event data
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
959 :param pos: the position of the event in the source
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
960 """
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
961 if kind is SUB:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
962 # The order needs to be +1 because a new START kind event will
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
963 # happen and we we need to wrap those events into our custom kind(s)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
964 order = self.stack[-1] + 1
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
965 subdirectives, substream = data
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
966 # Store the directives that should be applied after translation
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
967 self.subdirectives.setdefault(order, []).extend(subdirectives)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
968 self.events.setdefault(order, []).append((SUB_START, None, pos))
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
969 for skind, sdata, spos in substream:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
970 self.append(skind, sdata, spos)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
971 self.events.setdefault(order, []).append((SUB_END, None, pos))
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
972 elif kind is TEXT:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
973 if '[' in data or ']' in data:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
974 # Quote [ and ] if it ain't us adding it, ie, if the user is
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
975 # using those chars in his templates, escape them
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
976 data = data.replace('[', '\[').replace(']', '\]')
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
977 self.string.append(data)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
978 self.events.setdefault(self.stack[-1], []).append((kind, data, pos))
775
f0f1416a814f Support for parameters in internationalized `i18n:msg` content. See #129.
cmlenz
parents: 762
diff changeset
979 elif kind is EXPR:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
980 if self.params:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
981 param = self.params.pop(0)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
982 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
983 params = ', '.join(['"%s"' % p for p in self.orig_params if p])
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
984 if params:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
985 params = "(%s)" % params
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
986 raise IndexError("%d parameters%s given to 'i18n:%s' but "
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
987 "%d or more expressions used in '%s', line %s"
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
988 % (len(self.orig_params), params,
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
989 self.directive.tagname,
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
990 len(self.orig_params) + 1,
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
991 os.path.basename(pos[0] or
872
e966d7a20d48 Typo correction.
palgarvio
parents: 871
diff changeset
992 'In-memory Template'),
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
993 pos[1]))
775
f0f1416a814f Support for parameters in internationalized `i18n:msg` content. See #129.
cmlenz
parents: 762
diff changeset
994 self.string.append('%%(%s)s' % param)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
995 self.events.setdefault(self.stack[-1], []).append((kind, data, pos))
775
f0f1416a814f Support for parameters in internationalized `i18n:msg` content. See #129.
cmlenz
parents: 762
diff changeset
996 self.values[param] = (kind, data, pos)
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
997 else:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
998 if kind is START:
854
0d9e87c6cf6e More work on reducing the size of the diff produced by 2to3.
cmlenz
parents: 853
diff changeset
999 self.string.append('[%d:' % self.order)
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1000 self.stack.append(self.order)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1001 self.events.setdefault(self.stack[-1],
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1002 []).append((kind, data, pos))
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1003 self.depth += 1
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1004 self.order += 1
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1005 elif kind is END:
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1006 self.depth -= 1
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1007 if self.depth:
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1008 self.events[self.stack[-1]].append((kind, data, pos))
854
0d9e87c6cf6e More work on reducing the size of the diff produced by 2to3.
cmlenz
parents: 853
diff changeset
1009 self.string.append(']')
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1010 self.stack.pop()
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1011
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1012 def format(self):
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1013 """Return a message identifier representing the content in the
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1014 buffer.
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1015 """
854
0d9e87c6cf6e More work on reducing the size of the diff produced by 2to3.
cmlenz
parents: 853
diff changeset
1016 return ''.join(self.string).strip()
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1017
775
f0f1416a814f Support for parameters in internationalized `i18n:msg` content. See #129.
cmlenz
parents: 762
diff changeset
1018 def translate(self, string, regex=re.compile(r'%\((\w+)\)s')):
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1019 """Interpolate the given message translation with the events in the
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1020 buffer and return the translated stream.
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1021
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1022 :param string: the translated message string
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1023 """
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1024 substream = None
895
f30c9fb10272 i18n: some cleanup, especially for the pluralization directives.
cmlenz
parents: 892
diff changeset
1025
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1026 def yield_parts(string):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1027 for idx, part in enumerate(regex.split(string)):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1028 if idx % 2:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1029 yield self.values[part]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1030 elif part:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1031 yield (TEXT,
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1032 part.replace('\[', '[').replace('\]', ']'),
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1033 (None, -1, -1)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1034 )
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1035
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1036 parts = parse_msg(string)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1037 parts_counter = {}
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1038 for order, string in parts:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1039 parts_counter.setdefault(order, []).append(None)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1040
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1041 while parts:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1042 order, string = parts.pop(0)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1043 if len(parts_counter[order]) == 1:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1044 events = self.events[order]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1045 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1046 events = [self.events[order].pop(0)]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1047 parts_counter[order].pop()
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1048
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1049 for event in events:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1050 if event[0] is SUB_START:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1051 substream = []
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1052 elif event[0] is SUB_END:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1053 # Yield a substream which might have directives to be
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1054 # applied to it (after translation events)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1055 yield SUB, (self.subdirectives[order], substream), event[2]
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1056 substream = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1057 elif event[0] is TEXT:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1058 if string:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1059 for part in yield_parts(string):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1060 if substream is not None:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1061 substream.append(part)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1062 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1063 yield part
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1064 # String handled, reset it
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1065 string = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1066 elif event[0] is START:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1067 if substream is not None:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1068 substream.append(event)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1069 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1070 yield event
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1071 if string:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1072 for part in yield_parts(string):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1073 if substream is not None:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1074 substream.append(part)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1075 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1076 yield part
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1077 # String handled, reset it
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1078 string = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1079 elif event[0] is END:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1080 if string:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1081 for part in yield_parts(string):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1082 if substream is not None:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1083 substream.append(part)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1084 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1085 yield part
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1086 # String handled, reset it
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1087 string = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1088 if substream is not None:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1089 substream.append(event)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1090 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1091 yield event
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1092 elif event[0] is EXPR:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1093 # These are handled on the strings itself
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1094 continue
775
f0f1416a814f Support for parameters in internationalized `i18n:msg` content. See #129.
cmlenz
parents: 762
diff changeset
1095 else:
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1096 if string:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1097 for part in yield_parts(string):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1098 if substream is not None:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1099 substream.append(part)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1100 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1101 yield part
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1102 # String handled, reset it
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1103 string = None
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1104 if substream is not None:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1105 substream.append(event)
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1106 else:
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1107 yield event
560
f227a2f12e5f Start implementation of advanced I18n as dicussed in #129 and the MailingList. This is not complete yet, but many simple cases work okay.
cmlenz
parents: 549
diff changeset
1108
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
1109
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1110 def parse_msg(string, regex=re.compile(r'(?:\[(\d+)\:)|(?<!\\)\]')):
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1111 """Parse a translated message using Genshi mixed content message
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1112 formatting.
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1113
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1114 >>> parse_msg("See [1:Help].")
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1115 [(0, 'See '), (1, 'Help'), (0, '.')]
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1116
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1117 >>> parse_msg("See [1:our [2:Help] page] for details.")
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1118 [(0, 'See '), (1, 'our '), (2, 'Help'), (1, ' page'), (0, ' for details.')]
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1119
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1120 >>> parse_msg("[2:Details] finden Sie in [1:Hilfe].")
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1121 [(2, 'Details'), (0, ' finden Sie in '), (1, 'Hilfe'), (0, '.')]
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1122
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1123 >>> parse_msg("[1:] Bilder pro Seite anzeigen.")
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1124 [(1, ''), (0, ' Bilder pro Seite anzeigen.')]
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1125
738
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1126 :param string: the translated message string
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1127 :return: a list of ``(order, string)`` tuples
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1128 :rtype: `list`
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1129 """
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1130 parts = []
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1131 stack = [0]
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1132 while True:
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1133 mo = regex.search(string)
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1134 if not mo:
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1135 break
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1136
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1137 if mo.start() or stack[-1]:
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1138 parts.append((stack[-1], string[:mo.start()]))
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1139 string = string[mo.end():]
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1140
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1141 orderno = mo.group(1)
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1142 if orderno is not None:
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1143 stack.append(int(orderno))
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1144 else:
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1145 stack.pop()
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1146 if not stack:
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1147 break
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1148
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1149 if string:
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1150 parts.append((stack[-1], string))
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1151
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1152 return parts
4b7e2aa518af Minor cleanup in the i18n module.
cmlenz
parents: 667
diff changeset
1153
776
9e0ba5b9693c Added tests for the parameter support added to advanced internationalization in [901]. See #129.
cmlenz
parents: 775
diff changeset
1154
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1155 def extract_from_code(code, gettext_functions):
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1156 """Extract strings from Python bytecode.
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1157
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1158 >>> from genshi.template.eval import Expression
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1159 >>> expr = Expression('_("Hello")')
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
1160 >>> list(extract_from_code(expr, GETTEXT_FUNCTIONS))
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1161 [('_', u'Hello')]
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1162
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1163 >>> expr = Expression('ngettext("You have %(num)s item", '
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1164 ... '"You have %(num)s items", num)')
892
1de952fd479e i18n: Support extraction of attributes in markup embedded in ``i18n:msg`` and ``i18n:choose`` directives. See also #380.
cmlenz
parents: 891
diff changeset
1165 >>> list(extract_from_code(expr, GETTEXT_FUNCTIONS))
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1166 [('ngettext', (u'You have %(num)s item', u'You have %(num)s items', None))]
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1167
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1168 :param code: the `Code` object
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1169 :type code: `genshi.template.eval.Code`
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1170 :param gettext_functions: a sequence of function names
576
53f4088e1e3b Improve docs on `Stream.select()` for #135.
cmlenz
parents: 565
diff changeset
1171 :since: version 0.5
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1172 """
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1173 def _walk(node):
794
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1174 if isinstance(node, _ast.Call) and isinstance(node.func, _ast.Name) \
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1175 and node.func.id in gettext_functions:
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1176 strings = []
600
0d802a7e3630 Handle starargs and dstarargs in the I18n extraction code.
cmlenz
parents: 596
diff changeset
1177 def _add(arg):
916
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
1178 if isinstance(arg, _ast.Str) and isinstance(arg.s, unicode):
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
1179 strings.append(arg.s)
872726bac135 add support for python 3 to genshi.filters:
hodgestar
parents: 897
diff changeset
1180 elif isinstance(arg, _ast.Str):
794
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1181 strings.append(unicode(arg.s, 'utf-8'))
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1182 elif arg:
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1183 strings.append(None)
600
0d802a7e3630 Handle starargs and dstarargs in the I18n extraction code.
cmlenz
parents: 596
diff changeset
1184 [_add(arg) for arg in node.args]
794
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1185 _add(node.starargs)
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1186 _add(node.kwargs)
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1187 if len(strings) == 1:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1188 strings = strings[0]
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1189 else:
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1190 strings = tuple(strings)
794
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1191 yield node.func.id, strings
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1192 elif node._fields:
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1193 children = []
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1194 for field in node._fields:
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1195 child = getattr(node, field, None)
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1196 if isinstance(child, list):
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1197 for elem in child:
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1198 children.append(elem)
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1199 elif isinstance(child, _ast.AST):
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1200 children.append(child)
ada9d53ea751 Merged AST branch back into trunk. Most of this code was written by Marcin Kurczych for his Google Summer of Code 2008 project. The merge of this branch means that Genshi now uses the native `_ast` module on Python >= 2.5, and an emulation thereof on Python 2.4. This replaces the usage of the `compiler` package, which was deprecated in Python 2.6 and removed in Python 3.0. Another effect is that Genshi now runs on Google AppEngine (although performance is bad due to the lack of template caching).
cmlenz
parents: 790
diff changeset
1201 for child in children:
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1202 for funcname, strings in _walk(child):
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1203 yield funcname, strings
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 561
diff changeset
1204 return _walk(code.ast)
561
3225bb74c672 Move code for extracting messages from bytecode into a separate function.
cmlenz
parents: 560
diff changeset
1205
776
9e0ba5b9693c Added tests for the parameter support added to advanced internationalization in [901]. See #129.
cmlenz
parents: 775
diff changeset
1206
528
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1207 def extract(fileobj, keywords, comment_tags, options):
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1208 """Babel extraction method for Genshi templates.
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1209
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1210 :param fileobj: the file-like object the messages should be extracted from
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1211 :param keywords: a list of keywords (i.e. function names) that should be
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1212 recognized as translation functions
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1213 :param comment_tags: a list of translator tags to search for and include
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1214 in the results
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1215 :param options: a dictionary of additional options (optional)
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1216 :return: an iterator over ``(lineno, funcname, message, comments)`` tuples
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1217 :rtype: ``iterator``
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1218 """
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1219 template_class = options.get('template_class', MarkupTemplate)
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1220 if isinstance(template_class, basestring):
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1221 module, clsname = template_class.split(':', 1)
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1222 template_class = getattr(__import__(module, {}, {}, [clsname]), clsname)
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1223 encoding = options.get('encoding', None)
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1224
596
f436c7db99f5 Follow-up to [708]. The added `extract_text` option wasn't actually being handled by the Babel extraction plugin.
cmlenz
parents: 594
diff changeset
1225 extract_text = options.get('extract_text', True)
f436c7db99f5 Follow-up to [708]. The added `extract_text` option wasn't actually being handled by the Babel extraction plugin.
cmlenz
parents: 594
diff changeset
1226 if isinstance(extract_text, basestring):
f436c7db99f5 Follow-up to [708]. The added `extract_text` option wasn't actually being handled by the Babel extraction plugin.
cmlenz
parents: 594
diff changeset
1227 extract_text = extract_text.lower() in ('1', 'on', 'yes', 'true')
f436c7db99f5 Follow-up to [708]. The added `extract_text` option wasn't actually being handled by the Babel extraction plugin.
cmlenz
parents: 594
diff changeset
1228
528
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1229 ignore_tags = options.get('ignore_tags', Translator.IGNORE_TAGS)
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1230 if isinstance(ignore_tags, basestring):
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1231 ignore_tags = ignore_tags.split()
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1232 ignore_tags = [QName(tag) for tag in ignore_tags]
596
f436c7db99f5 Follow-up to [708]. The added `extract_text` option wasn't actually being handled by the Babel extraction plugin.
cmlenz
parents: 594
diff changeset
1233
528
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1234 include_attrs = options.get('include_attrs', Translator.INCLUDE_ATTRS)
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1235 if isinstance(include_attrs, basestring):
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1236 include_attrs = include_attrs.split()
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1237 include_attrs = [QName(attr) for attr in include_attrs]
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1238
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1239 tmpl = template_class(fileobj, filename=getattr(fileobj, 'name', None),
f38ce008ab0a Integrated [http://babel.edgewall.org/ Babel] message extraction plugin, and added I18n doc page.
cmlenz
parents: 522
diff changeset
1240 encoding=encoding)
882
6f49c23045b1 Fix regression in [1099]: templates must not have an implicit loader during message extraction.
cmlenz
parents: 873
diff changeset
1241 tmpl.loader = None
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1242
596
f436c7db99f5 Follow-up to [708]. The added `extract_text` option wasn't actually being handled by the Babel extraction plugin.
cmlenz
parents: 594
diff changeset
1243 translator = Translator(None, ignore_tags, include_attrs, extract_text)
849
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1244 if hasattr(tmpl, 'add_directives'):
e43633b320db Merged advanced-i18n branch back into trunk.
cmlenz
parents: 794
diff changeset
1245 tmpl.add_directives(Translator.NAMESPACE, translator)
787
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
1246 for message in translator.extract(tmpl.stream, gettext_functions=keywords):
422a9dd01e9f Add support for supplying comments on localizable messages in the i18n filter. Based on patch by Pedro Algarvio on #129.
cmlenz
parents: 785
diff changeset
1247 yield message
Copyright (C) 2012-2017 Edgewall Software