annotate genshi/filters/i18n.py @ 500:0742f421caba experimental-inline

Merged revisions 487-603 via svnmerge from http://svn.edgewall.org/repos/genshi/trunk
author cmlenz
date Fri, 01 Jun 2007 17:21:47 +0000
parents
children 1837f39efd6f
rev   line source
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
1 """Utilities for internationalization and localization of templates."""
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
2
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
3 try:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
4 frozenset
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
5 except NameError:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
6 from sets import ImmutableSet as frozenset
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
7 from gettext import gettext
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
8 from opcode import opmap
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
9 import re
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
10
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
11 from genshi.core import Attrs, Namespace, QName, START, END, TEXT, _ensure
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
12 from genshi.template.base import Template, EXPR, SUB
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
13 from genshi.template.markup import EXEC
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
14
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
15 _LOAD_NAME = chr(opmap['LOAD_NAME'])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
16 _LOAD_CONST = chr(opmap['LOAD_CONST'])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
17 _CALL_FUNCTION = chr(opmap['CALL_FUNCTION'])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
18 _BINARY_ADD = chr(opmap['BINARY_ADD'])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
19
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
20
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
21 class Translator(object):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
22 """Can extract and translate localizable strings from markup streams and
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
23 templates.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
24
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
25 For example, assume the followng template:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
26
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
27 >>> from genshi.template import MarkupTemplate
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
28 >>>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
29 >>> tmpl = MarkupTemplate('''<html xmlns:py="http://genshi.edgewall.org/">
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
30 ... <head>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
31 ... <title>Example</title>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
32 ... </head>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
33 ... <body>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
34 ... <h1>Example</h1>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
35 ... <p>${_("Hello, %(name)s") % dict(name=username)}</p>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
36 ... </body>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
37 ... </html>''', filename='example.html')
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
38
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
39 For demonstration, we define a dummy ``gettext``-style function with a
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
40 hard-coded translation table, and pass that to the `Translator` initializer:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
41
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
42 >>> def pseudo_gettext(string):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
43 ... return {
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
44 ... 'Example': 'Beispiel',
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
45 ... 'Hello, %(name)s': 'Hallo, %(name)s'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
46 ... }[string]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
47 >>>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
48 >>> translator = Translator(pseudo_gettext)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
49
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
50 Next, the translator needs to be prepended to any already defined filters
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
51 on the template:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
52
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
53 >>> tmpl.filters.insert(0, translator)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
54
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
55 When generating the template output, our hard-coded translations should be
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
56 applied as expected:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
57
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
58 >>> print tmpl.generate(username='Hans', _=pseudo_gettext)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
59 <html>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
60 <head>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
61 <title>Beispiel</title>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
62 </head>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
63 <body>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
64 <h1>Beispiel</h1>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
65 <p>Hallo, Hans</p>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
66 </body>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
67 </html>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
68 """
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
69
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
70 IGNORE_TAGS = frozenset([
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
71 QName('script'), QName('http://www.w3.org/1999/xhtml}script'),
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
72 QName('style'), QName('http://www.w3.org/1999/xhtml}style')
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
73 ])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
74 INCLUDE_ATTRS = frozenset(['abbr', 'alt', 'label', 'prompt', 'standby',
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
75 'summary', 'title'])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
76
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
77 def __init__(self, translate=gettext, ignore_tags=IGNORE_TAGS,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
78 include_attrs=INCLUDE_ATTRS):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
79 """Initialize the translator.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
80
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
81 :param translate: the translation function, for example ``gettext`` or
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
82 ``ugettext``.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
83 :param ignore_tags: a set of tag names that should not be localized
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
84 :param include_attrs: a set of attribute names should be localized
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
85 """
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
86 self.translate = translate
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
87 self.ignore_tags = ignore_tags
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
88 self.include_attrs = include_attrs
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
89
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
90 def __call__(self, stream, ctxt=None, search_text=True):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
91 """Translate any localizable strings in the given stream.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
92
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
93 This function shouldn't be called directly. Instead, an instance of
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
94 the `Translator` class should be registered as a filter with the
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
95 `Template` or the `TemplateLoader`, or applied as a regular stream
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
96 filter. If used as a template filter, it should be inserted in front of
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
97 all the default filters.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
98
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
99 :param stream: the markup event stream
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
100 :param ctxt: the template context (not used)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
101 :param search_text: whether text nodes should be translated (used
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
102 internally)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
103 :return: the localized stream
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
104 """
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
105 ignore_tags = self.ignore_tags
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
106 include_attrs = self.include_attrs
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
107 translate = self.translate
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
108 skip = 0
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
109
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
110 for kind, data, pos in stream:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
111
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
112 # skip chunks that should not be localized
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
113 if skip:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
114 if kind is START:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
115 tag, attrs = data
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
116 if tag in ignore_tags:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
117 skip += 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
118 elif kind is END:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
119 if tag in ignore_tags:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
120 skip -= 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
121 yield kind, data, pos
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
122 continue
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
123
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
124 # handle different events that can be localized
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
125 if kind is START:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
126 tag, attrs = data
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
127 if tag in ignore_tags:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
128 skip += 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
129 yield kind, data, pos
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
130 continue
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
131
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
132 new_attrs = []
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
133 changed = False
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
134 for name, value in attrs:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
135 newval = value
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
136 if isinstance(value, basestring):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
137 if name in include_attrs:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
138 newval = self.translate(value)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
139 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
140 newval = list(self(_ensure(value), ctxt,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
141 search_text=name in include_attrs)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
142 )
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
143 if newval != value:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
144 value = newval
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
145 changed = True
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
146 new_attrs.append((name, value))
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
147 if changed:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
148 attrs = new_attrs
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
149
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
150 yield kind, (tag, attrs), pos
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
151
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
152 elif search_text and kind is TEXT:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
153 text = data.strip()
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
154 if text:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
155 data = data.replace(text, translate(text))
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
156 yield kind, data, pos
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
157
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
158 elif kind is SUB:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
159 subkind, substream = data
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
160 new_substream = list(self(substream, ctxt))
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
161 yield kind, (subkind, new_substream), pos
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
162
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
163 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
164 yield kind, data, pos
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
165
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
166 GETTEXT_FUNCTIONS = ('_', 'gettext', 'ngettext', 'dgettext', 'dngettext',
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
167 'ugettext', 'ungettext')
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
168
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
169 def extract(self, stream, gettext_functions=GETTEXT_FUNCTIONS,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
170 search_text=True):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
171 """Extract localizable strings from the given template stream.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
172
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
173 For every string found, this function yields a ``(lineno, function,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
174 message)`` tuple, where:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
175
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
176 * ``lineno`` is the number of the line on which the string was found,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
177 * ``function`` is the name of the ``gettext`` function used (if the
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
178 string was extracted from embedded Python code), and
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
179 * ``message`` is the string itself (a ``unicode`` object, or a tuple
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
180 of ``unicode`` objects for functions with multiple string arguments).
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
181
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
182 >>> from genshi.template import MarkupTemplate
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
183 >>>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
184 >>> tmpl = MarkupTemplate('''<html xmlns:py="http://genshi.edgewall.org/">
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
185 ... <head>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
186 ... <title>Example</title>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
187 ... </head>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
188 ... <body>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
189 ... <h1>Example</h1>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
190 ... <p>${_("Hello, %(name)s") % dict(name=username)}</p>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
191 ... <p>${ngettext("You have %d item", "You have %d items", num)}</p>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
192 ... </body>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
193 ... </html>''', filename='example.html')
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
194 >>>
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
195 >>> for lineno, funcname, message in Translator().extract(tmpl.stream):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
196 ... print "%d, %r, %r" % (lineno, funcname, message)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
197 3, None, u'Example'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
198 6, None, u'Example'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
199 7, '_', u'Hello, %(name)s'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
200 8, 'ngettext', (u'You have %d item', u'You have %d items')
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
201
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
202 :param stream: the event stream to extract strings from; can be a
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
203 regular stream or a template stream
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
204 :param gettext_functions: a sequence of function names that should be
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
205 treated as gettext-style localization
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
206 functions
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
207 :param search_text: whether the content of text nodes should be
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
208 extracted (used internally)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
209
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
210 :note: Changed in 0.4.1: For a function with multiple string arguments
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
211 (such as ``ngettext``), a single item with a tuple of strings is
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
212 yielded, instead an item for each string argument.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
213 """
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
214 tagname = None
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
215 skip = 0
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
216
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
217 for kind, data, pos in stream:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
218 if skip:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
219 if kind is START:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
220 tag, attrs = data
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
221 if tag in self.ignore_tags:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
222 skip += 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
223 if kind is END:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
224 tag = data
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
225 if tag in self.ignore_tags:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
226 skip -= 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
227 continue
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
228
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
229 if kind is START:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
230 tag, attrs = data
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
231 if tag in self.ignore_tags:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
232 skip += 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
233 continue
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
234
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
235 for name, value in attrs:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
236 if isinstance(value, basestring):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
237 if name in self.include_attrs:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
238 text = value.strip()
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
239 if text:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
240 yield pos[1], None, text
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
241 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
242 for lineno, funcname, text in self.extract(
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
243 _ensure(value), gettext_functions,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
244 search_text=name in self.include_attrs):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
245 yield lineno, funcname, text
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
246
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
247 elif search_text and kind is TEXT:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
248 text = data.strip()
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
249 if text and filter(None, [ch.isalpha() for ch in text]):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
250 yield pos[1], None, text
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
251
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
252 elif kind is EXPR or kind is EXEC:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
253 consts = dict([(n, chr(i) + '\x00') for i, n in
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
254 enumerate(data.code.co_consts)])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
255 gettext_locs = [consts[n] for n in gettext_functions
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
256 if n in consts]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
257 ops = [
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
258 _LOAD_CONST, '(', '|'.join(gettext_locs), ')',
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
259 _CALL_FUNCTION, '.\x00',
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
260 '((?:', _BINARY_ADD, '|', _LOAD_CONST, '.\x00)+)'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
261 ]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
262 for loc, opcodes in re.findall(''.join(ops), data.code.co_code):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
263 funcname = data.code.co_consts[ord(loc[0])]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
264 strings = []
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
265 opcodes = iter(opcodes)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
266 for opcode in opcodes:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
267 if opcode == _BINARY_ADD:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
268 arg = strings.pop()
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
269 strings[-1] += arg
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
270 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
271 arg = data.code.co_consts[ord(opcodes.next())]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
272 opcodes.next() # skip second byte
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
273 if not isinstance(arg, basestring):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
274 break
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
275 strings.append(unicode(arg))
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
276 if len(strings) == 1:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
277 strings = strings[0]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
278 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
279 strings = tuple(strings)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
280 yield pos[1], funcname, strings
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
281
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
282 elif kind is SUB:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
283 subkind, substream = data
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
284 for lineno, funcname, text in self.extract(substream,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
285 gettext_functions):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
286 yield lineno, funcname, text
Copyright (C) 2012-2017 Edgewall Software