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