comparison genshi/filters/tests/i18n.py @ 902:09cc3627654c experimental-inline

Sync `experimental/inline` branch with [source:trunk@1126].
author cmlenz
date Fri, 23 Apr 2010 21:08:26 +0000
parents 1837f39efd6f
children
comparison
equal deleted inserted replaced
830:de82830f8816 902:09cc3627654c
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 # 2 #
3 # Copyright (C) 2007-2008 Edgewall Software 3 # Copyright (C) 2007-2010 Edgewall Software
4 # All rights reserved. 4 # All rights reserved.
5 # 5 #
6 # This software is licensed as described in the file COPYING, which 6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution. The terms 7 # you should have received as part of this distribution. The terms
8 # are also available at http://genshi.edgewall.org/wiki/License. 8 # are also available at http://genshi.edgewall.org/wiki/License.
16 from gettext import NullTranslations 16 from gettext import NullTranslations
17 from StringIO import StringIO 17 from StringIO import StringIO
18 import unittest 18 import unittest
19 19
20 from genshi.core import Attrs 20 from genshi.core import Attrs
21 from genshi.template import MarkupTemplate 21 from genshi.template import MarkupTemplate, Context
22 from genshi.filters.i18n import Translator, extract 22 from genshi.filters.i18n import Translator, extract
23 from genshi.input import HTML 23 from genshi.input import HTML
24 24
25 25
26 class DummyTranslations(NullTranslations): 26 class DummyTranslations(NullTranslations):
27 27 _domains = {}
28 def __init__(self, catalog): 28
29 def __init__(self, catalog=()):
29 NullTranslations.__init__(self) 30 NullTranslations.__init__(self)
30 self._catalog = catalog 31 self._catalog = catalog or {}
32 self.plural = lambda n: n != 1
33
34 def add_domain(self, domain, catalog):
35 translation = DummyTranslations(catalog)
36 translation.add_fallback(self)
37 self._domains[domain] = translation
38
39 def _domain_call(self, func, domain, *args, **kwargs):
40 return getattr(self._domains.get(domain, self), func)(*args, **kwargs)
31 41
32 def ugettext(self, message): 42 def ugettext(self, message):
33 missing = object() 43 missing = object()
34 tmsg = self._catalog.get(message, missing) 44 tmsg = self._catalog.get(message, missing)
35 if tmsg is missing: 45 if tmsg is missing:
36 if self._fallback: 46 if self._fallback:
37 return self._fallback.ugettext(message) 47 return self._fallback.ugettext(message)
38 return unicode(message) 48 return unicode(message)
39 return tmsg 49 return tmsg
40 50
51 def dugettext(self, domain, message):
52 return self._domain_call('ugettext', domain, message)
53
54 def ungettext(self, msgid1, msgid2, n):
55 try:
56 return self._catalog[(msgid1, self.plural(n))]
57 except KeyError:
58 if self._fallback:
59 return self._fallback.ngettext(msgid1, msgid2, n)
60 if n == 1:
61 return msgid1
62 else:
63 return msgid2
64
65 def dungettext(self, domain, singular, plural, numeral):
66 return self._domain_call('ungettext', domain, singular, plural, numeral)
67
41 68
42 class TranslatorTestCase(unittest.TestCase): 69 class TranslatorTestCase(unittest.TestCase):
43 70
44 def test_translate_included_attribute_text(self): 71 def test_translate_included_attribute_text(self):
45 """ 72 """
59 ${ngettext("Singular", "Plural", num)} 86 ${ngettext("Singular", "Plural", num)}
60 </html>""") 87 </html>""")
61 translator = Translator(extract_text=False) 88 translator = Translator(extract_text=False)
62 messages = list(translator.extract(tmpl.stream)) 89 messages = list(translator.extract(tmpl.stream))
63 self.assertEqual(1, len(messages)) 90 self.assertEqual(1, len(messages))
64 self.assertEqual((3, 'ngettext', (u'Singular', u'Plural', None), []), 91 self.assertEqual((3, 'ngettext', ('Singular', 'Plural', None), []),
65 messages[0]) 92 messages[0])
66 93
67 def test_extract_plural_form(self): 94 def test_extract_plural_form(self):
68 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"> 95 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
69 ${ngettext("Singular", "Plural", num)} 96 ${ngettext("Singular", "Plural", num)}
70 </html>""") 97 </html>""")
71 translator = Translator() 98 translator = Translator()
72 messages = list(translator.extract(tmpl.stream)) 99 messages = list(translator.extract(tmpl.stream))
73 self.assertEqual(1, len(messages)) 100 self.assertEqual(1, len(messages))
74 self.assertEqual((2, 'ngettext', (u'Singular', u'Plural', None), []), 101 self.assertEqual((2, 'ngettext', ('Singular', 'Plural', None), []),
75 messages[0]) 102 messages[0])
76 103
77 def test_extract_funky_plural_form(self): 104 def test_extract_funky_plural_form(self):
78 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"> 105 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
79 ${ngettext(len(items), *widget.display_names)} 106 ${ngettext(len(items), *widget.display_names)}
97 <span title="Foo"></span> 124 <span title="Foo"></span>
98 </html>""") 125 </html>""")
99 translator = Translator() 126 translator = Translator()
100 messages = list(translator.extract(tmpl.stream)) 127 messages = list(translator.extract(tmpl.stream))
101 self.assertEqual(1, len(messages)) 128 self.assertEqual(1, len(messages))
102 self.assertEqual((2, None, u'Foo', []), messages[0]) 129 self.assertEqual((2, None, 'Foo', []), messages[0])
103 130
104 def test_extract_attribute_expr(self): 131 def test_extract_attribute_expr(self):
105 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"> 132 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
106 <input type="submit" value="${_('Save')}" /> 133 <input type="submit" value="${_('Save')}" />
107 </html>""") 134 </html>""")
108 translator = Translator() 135 translator = Translator()
109 messages = list(translator.extract(tmpl.stream)) 136 messages = list(translator.extract(tmpl.stream))
110 self.assertEqual(1, len(messages)) 137 self.assertEqual(1, len(messages))
111 self.assertEqual((2, '_', u'Save', []), messages[0]) 138 self.assertEqual((2, '_', 'Save', []), messages[0])
112 139
113 def test_extract_non_included_attribute_interpolated(self): 140 def test_extract_non_included_attribute_interpolated(self):
114 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"> 141 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
115 <a href="#anchor_${num}">Foo</a> 142 <a href="#anchor_${num}">Foo</a>
116 </html>""") 143 </html>""")
117 translator = Translator() 144 translator = Translator()
118 messages = list(translator.extract(tmpl.stream)) 145 messages = list(translator.extract(tmpl.stream))
119 self.assertEqual(1, len(messages)) 146 self.assertEqual(1, len(messages))
120 self.assertEqual((2, None, u'Foo', []), messages[0]) 147 self.assertEqual((2, None, 'Foo', []), messages[0])
121 148
122 def test_extract_text_from_sub(self): 149 def test_extract_text_from_sub(self):
123 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"> 150 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
124 <py:if test="foo">Foo</py:if> 151 <py:if test="foo">Foo</py:if>
125 </html>""") 152 </html>""")
126 translator = Translator() 153 translator = Translator()
127 messages = list(translator.extract(tmpl.stream)) 154 messages = list(translator.extract(tmpl.stream))
128 self.assertEqual(1, len(messages)) 155 self.assertEqual(1, len(messages))
129 self.assertEqual((2, None, u'Foo', []), messages[0]) 156 self.assertEqual((2, None, 'Foo', []), messages[0])
130 157
131 def test_ignore_tag_with_fixed_xml_lang(self): 158 def test_ignore_tag_with_fixed_xml_lang(self):
132 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"> 159 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
133 <p xml:lang="en">(c) 2007 Edgewall Software</p> 160 <p xml:lang="en">(c) 2007 Edgewall Software</p>
134 </html>""") 161 </html>""")
141 <p xml:lang="${lang}">(c) 2007 Edgewall Software</p> 168 <p xml:lang="${lang}">(c) 2007 Edgewall Software</p>
142 </html>""") 169 </html>""")
143 translator = Translator() 170 translator = Translator()
144 messages = list(translator.extract(tmpl.stream)) 171 messages = list(translator.extract(tmpl.stream))
145 self.assertEqual(1, len(messages)) 172 self.assertEqual(1, len(messages))
146 self.assertEqual((2, None, u'(c) 2007 Edgewall Software', []), 173 self.assertEqual((2, None, '(c) 2007 Edgewall Software', []),
147 messages[0]) 174 messages[0])
148 175
149 def test_ignore_attribute_with_expression(self): 176 def test_ignore_attribute_with_expression(self):
150 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"> 177 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/">
151 <input type="submit" value="Reply" title="Reply to comment $num" /> 178 <input type="submit" value="Reply" title="Reply to comment $num" />
152 </html>""") 179 </html>""")
153 translator = Translator() 180 translator = Translator()
154 messages = list(translator.extract(tmpl.stream)) 181 messages = list(translator.extract(tmpl.stream))
155 self.assertEqual(0, len(messages)) 182 self.assertEqual(0, len(messages))
156 183
184 def test_translate_with_translations_object(self):
185 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
186 xmlns:i18n="http://genshi.edgewall.org/i18n">
187 <p i18n:msg="" i18n:comment="As in foo bar">Foo</p>
188 </html>""")
189 translator = Translator(DummyTranslations({'Foo': 'Voh'}))
190 translator.setup(tmpl)
191 self.assertEqual("""<html>
192 <p>Voh</p>
193 </html>""", tmpl.generate().render())
194
195
196 class MsgDirectiveTestCase(unittest.TestCase):
197
157 def test_extract_i18n_msg(self): 198 def test_extract_i18n_msg(self):
158 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" 199 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
159 xmlns:i18n="http://genshi.edgewall.org/i18n"> 200 xmlns:i18n="http://genshi.edgewall.org/i18n">
160 <p i18n:msg=""> 201 <p i18n:msg="">
161 Please see <a href="help.html">Help</a> for details. 202 Please see <a href="help.html">Help</a> for details.
162 </p> 203 </p>
163 </html>""") 204 </html>""")
164 translator = Translator() 205 translator = Translator()
206 tmpl.add_directives(Translator.NAMESPACE, translator)
165 messages = list(translator.extract(tmpl.stream)) 207 messages = list(translator.extract(tmpl.stream))
166 self.assertEqual(1, len(messages)) 208 self.assertEqual(1, len(messages))
167 self.assertEqual('Please see [1:Help] for details.', messages[0][2]) 209 self.assertEqual('Please see [1:Help] for details.', messages[0][2])
168 210
169 def test_translate_i18n_msg(self): 211 def test_translate_i18n_msg(self):
173 Please see <a href="help.html">Help</a> for details. 215 Please see <a href="help.html">Help</a> for details.
174 </p> 216 </p>
175 </html>""") 217 </html>""")
176 gettext = lambda s: u"Für Details siehe bitte [1:Hilfe]." 218 gettext = lambda s: u"Für Details siehe bitte [1:Hilfe]."
177 translator = Translator(gettext) 219 translator = Translator(gettext)
178 tmpl.filters.insert(0, translator) 220 translator.setup(tmpl)
179 tmpl.add_directives(Translator.NAMESPACE, translator)
180 self.assertEqual("""<html> 221 self.assertEqual("""<html>
181 <p>Für Details siehe bitte <a href="help.html">Hilfe</a>.</p> 222 <p>Für Details siehe bitte <a href="help.html">Hilfe</a>.</p>
182 </html>""", tmpl.generate().render()) 223 </html>""", tmpl.generate().render())
224
225 def test_extract_i18n_msg_nonewline(self):
226 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
227 xmlns:i18n="http://genshi.edgewall.org/i18n">
228 <p i18n:msg="">Please see <a href="help.html">Help</a></p>
229 </html>""")
230 translator = Translator()
231 tmpl.add_directives(Translator.NAMESPACE, translator)
232 messages = list(translator.extract(tmpl.stream))
233 self.assertEqual(1, len(messages))
234 self.assertEqual('Please see [1:Help]', messages[0][2])
235
236 def test_translate_i18n_msg_nonewline(self):
237 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
238 xmlns:i18n="http://genshi.edgewall.org/i18n">
239 <p i18n:msg="">Please see <a href="help.html">Help</a></p>
240 </html>""")
241 gettext = lambda s: u"Für Details siehe bitte [1:Hilfe]"
242 translator = Translator(gettext)
243 translator.setup(tmpl)
244 self.assertEqual("""<html>
245 <p>Für Details siehe bitte <a href="help.html">Hilfe</a></p>
246 </html>""", tmpl.generate().render())
247
248 def test_extract_i18n_msg_elt_nonewline(self):
249 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
250 xmlns:i18n="http://genshi.edgewall.org/i18n">
251 <i18n:msg>Please see <a href="help.html">Help</a></i18n:msg>
252 </html>""")
253 translator = Translator()
254 tmpl.add_directives(Translator.NAMESPACE, translator)
255 messages = list(translator.extract(tmpl.stream))
256 self.assertEqual(1, len(messages))
257 self.assertEqual('Please see [1:Help]', messages[0][2])
258
259 def test_translate_i18n_msg_elt_nonewline(self):
260 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
261 xmlns:i18n="http://genshi.edgewall.org/i18n">
262 <i18n:msg>Please see <a href="help.html">Help</a></i18n:msg>
263 </html>""")
264 gettext = lambda s: u"Für Details siehe bitte [1:Hilfe]"
265 translator = Translator(gettext)
266 translator.setup(tmpl)
267 self.assertEqual("""<html>
268 Für Details siehe bitte <a href="help.html">Hilfe</a>
269 </html>""", tmpl.generate().render())
270
271 def test_extract_i18n_msg_with_attributes(self):
272 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
273 xmlns:i18n="http://genshi.edgewall.org/i18n">
274 <p i18n:msg="" title="A helpful paragraph">
275 Please see <a href="help.html" title="Click for help">Help</a>
276 </p>
277 </html>""")
278 translator = Translator()
279 translator.setup(tmpl)
280 messages = list(translator.extract(tmpl.stream))
281 self.assertEqual(3, len(messages))
282 self.assertEqual('A helpful paragraph', messages[0][2])
283 self.assertEqual(3, messages[0][0])
284 self.assertEqual('Click for help', messages[1][2])
285 self.assertEqual(4, messages[1][0])
286 self.assertEqual('Please see [1:Help]', messages[2][2])
287 self.assertEqual(3, messages[2][0])
288
289 def test_translate_i18n_msg_with_attributes(self):
290 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
291 xmlns:i18n="http://genshi.edgewall.org/i18n">
292 <p i18n:msg="" title="A helpful paragraph">
293 Please see <a href="help.html" title="Click for help">Help</a>
294 </p>
295 </html>""")
296 translator = Translator(lambda msgid: {
297 'A helpful paragraph': 'Ein hilfreicher Absatz',
298 'Click for help': u'Klicken für Hilfe',
299 'Please see [1:Help]': u'Siehe bitte [1:Hilfe]'
300 }[msgid])
301 translator.setup(tmpl)
302 self.assertEqual(u"""<html>
303 <p title="Ein hilfreicher Absatz">Siehe bitte <a href="help.html" title="Klicken für Hilfe">Hilfe</a></p>
304 </html>""", tmpl.generate().render(encoding=None))
305
306 def test_extract_i18n_msg_with_dynamic_attributes(self):
307 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
308 xmlns:i18n="http://genshi.edgewall.org/i18n">
309 <p i18n:msg="" title="${_('A helpful paragraph')}">
310 Please see <a href="help.html" title="${_('Click for help')}">Help</a>
311 </p>
312 </html>""")
313 translator = Translator()
314 translator.setup(tmpl)
315 messages = list(translator.extract(tmpl.stream))
316 self.assertEqual(3, len(messages))
317 self.assertEqual('A helpful paragraph', messages[0][2])
318 self.assertEqual(3, messages[0][0])
319 self.assertEqual('Click for help', messages[1][2])
320 self.assertEqual(4, messages[1][0])
321 self.assertEqual('Please see [1:Help]', messages[2][2])
322 self.assertEqual(3, messages[2][0])
323
324 def test_translate_i18n_msg_with_dynamic_attributes(self):
325 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
326 xmlns:i18n="http://genshi.edgewall.org/i18n">
327 <p i18n:msg="" title="${_('A helpful paragraph')}">
328 Please see <a href="help.html" title="${_('Click for help')}">Help</a>
329 </p>
330 </html>""")
331 translator = Translator(lambda msgid: {
332 'A helpful paragraph': 'Ein hilfreicher Absatz',
333 'Click for help': u'Klicken für Hilfe',
334 'Please see [1:Help]': u'Siehe bitte [1:Hilfe]'
335 }[msgid])
336 translator.setup(tmpl)
337 self.assertEqual(u"""<html>
338 <p title="Ein hilfreicher Absatz">Siehe bitte <a href="help.html" title="Klicken für Hilfe">Hilfe</a></p>
339 </html>""", tmpl.generate(_=translator.translate).render(encoding=None))
340
341 def test_extract_i18n_msg_as_element_with_attributes(self):
342 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
343 xmlns:i18n="http://genshi.edgewall.org/i18n">
344 <i18n:msg params="">
345 Please see <a href="help.html" title="Click for help">Help</a>
346 </i18n:msg>
347 </html>""")
348 translator = Translator()
349 translator.setup(tmpl)
350 messages = list(translator.extract(tmpl.stream))
351 self.assertEqual(2, len(messages))
352 self.assertEqual('Click for help', messages[0][2])
353 self.assertEqual(4, messages[0][0])
354 self.assertEqual('Please see [1:Help]', messages[1][2])
355 self.assertEqual(3, messages[1][0])
356
357 def test_translate_i18n_msg_as_element_with_attributes(self):
358 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
359 xmlns:i18n="http://genshi.edgewall.org/i18n">
360 <i18n:msg params="">
361 Please see <a href="help.html" title="Click for help">Help</a>
362 </i18n:msg>
363 </html>""")
364 translator = Translator(lambda msgid: {
365 'Click for help': u'Klicken für Hilfe',
366 'Please see [1:Help]': u'Siehe bitte [1:Hilfe]'
367 }[msgid])
368 translator.setup(tmpl)
369 self.assertEqual(u"""<html>
370 Siehe bitte <a href="help.html" title="Klicken für Hilfe">Hilfe</a>
371 </html>""", tmpl.generate().render(encoding=None))
183 372
184 def test_extract_i18n_msg_nested(self): 373 def test_extract_i18n_msg_nested(self):
185 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" 374 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
186 xmlns:i18n="http://genshi.edgewall.org/i18n"> 375 xmlns:i18n="http://genshi.edgewall.org/i18n">
187 <p i18n:msg=""> 376 <p i18n:msg="">
188 Please see <a href="help.html"><em>Help</em> page</a> for details. 377 Please see <a href="help.html"><em>Help</em> page</a> for details.
189 </p> 378 </p>
190 </html>""") 379 </html>""")
191 translator = Translator() 380 translator = Translator()
381 tmpl.add_directives(Translator.NAMESPACE, translator)
192 messages = list(translator.extract(tmpl.stream)) 382 messages = list(translator.extract(tmpl.stream))
193 self.assertEqual(1, len(messages)) 383 self.assertEqual(1, len(messages))
194 self.assertEqual('Please see [1:[2:Help] page] for details.', 384 self.assertEqual('Please see [1:[2:Help] page] for details.',
195 messages[0][2]) 385 messages[0][2])
196 386
201 Please see <a href="help.html"><em>Help</em> page</a> for details. 391 Please see <a href="help.html"><em>Help</em> page</a> for details.
202 </p> 392 </p>
203 </html>""") 393 </html>""")
204 gettext = lambda s: u"Für Details siehe bitte [1:[2:Hilfeseite]]." 394 gettext = lambda s: u"Für Details siehe bitte [1:[2:Hilfeseite]]."
205 translator = Translator(gettext) 395 translator = Translator(gettext)
206 tmpl.filters.insert(0, translator) 396 translator.setup(tmpl)
207 tmpl.add_directives(Translator.NAMESPACE, translator)
208 self.assertEqual("""<html> 397 self.assertEqual("""<html>
209 <p>Für Details siehe bitte <a href="help.html"><em>Hilfeseite</em></a>.</p> 398 <p>Für Details siehe bitte <a href="help.html"><em>Hilfeseite</em></a>.</p>
399 </html>""", tmpl.generate().render())
400
401 def test_extract_i18n_msg_label_with_nested_input(self):
402 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
403 xmlns:i18n="http://genshi.edgewall.org/i18n">
404 <div i18n:msg="">
405 <label><input type="text" size="3" name="daysback" value="30" /> days back</label>
406 </div>
407 </html>""")
408 translator = Translator()
409 tmpl.add_directives(Translator.NAMESPACE, translator)
410 messages = list(translator.extract(tmpl.stream))
411 self.assertEqual(1, len(messages))
412 self.assertEqual('[1:[2:] days back]',
413 messages[0][2])
414
415 def test_translate_i18n_msg_label_with_nested_input(self):
416 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
417 xmlns:i18n="http://genshi.edgewall.org/i18n">
418 <div i18n:msg="">
419 <label><input type="text" size="3" name="daysback" value="30" /> foo bar</label>
420 </div>
421 </html>""")
422 gettext = lambda s: "[1:[2:] foo bar]"
423 translator = Translator(gettext)
424 translator.setup(tmpl)
425 self.assertEqual("""<html>
426 <div><label><input type="text" size="3" name="daysback" value="30"/> foo bar</label></div>
210 </html>""", tmpl.generate().render()) 427 </html>""", tmpl.generate().render())
211 428
212 def test_extract_i18n_msg_empty(self): 429 def test_extract_i18n_msg_empty(self):
213 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" 430 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
214 xmlns:i18n="http://genshi.edgewall.org/i18n"> 431 xmlns:i18n="http://genshi.edgewall.org/i18n">
215 <p i18n:msg=""> 432 <p i18n:msg="">
216 Show me <input type="text" name="num" /> entries per page. 433 Show me <input type="text" name="num" /> entries per page.
217 </p> 434 </p>
218 </html>""") 435 </html>""")
219 translator = Translator() 436 translator = Translator()
437 tmpl.add_directives(Translator.NAMESPACE, translator)
220 messages = list(translator.extract(tmpl.stream)) 438 messages = list(translator.extract(tmpl.stream))
221 self.assertEqual(1, len(messages)) 439 self.assertEqual(1, len(messages))
222 self.assertEqual('Show me [1:] entries per page.', messages[0][2]) 440 self.assertEqual('Show me [1:] entries per page.', messages[0][2])
223 441
224 def test_translate_i18n_msg_empty(self): 442 def test_translate_i18n_msg_empty(self):
228 Show me <input type="text" name="num" /> entries per page. 446 Show me <input type="text" name="num" /> entries per page.
229 </p> 447 </p>
230 </html>""") 448 </html>""")
231 gettext = lambda s: u"[1:] Einträge pro Seite anzeigen." 449 gettext = lambda s: u"[1:] Einträge pro Seite anzeigen."
232 translator = Translator(gettext) 450 translator = Translator(gettext)
233 tmpl.filters.insert(0, translator) 451 translator.setup(tmpl)
234 tmpl.add_directives(Translator.NAMESPACE, translator)
235 self.assertEqual("""<html> 452 self.assertEqual("""<html>
236 <p><input type="text" name="num"/> Einträge pro Seite anzeigen.</p> 453 <p><input type="text" name="num"/> Einträge pro Seite anzeigen.</p>
237 </html>""", tmpl.generate().render()) 454 </html>""", tmpl.generate().render())
238 455
239 def test_extract_i18n_msg_multiple(self): 456 def test_extract_i18n_msg_multiple(self):
242 <p i18n:msg=""> 459 <p i18n:msg="">
243 Please see <a href="help.html">Help</a> for <em>details</em>. 460 Please see <a href="help.html">Help</a> for <em>details</em>.
244 </p> 461 </p>
245 </html>""") 462 </html>""")
246 translator = Translator() 463 translator = Translator()
464 tmpl.add_directives(Translator.NAMESPACE, translator)
247 messages = list(translator.extract(tmpl.stream)) 465 messages = list(translator.extract(tmpl.stream))
248 self.assertEqual(1, len(messages)) 466 self.assertEqual(1, len(messages))
249 self.assertEqual('Please see [1:Help] for [2:details].', messages[0][2]) 467 self.assertEqual('Please see [1:Help] for [2:details].', messages[0][2])
250 468
251 def test_translate_i18n_msg_multiple(self): 469 def test_translate_i18n_msg_multiple(self):
255 Please see <a href="help.html">Help</a> for <em>details</em>. 473 Please see <a href="help.html">Help</a> for <em>details</em>.
256 </p> 474 </p>
257 </html>""") 475 </html>""")
258 gettext = lambda s: u"Für [2:Details] siehe bitte [1:Hilfe]." 476 gettext = lambda s: u"Für [2:Details] siehe bitte [1:Hilfe]."
259 translator = Translator(gettext) 477 translator = Translator(gettext)
260 tmpl.filters.insert(0, translator) 478 translator.setup(tmpl)
261 tmpl.add_directives(Translator.NAMESPACE, translator)
262 self.assertEqual("""<html> 479 self.assertEqual("""<html>
263 <p>Für <em>Details</em> siehe bitte <a href="help.html">Hilfe</a>.</p> 480 <p>Für <em>Details</em> siehe bitte <a href="help.html">Hilfe</a>.</p>
264 </html>""", tmpl.generate().render()) 481 </html>""", tmpl.generate().render())
265 482
266 def test_extract_i18n_msg_multiple_empty(self): 483 def test_extract_i18n_msg_multiple_empty(self):
269 <p i18n:msg=""> 486 <p i18n:msg="">
270 Show me <input type="text" name="num" /> entries per page, starting at page <input type="text" name="num" />. 487 Show me <input type="text" name="num" /> entries per page, starting at page <input type="text" name="num" />.
271 </p> 488 </p>
272 </html>""") 489 </html>""")
273 translator = Translator() 490 translator = Translator()
491 tmpl.add_directives(Translator.NAMESPACE, translator)
274 messages = list(translator.extract(tmpl.stream)) 492 messages = list(translator.extract(tmpl.stream))
275 self.assertEqual(1, len(messages)) 493 self.assertEqual(1, len(messages))
276 self.assertEqual('Show me [1:] entries per page, starting at page [2:].', 494 self.assertEqual('Show me [1:] entries per page, starting at page [2:].',
277 messages[0][2]) 495 messages[0][2])
278 496
283 Show me <input type="text" name="num" /> entries per page, starting at page <input type="text" name="num" />. 501 Show me <input type="text" name="num" /> entries per page, starting at page <input type="text" name="num" />.
284 </p> 502 </p>
285 </html>""") 503 </html>""")
286 gettext = lambda s: u"[1:] Einträge pro Seite, beginnend auf Seite [2:]." 504 gettext = lambda s: u"[1:] Einträge pro Seite, beginnend auf Seite [2:]."
287 translator = Translator(gettext) 505 translator = Translator(gettext)
288 tmpl.filters.insert(0, translator) 506 translator.setup(tmpl)
289 tmpl.add_directives(Translator.NAMESPACE, translator)
290 self.assertEqual("""<html> 507 self.assertEqual("""<html>
291 <p><input type="text" name="num"/> Eintr\xc3\xa4ge pro Seite, beginnend auf Seite <input type="text" name="num"/>.</p> 508 <p><input type="text" name="num"/> Eintr\xc3\xa4ge pro Seite, beginnend auf Seite <input type="text" name="num"/>.</p>
292 </html>""", tmpl.generate().render()) 509 </html>""", tmpl.generate().render())
293 510
294 def test_extract_i18n_msg_with_param(self): 511 def test_extract_i18n_msg_with_param(self):
297 <p i18n:msg="name"> 514 <p i18n:msg="name">
298 Hello, ${user.name}! 515 Hello, ${user.name}!
299 </p> 516 </p>
300 </html>""") 517 </html>""")
301 translator = Translator() 518 translator = Translator()
519 tmpl.add_directives(Translator.NAMESPACE, translator)
302 messages = list(translator.extract(tmpl.stream)) 520 messages = list(translator.extract(tmpl.stream))
303 self.assertEqual(1, len(messages)) 521 self.assertEqual(1, len(messages))
304 self.assertEqual('Hello, %(name)s!', messages[0][2]) 522 self.assertEqual('Hello, %(name)s!', messages[0][2])
305 523
306 def test_translate_i18n_msg_with_param(self): 524 def test_translate_i18n_msg_with_param(self):
310 Hello, ${user.name}! 528 Hello, ${user.name}!
311 </p> 529 </p>
312 </html>""") 530 </html>""")
313 gettext = lambda s: u"Hallo, %(name)s!" 531 gettext = lambda s: u"Hallo, %(name)s!"
314 translator = Translator(gettext) 532 translator = Translator(gettext)
315 tmpl.filters.insert(0, translator) 533 translator.setup(tmpl)
316 tmpl.add_directives(Translator.NAMESPACE, translator)
317 self.assertEqual("""<html> 534 self.assertEqual("""<html>
318 <p>Hallo, Jim!</p> 535 <p>Hallo, Jim!</p>
319 </html>""", tmpl.generate(user=dict(name='Jim')).render()) 536 </html>""", tmpl.generate(user=dict(name='Jim')).render())
320 537
321 def test_translate_i18n_msg_with_param_reordered(self): 538 def test_translate_i18n_msg_with_param_reordered(self):
325 Hello, ${user.name}! 542 Hello, ${user.name}!
326 </p> 543 </p>
327 </html>""") 544 </html>""")
328 gettext = lambda s: u"%(name)s, sei gegrüßt!" 545 gettext = lambda s: u"%(name)s, sei gegrüßt!"
329 translator = Translator(gettext) 546 translator = Translator(gettext)
330 tmpl.filters.insert(0, translator) 547 translator.setup(tmpl)
331 tmpl.add_directives(Translator.NAMESPACE, translator)
332 self.assertEqual("""<html> 548 self.assertEqual("""<html>
333 <p>Jim, sei gegrüßt!</p> 549 <p>Jim, sei gegrüßt!</p>
334 </html>""", tmpl.generate(user=dict(name='Jim')).render()) 550 </html>""", tmpl.generate(user=dict(name='Jim')).render())
335 551
336 def test_translate_i18n_msg_with_attribute_param(self): 552 def test_translate_i18n_msg_with_attribute_param(self):
340 Hello, <a href="#${anchor}">dude</a>! 556 Hello, <a href="#${anchor}">dude</a>!
341 </p> 557 </p>
342 </html>""") 558 </html>""")
343 gettext = lambda s: u"Sei gegrüßt, [1:Alter]!" 559 gettext = lambda s: u"Sei gegrüßt, [1:Alter]!"
344 translator = Translator(gettext) 560 translator = Translator(gettext)
345 tmpl.filters.insert(0, translator) 561 translator.setup(tmpl)
346 tmpl.add_directives(Translator.NAMESPACE, translator)
347 self.assertEqual("""<html> 562 self.assertEqual("""<html>
348 <p>Sei gegrüßt, <a href="#42">Alter</a>!</p> 563 <p>Sei gegrüßt, <a href="#42">Alter</a>!</p>
349 </html>""", tmpl.generate(anchor='42').render()) 564 </html>""", tmpl.generate(anchor='42').render())
350 565
351 def test_extract_i18n_msg_with_two_params(self): 566 def test_extract_i18n_msg_with_two_params(self):
354 <p i18n:msg="name, time"> 569 <p i18n:msg="name, time">
355 Posted by ${post.author} at ${entry.time.strftime('%H:%m')} 570 Posted by ${post.author} at ${entry.time.strftime('%H:%m')}
356 </p> 571 </p>
357 </html>""") 572 </html>""")
358 translator = Translator() 573 translator = Translator()
574 tmpl.add_directives(Translator.NAMESPACE, translator)
359 messages = list(translator.extract(tmpl.stream)) 575 messages = list(translator.extract(tmpl.stream))
360 self.assertEqual(1, len(messages)) 576 self.assertEqual(1, len(messages))
361 self.assertEqual('Posted by %(name)s at %(time)s', messages[0][2]) 577 self.assertEqual('Posted by %(name)s at %(time)s', messages[0][2])
362 578
363 def test_translate_i18n_msg_with_two_params(self): 579 def test_translate_i18n_msg_with_two_params(self):
367 Written by ${entry.author} at ${entry.time.strftime('%H:%M')} 583 Written by ${entry.author} at ${entry.time.strftime('%H:%M')}
368 </p> 584 </p>
369 </html>""") 585 </html>""")
370 gettext = lambda s: u"%(name)s schrieb dies um %(time)s" 586 gettext = lambda s: u"%(name)s schrieb dies um %(time)s"
371 translator = Translator(gettext) 587 translator = Translator(gettext)
372 tmpl.filters.insert(0, translator) 588 translator.setup(tmpl)
373 tmpl.add_directives(Translator.NAMESPACE, translator)
374 entry = { 589 entry = {
375 'author': 'Jim', 590 'author': 'Jim',
376 'time': datetime(2008, 4, 1, 14, 30) 591 'time': datetime(2008, 4, 1, 14, 30)
377 } 592 }
378 self.assertEqual("""<html> 593 self.assertEqual("""<html>
385 <p i18n:msg=""> 600 <p i18n:msg="">
386 Show me <input type="text" name="num" py:attrs="{'value': x}" /> entries per page. 601 Show me <input type="text" name="num" py:attrs="{'value': x}" /> entries per page.
387 </p> 602 </p>
388 </html>""") 603 </html>""")
389 translator = Translator() 604 translator = Translator()
605 tmpl.add_directives(Translator.NAMESPACE, translator)
390 messages = list(translator.extract(tmpl.stream)) 606 messages = list(translator.extract(tmpl.stream))
391 self.assertEqual(1, len(messages)) 607 self.assertEqual(1, len(messages))
392 self.assertEqual('Show me [1:] entries per page.', messages[0][2]) 608 self.assertEqual('Show me [1:] entries per page.', messages[0][2])
393 609
394 # FIXME: this currently fails :-/ 610 def test_translate_i18n_msg_with_directive(self):
395 # def test_translate_i18n_msg_with_directive(self): 611 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
396 # tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" 612 xmlns:i18n="http://genshi.edgewall.org/i18n">
397 # xmlns:i18n="http://genshi.edgewall.org/i18n"> 613 <p i18n:msg="">
398 # <p i18n:msg=""> 614 Show me <input type="text" name="num" py:attrs="{'value': 'x'}" /> entries per page.
399 # Show me <input type="text" name="num" py:attrs="{'value': x}" /> entries per page. 615 </p>
400 # </p> 616 </html>""")
401 # </html>""") 617 gettext = lambda s: u"[1:] Einträge pro Seite anzeigen."
402 # gettext = lambda s: u"[1:] Einträge pro Seite anzeigen." 618 translator = Translator(gettext)
403 # tmpl.filters.insert(0, Translator(gettext)) 619 translator.setup(tmpl)
404 # self.assertEqual("""<html> 620 self.assertEqual("""<html>
405 # <p><input type="text" name="num" value="x"/> Einträge pro Seite anzeigen.</p> 621 <p><input type="text" name="num" value="x"/> Einträge pro Seite anzeigen.</p>
406 # </html>""", tmpl.generate().render()) 622 </html>""", tmpl.generate().render())
407 623
408 def test_extract_i18n_msg_with_comment(self): 624 def test_extract_i18n_msg_with_comment(self):
409 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" 625 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
410 xmlns:i18n="http://genshi.edgewall.org/i18n"> 626 xmlns:i18n="http://genshi.edgewall.org/i18n">
627 <p i18n:comment="As in foo bar" i18n:msg="">Foo</p>
628 </html>""")
629 translator = Translator()
630 tmpl.add_directives(Translator.NAMESPACE, translator)
631 messages = list(translator.extract(tmpl.stream))
632 self.assertEqual(1, len(messages))
633 self.assertEqual((3, None, 'Foo', ['As in foo bar']), messages[0])
634 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
635 xmlns:i18n="http://genshi.edgewall.org/i18n">
411 <p i18n:msg="" i18n:comment="As in foo bar">Foo</p> 636 <p i18n:msg="" i18n:comment="As in foo bar">Foo</p>
412 </html>""") 637 </html>""")
413 translator = Translator() 638 translator = Translator()
414 messages = list(translator.extract(tmpl.stream)) 639 tmpl.add_directives(Translator.NAMESPACE, translator)
415 self.assertEqual(1, len(messages)) 640 messages = list(translator.extract(tmpl.stream))
416 self.assertEqual((3, None, u'Foo', ['As in foo bar']), messages[0]) 641 self.assertEqual(1, len(messages))
642 self.assertEqual((3, None, 'Foo', ['As in foo bar']), messages[0])
417 643
418 def test_translate_i18n_msg_with_comment(self): 644 def test_translate_i18n_msg_with_comment(self):
419 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" 645 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
420 xmlns:i18n="http://genshi.edgewall.org/i18n"> 646 xmlns:i18n="http://genshi.edgewall.org/i18n">
421 <p i18n:msg="" i18n:comment="As in foo bar">Foo</p> 647 <p i18n:msg="" i18n:comment="As in foo bar">Foo</p>
422 </html>""") 648 </html>""")
423 gettext = lambda s: u"Voh" 649 gettext = lambda s: u"Voh"
424 translator = Translator(gettext) 650 translator = Translator(gettext)
425 tmpl.filters.insert(0, translator) 651 translator.setup(tmpl)
426 tmpl.add_directives(Translator.NAMESPACE, translator)
427 self.assertEqual("""<html> 652 self.assertEqual("""<html>
428 <p>Voh</p> 653 <p>Voh</p>
429 </html>""", tmpl.generate().render()) 654 </html>""", tmpl.generate().render())
430 655
431 def test_extract_i18n_msg_with_attr(self): 656 def test_extract_i18n_msg_with_attr(self):
434 <p i18n:msg="" title="Foo bar">Foo</p> 659 <p i18n:msg="" title="Foo bar">Foo</p>
435 </html>""") 660 </html>""")
436 translator = Translator() 661 translator = Translator()
437 messages = list(translator.extract(tmpl.stream)) 662 messages = list(translator.extract(tmpl.stream))
438 self.assertEqual(2, len(messages)) 663 self.assertEqual(2, len(messages))
439 self.assertEqual((3, None, u'Foo bar', []), messages[0]) 664 self.assertEqual((3, None, 'Foo bar', []), messages[0])
440 self.assertEqual((3, None, u'Foo', []), messages[1]) 665 self.assertEqual((3, None, 'Foo', []), messages[1])
441 666
442 def test_translate_i18n_msg_with_attr(self): 667 def test_translate_i18n_msg_with_attr(self):
443 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" 668 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
444 xmlns:i18n="http://genshi.edgewall.org/i18n"> 669 xmlns:i18n="http://genshi.edgewall.org/i18n">
445 <p i18n:msg="" title="Foo bar">Foo</p> 670 <p i18n:msg="" title="Foo bar">Foo</p>
446 </html>""") 671 </html>""")
447 gettext = lambda s: u"Voh" 672 gettext = lambda s: u"Voh"
448 translator = Translator(DummyTranslations({ 673 translator = Translator(DummyTranslations({
449 'Foo': u'Voh', 674 'Foo': 'Voh',
450 'Foo bar': u'Voh bär' 675 'Foo bar': u'Voh bär'
451 })) 676 }))
452 tmpl.filters.insert(0, translator) 677 tmpl.filters.insert(0, translator)
453 tmpl.add_directives(Translator.NAMESPACE, translator) 678 tmpl.add_directives(Translator.NAMESPACE, translator)
454 self.assertEqual("""<html> 679 self.assertEqual("""<html>
455 <p title="Voh bär">Voh</p> 680 <p title="Voh bär">Voh</p>
456 </html>""", tmpl.generate().render()) 681 </html>""", tmpl.generate().render())
457 682
458 def test_translate_with_translations_object(self): 683 def test_translate_i18n_msg_and_py_strip_directives(self):
459 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" 684 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
460 xmlns:i18n="http://genshi.edgewall.org/i18n"> 685 xmlns:i18n="http://genshi.edgewall.org/i18n">
461 <p i18n:msg="" i18n:comment="As in foo bar">Foo</p> 686 <p i18n:msg="" py:strip="">Foo</p>
687 <p py:strip="" i18n:msg="">Foo</p>
462 </html>""") 688 </html>""")
463 translator = Translator(DummyTranslations({'Foo': 'Voh'})) 689 translator = Translator(DummyTranslations({'Foo': 'Voh'}))
464 tmpl.filters.insert(0, translator) 690 translator.setup(tmpl)
465 tmpl.add_directives(Translator.NAMESPACE, translator) 691 self.assertEqual("""<html>
692 Voh
693 Voh
694 </html>""", tmpl.generate().render())
695
696 def test_i18n_msg_ticket_300_extract(self):
697 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
698 xmlns:i18n="http://genshi.edgewall.org/i18n">
699 <i18n:msg params="date, author">
700 Changed ${ '10/12/2008' } ago by ${ 'me, the author' }
701 </i18n:msg>
702 </html>""")
703 translator = Translator()
704 tmpl.add_directives(Translator.NAMESPACE, translator)
705 messages = list(translator.extract(tmpl.stream))
706 self.assertEqual(1, len(messages))
707 self.assertEqual(
708 (3, None, 'Changed %(date)s ago by %(author)s', []), messages[0]
709 )
710
711 def test_i18n_msg_ticket_300_translate(self):
712 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
713 xmlns:i18n="http://genshi.edgewall.org/i18n">
714 <i18n:msg params="date, author">
715 Changed ${ date } ago by ${ author }
716 </i18n:msg>
717 </html>""")
718 translations = DummyTranslations({
719 'Changed %(date)s ago by %(author)s': u'Modificado à %(date)s por %(author)s'
720 })
721 translator = Translator(translations)
722 translator.setup(tmpl)
723 self.assertEqual("""<html>
724 Modificado à um dia por Pedro
725 </html>""", tmpl.generate(date='um dia', author="Pedro").render())
726
727
728 def test_i18n_msg_ticket_251_extract(self):
729 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
730 xmlns:i18n="http://genshi.edgewall.org/i18n">
731 <p i18n:msg=""><tt><b>Translation[&nbsp;0&nbsp;]</b>: <em>One coin</em></tt></p>
732 </html>""")
733 translator = Translator()
734 tmpl.add_directives(Translator.NAMESPACE, translator)
735 messages = list(translator.extract(tmpl.stream))
736 self.assertEqual(1, len(messages))
737 self.assertEqual(
738 (3, None, u'[1:[2:Translation\\[\xa00\xa0\\]]: [3:One coin]]', []), messages[0]
739 )
740
741 def test_i18n_msg_ticket_251_translate(self):
742 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
743 xmlns:i18n="http://genshi.edgewall.org/i18n">
744 <p i18n:msg=""><tt><b>Translation[&nbsp;0&nbsp;]</b>: <em>One coin</em></tt></p>
745 </html>""")
746 translations = DummyTranslations({
747 u'[1:[2:Translation\\[\xa00\xa0\\]]: [3:One coin]]':
748 u'[1:[2:Trandução\\[\xa00\xa0\\]]: [3:Uma moeda]]'
749 })
750 translator = Translator(translations)
751 translator.setup(tmpl)
752 self.assertEqual("""<html>
753 <p><tt><b>Trandução[ 0 ]</b>: <em>Uma moeda</em></tt></p>
754 </html>""", tmpl.generate().render())
755
756 def test_extract_i18n_msg_with_other_directives_nested(self):
757 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
758 xmlns:i18n="http://genshi.edgewall.org/i18n">
759 <p i18n:msg="" py:with="q = quote_plus(message[:80])">Before you do that, though, please first try
760 <strong><a href="${trac.homepage}search?ticket=yes&amp;noquickjump=1&amp;q=$q">searching</a>
761 for similar issues</strong>, as it is quite likely that this problem
762 has been reported before. For questions about installation
763 and configuration of Trac, please try the
764 <a href="${trac.homepage}wiki/MailingList">mailing list</a>
765 instead of filing a ticket.
766 </p>
767 </html>""")
768 translator = Translator()
769 translator.setup(tmpl)
770 messages = list(translator.extract(tmpl.stream))
771 self.assertEqual(1, len(messages))
772 self.assertEqual(
773 'Before you do that, though, please first try\n '
774 '[1:[2:searching]\n for similar issues], as it is '
775 'quite likely that this problem\n has been reported '
776 'before. For questions about installation\n and '
777 'configuration of Trac, please try the\n '
778 '[3:mailing list]\n instead of filing a ticket.',
779 messages[0][2]
780 )
781
782 def test_translate_i18n_msg_with_other_directives_nested(self):
783 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
784 xmlns:i18n="http://genshi.edgewall.org/i18n">
785 <p i18n:msg="">Before you do that, though, please first try
786 <strong><a href="${trac.homepage}search?ticket=yes&amp;noquickjump=1&amp;q=q">searching</a>
787 for similar issues</strong>, as it is quite likely that this problem
788 has been reported before. For questions about installation
789 and configuration of Trac, please try the
790 <a href="${trac.homepage}wiki/MailingList">mailing list</a>
791 instead of filing a ticket.
792 </p>
793 </html>""")
794 translations = DummyTranslations({
795 'Before you do that, though, please first try\n '
796 '[1:[2:searching]\n for similar issues], as it is '
797 'quite likely that this problem\n has been reported '
798 'before. For questions about installation\n and '
799 'configuration of Trac, please try the\n '
800 '[3:mailing list]\n instead of filing a ticket.':
801 u'Antes de o fazer, porém,\n '
802 u'[1:por favor tente [2:procurar]\n por problemas semelhantes], uma vez que '
803 u'é muito provável que este problema\n já tenha sido reportado '
804 u'anteriormente. Para questões relativas à instalação\n e '
805 u'configuração do Trac, por favor tente a\n '
806 u'[3:mailing list]\n em vez de criar um assunto.'
807 })
808 translator = Translator(translations)
809 translator.setup(tmpl)
810 messages = list(translator.extract(tmpl.stream))
811 self.assertEqual(1, len(messages))
812 ctx = Context()
813 ctx.push({'trac': {'homepage': 'http://trac.edgewall.org/'}})
814 self.assertEqual("""<html>
815 <p>Antes de o fazer, porém,
816 <strong>por favor tente <a href="http://trac.edgewall.org/search?ticket=yes&amp;noquickjump=1&amp;q=q">procurar</a>
817 por problemas semelhantes</strong>, uma vez que é muito provável que este problema
818 já tenha sido reportado anteriormente. Para questões relativas à instalação
819 e configuração do Trac, por favor tente a
820 <a href="http://trac.edgewall.org/wiki/MailingList">mailing list</a>
821 em vez de criar um assunto.</p>
822 </html>""", tmpl.generate(ctx).render())
823
824 def test_i18n_msg_with_other_nested_directives_with_reordered_content(self):
825 # See: http://genshi.edgewall.org/ticket/300#comment:10
826 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
827 xmlns:i18n="http://genshi.edgewall.org/i18n">
828 <p py:if="not editable" class="hint" i18n:msg="">
829 <strong>Note:</strong> This repository is defined in
830 <code><a href="${ 'href.wiki(TracIni)' }">trac.ini</a></code>
831 and cannot be edited on this page.
832 </p>
833 </html>""")
834 translations = DummyTranslations({
835 '[1:Note:] This repository is defined in\n '
836 '[2:[3:trac.ini]]\n and cannot be edited on this page.':
837 u'[1:Nota:] Este repositório está definido em \n '
838 u'[2:[3:trac.ini]]\n e não pode ser editado nesta página.',
839 })
840 translator = Translator(translations)
841 translator.setup(tmpl)
842 messages = list(translator.extract(tmpl.stream))
843 self.assertEqual(1, len(messages))
844 self.assertEqual(
845 '[1:Note:] This repository is defined in\n '
846 '[2:[3:trac.ini]]\n and cannot be edited on this page.',
847 messages[0][2]
848 )
849 self.assertEqual("""<html>
850 <p class="hint"><strong>Nota:</strong> Este repositório está definido em
851 <code><a href="href.wiki(TracIni)">trac.ini</a></code>
852 e não pode ser editado nesta página.</p>
853 </html>""", tmpl.generate(editable=False).render())
854
855 def test_extract_i18n_msg_with_py_strip(self):
856 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
857 xmlns:i18n="http://genshi.edgewall.org/i18n">
858 <p i18n:msg="" py:strip="">
859 Please see <a href="help.html">Help</a> for details.
860 </p>
861 </html>""")
862 translator = Translator()
863 tmpl.add_directives(Translator.NAMESPACE, translator)
864 messages = list(translator.extract(tmpl.stream))
865 self.assertEqual(1, len(messages))
866 self.assertEqual((3, None, 'Please see [1:Help] for details.', []),
867 messages[0])
868
869 def test_extract_i18n_msg_with_py_strip_and_comment(self):
870 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
871 xmlns:i18n="http://genshi.edgewall.org/i18n">
872 <p i18n:msg="" py:strip="" i18n:comment="Foo">
873 Please see <a href="help.html">Help</a> for details.
874 </p>
875 </html>""")
876 translator = Translator()
877 tmpl.add_directives(Translator.NAMESPACE, translator)
878 messages = list(translator.extract(tmpl.stream))
879 self.assertEqual(1, len(messages))
880 self.assertEqual((3, None, 'Please see [1:Help] for details.',
881 ['Foo']), messages[0])
882
883 def test_translate_i18n_msg_and_comment_with_py_strip_directives(self):
884 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
885 xmlns:i18n="http://genshi.edgewall.org/i18n">
886 <p i18n:msg="" i18n:comment="As in foo bar" py:strip="">Foo</p>
887 <p py:strip="" i18n:msg="" i18n:comment="As in foo bar">Foo</p>
888 </html>""")
889 translator = Translator(DummyTranslations({'Foo': 'Voh'}))
890 translator.setup(tmpl)
891 self.assertEqual("""<html>
892 Voh
893 Voh
894 </html>""", tmpl.generate().render())
895
896
897 class ChooseDirectiveTestCase(unittest.TestCase):
898
899 def test_translate_i18n_choose_as_attribute(self):
900 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
901 xmlns:i18n="http://genshi.edgewall.org/i18n">
902 <div i18n:choose="one">
903 <p i18n:singular="">FooBar</p>
904 <p i18n:plural="">FooBars</p>
905 </div>
906 <div i18n:choose="two">
907 <p i18n:singular="">FooBar</p>
908 <p i18n:plural="">FooBars</p>
909 </div>
910 </html>""")
911 translations = DummyTranslations()
912 translator = Translator(translations)
913 translator.setup(tmpl)
914 self.assertEqual("""<html>
915 <div>
916 <p>FooBar</p>
917 </div>
918 <div>
919 <p>FooBars</p>
920 </div>
921 </html>""", tmpl.generate(one=1, two=2).render())
922
923 def test_translate_i18n_choose_as_directive(self):
924 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
925 xmlns:i18n="http://genshi.edgewall.org/i18n">
926 <i18n:choose numeral="two">
927 <p i18n:singular="">FooBar</p>
928 <p i18n:plural="">FooBars</p>
929 </i18n:choose>
930 <i18n:choose numeral="one">
931 <p i18n:singular="">FooBar</p>
932 <p i18n:plural="">FooBars</p>
933 </i18n:choose>
934 </html>""")
935 translations = DummyTranslations()
936 translator = Translator(translations)
937 translator.setup(tmpl)
938 self.assertEqual("""<html>
939 <p>FooBars</p>
940 <p>FooBar</p>
941 </html>""", tmpl.generate(one=1, two=2).render())
942
943 def test_translate_i18n_choose_as_directive_singular_and_plural_with_strip(self):
944 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
945 xmlns:i18n="http://genshi.edgewall.org/i18n">
946 <i18n:choose numeral="two">
947 <p i18n:singular="" py:strip="">FooBar Singular with Strip</p>
948 <p i18n:plural="">FooBars Plural without Strip</p>
949 </i18n:choose>
950 <i18n:choose numeral="two">
951 <p i18n:singular="">FooBar singular without strip</p>
952 <p i18n:plural="" py:strip="">FooBars plural with strip</p>
953 </i18n:choose>
954 <i18n:choose numeral="one">
955 <p i18n:singular="">FooBar singular without strip</p>
956 <p i18n:plural="" py:strip="">FooBars plural with strip</p>
957 </i18n:choose>
958 <i18n:choose numeral="one">
959 <p i18n:singular="" py:strip="">FooBar singular with strip</p>
960 <p i18n:plural="">FooBars plural without strip</p>
961 </i18n:choose>
962 </html>""")
963 translations = DummyTranslations()
964 translator = Translator(translations)
965 translator.setup(tmpl)
966 self.assertEqual("""<html>
967 <p>FooBars Plural without Strip</p>
968 FooBars plural with strip
969 <p>FooBar singular without strip</p>
970 FooBar singular with strip
971 </html>""", tmpl.generate(one=1, two=2).render())
972
973 def test_translate_i18n_choose_plural_singular_as_directive(self):
974 # Ticket 371
975 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
976 xmlns:i18n="http://genshi.edgewall.org/i18n">
977 <i18n:choose numeral="two">
978 <i18n:singular>FooBar</i18n:singular>
979 <i18n:plural>FooBars</i18n:plural>
980 </i18n:choose>
981 <i18n:choose numeral="one">
982 <i18n:singular>FooBar</i18n:singular>
983 <i18n:plural>FooBars</i18n:plural>
984 </i18n:choose>
985 </html>""")
986 translations = DummyTranslations({
987 ('FooBar', 0): 'FuBar',
988 ('FooBars', 1): 'FuBars',
989 'FooBar': 'FuBar',
990 'FooBars': 'FuBars',
991 })
992 translator = Translator(translations)
993 translator.setup(tmpl)
994 self.assertEqual("""<html>
995 FuBars
996 FuBar
997 </html>""", tmpl.generate(one=1, two=2).render())
998
999 def test_translate_i18n_choose_as_attribute_with_params(self):
1000 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1001 xmlns:i18n="http://genshi.edgewall.org/i18n">
1002 <div i18n:choose="two; fname, lname">
1003 <p i18n:singular="">Foo $fname $lname</p>
1004 <p i18n:plural="">Foos $fname $lname</p>
1005 </div>
1006 </html>""")
1007 translations = DummyTranslations({
1008 ('Foo %(fname)s %(lname)s', 0): 'Voh %(fname)s %(lname)s',
1009 ('Foo %(fname)s %(lname)s', 1): 'Vohs %(fname)s %(lname)s',
1010 'Foo %(fname)s %(lname)s': 'Voh %(fname)s %(lname)s',
1011 'Foos %(fname)s %(lname)s': 'Vohs %(fname)s %(lname)s',
1012 })
1013 translator = Translator(translations)
1014 translator.setup(tmpl)
1015 self.assertEqual("""<html>
1016 <div>
1017 <p>Vohs John Doe</p>
1018 </div>
1019 </html>""", tmpl.generate(two=2, fname='John', lname='Doe').render())
1020
1021 def test_translate_i18n_choose_as_attribute_with_params_and_domain_as_param(self):
1022 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1023 xmlns:i18n="http://genshi.edgewall.org/i18n"
1024 i18n:domain="foo">
1025 <div i18n:choose="two; fname, lname">
1026 <p i18n:singular="">Foo $fname $lname</p>
1027 <p i18n:plural="">Foos $fname $lname</p>
1028 </div>
1029 </html>""")
1030 translations = DummyTranslations()
1031 translations.add_domain('foo', {
1032 ('Foo %(fname)s %(lname)s', 0): 'Voh %(fname)s %(lname)s',
1033 ('Foo %(fname)s %(lname)s', 1): 'Vohs %(fname)s %(lname)s',
1034 'Foo %(fname)s %(lname)s': 'Voh %(fname)s %(lname)s',
1035 'Foos %(fname)s %(lname)s': 'Vohs %(fname)s %(lname)s',
1036 })
1037 translator = Translator(translations)
1038 translator.setup(tmpl)
1039 self.assertEqual("""<html>
1040 <div>
1041 <p>Vohs John Doe</p>
1042 </div>
1043 </html>""", tmpl.generate(two=2, fname='John', lname='Doe').render())
1044
1045 def test_translate_i18n_choose_as_directive_with_params(self):
1046 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1047 xmlns:i18n="http://genshi.edgewall.org/i18n">
1048 <i18n:choose numeral="two" params="fname, lname">
1049 <p i18n:singular="">Foo ${fname} ${lname}</p>
1050 <p i18n:plural="">Foos ${fname} ${lname}</p>
1051 </i18n:choose>
1052 <i18n:choose numeral="one" params="fname, lname">
1053 <p i18n:singular="">Foo ${fname} ${lname}</p>
1054 <p i18n:plural="">Foos ${fname} ${lname}</p>
1055 </i18n:choose>
1056 </html>""")
1057 translations = DummyTranslations({
1058 ('Foo %(fname)s %(lname)s', 0): 'Voh %(fname)s %(lname)s',
1059 ('Foo %(fname)s %(lname)s', 1): 'Vohs %(fname)s %(lname)s',
1060 'Foo %(fname)s %(lname)s': 'Voh %(fname)s %(lname)s',
1061 'Foos %(fname)s %(lname)s': 'Vohs %(fname)s %(lname)s',
1062 })
1063 translator = Translator(translations)
1064 translator.setup(tmpl)
1065 self.assertEqual("""<html>
1066 <p>Vohs John Doe</p>
1067 <p>Voh John Doe</p>
1068 </html>""", tmpl.generate(one=1, two=2,
1069 fname='John', lname='Doe').render())
1070
1071 def test_translate_i18n_choose_as_directive_with_params_and_domain_as_directive(self):
1072 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1073 xmlns:i18n="http://genshi.edgewall.org/i18n">
1074 <i18n:domain name="foo">
1075 <i18n:choose numeral="two" params="fname, lname">
1076 <p i18n:singular="">Foo ${fname} ${lname}</p>
1077 <p i18n:plural="">Foos ${fname} ${lname}</p>
1078 </i18n:choose>
1079 </i18n:domain>
1080 <i18n:choose numeral="one" params="fname, lname">
1081 <p i18n:singular="">Foo ${fname} ${lname}</p>
1082 <p i18n:plural="">Foos ${fname} ${lname}</p>
1083 </i18n:choose>
1084 </html>""")
1085 translations = DummyTranslations()
1086 translations.add_domain('foo', {
1087 ('Foo %(fname)s %(lname)s', 0): 'Voh %(fname)s %(lname)s',
1088 ('Foo %(fname)s %(lname)s', 1): 'Vohs %(fname)s %(lname)s',
1089 'Foo %(fname)s %(lname)s': 'Voh %(fname)s %(lname)s',
1090 'Foos %(fname)s %(lname)s': 'Vohs %(fname)s %(lname)s',
1091 })
1092 translator = Translator(translations)
1093 translator.setup(tmpl)
1094 self.assertEqual("""<html>
1095 <p>Vohs John Doe</p>
1096 <p>Foo John Doe</p>
1097 </html>""", tmpl.generate(one=1, two=2,
1098 fname='John', lname='Doe').render())
1099
1100 def test_extract_i18n_choose_as_attribute(self):
1101 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1102 xmlns:i18n="http://genshi.edgewall.org/i18n">
1103 <div i18n:choose="one">
1104 <p i18n:singular="">FooBar</p>
1105 <p i18n:plural="">FooBars</p>
1106 </div>
1107 <div i18n:choose="two">
1108 <p i18n:singular="">FooBar</p>
1109 <p i18n:plural="">FooBars</p>
1110 </div>
1111 </html>""")
1112 translator = Translator()
1113 tmpl.add_directives(Translator.NAMESPACE, translator)
1114 messages = list(translator.extract(tmpl.stream))
1115 self.assertEqual(2, len(messages))
1116 self.assertEqual((3, 'ngettext', ('FooBar', 'FooBars'), []), messages[0])
1117 self.assertEqual((7, 'ngettext', ('FooBar', 'FooBars'), []), messages[1])
1118
1119 def test_extract_i18n_choose_as_directive(self):
1120 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1121 xmlns:i18n="http://genshi.edgewall.org/i18n">
1122 <i18n:choose numeral="two">
1123 <p i18n:singular="">FooBar</p>
1124 <p i18n:plural="">FooBars</p>
1125 </i18n:choose>
1126 <i18n:choose numeral="one">
1127 <p i18n:singular="">FooBar</p>
1128 <p i18n:plural="">FooBars</p>
1129 </i18n:choose>
1130 </html>""")
1131 translator = Translator()
1132 tmpl.add_directives(Translator.NAMESPACE, translator)
1133 messages = list(translator.extract(tmpl.stream))
1134 self.assertEqual(2, len(messages))
1135 self.assertEqual((3, 'ngettext', ('FooBar', 'FooBars'), []), messages[0])
1136 self.assertEqual((7, 'ngettext', ('FooBar', 'FooBars'), []), messages[1])
1137
1138 def test_extract_i18n_choose_as_attribute_with_params(self):
1139 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1140 xmlns:i18n="http://genshi.edgewall.org/i18n">
1141 <div i18n:choose="two; fname, lname">
1142 <p i18n:singular="">Foo $fname $lname</p>
1143 <p i18n:plural="">Foos $fname $lname</p>
1144 </div>
1145 </html>""")
1146 translator = Translator()
1147 tmpl.add_directives(Translator.NAMESPACE, translator)
1148 messages = list(translator.extract(tmpl.stream))
1149 self.assertEqual(1, len(messages))
1150 self.assertEqual((3, 'ngettext', ('Foo %(fname)s %(lname)s',
1151 'Foos %(fname)s %(lname)s'), []),
1152 messages[0])
1153
1154 def test_extract_i18n_choose_as_attribute_with_params_and_domain_as_param(self):
1155 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1156 xmlns:i18n="http://genshi.edgewall.org/i18n"
1157 i18n:domain="foo">
1158 <div i18n:choose="two; fname, lname">
1159 <p i18n:singular="">Foo $fname $lname</p>
1160 <p i18n:plural="">Foos $fname $lname</p>
1161 </div>
1162 </html>""")
1163 translator = Translator()
1164 tmpl.add_directives(Translator.NAMESPACE, translator)
1165 messages = list(translator.extract(tmpl.stream))
1166 self.assertEqual(1, len(messages))
1167 self.assertEqual((4, 'ngettext', ('Foo %(fname)s %(lname)s',
1168 'Foos %(fname)s %(lname)s'), []),
1169 messages[0])
1170
1171 def test_extract_i18n_choose_as_directive_with_params(self):
1172 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1173 xmlns:i18n="http://genshi.edgewall.org/i18n">
1174 <i18n:choose numeral="two" params="fname, lname">
1175 <p i18n:singular="">Foo ${fname} ${lname}</p>
1176 <p i18n:plural="">Foos ${fname} ${lname}</p>
1177 </i18n:choose>
1178 <i18n:choose numeral="one" params="fname, lname">
1179 <p i18n:singular="">Foo ${fname} ${lname}</p>
1180 <p i18n:plural="">Foos ${fname} ${lname}</p>
1181 </i18n:choose>
1182 </html>""")
1183 translator = Translator()
1184 tmpl.add_directives(Translator.NAMESPACE, translator)
1185 messages = list(translator.extract(tmpl.stream))
1186 self.assertEqual(2, len(messages))
1187 self.assertEqual((3, 'ngettext', ('Foo %(fname)s %(lname)s',
1188 'Foos %(fname)s %(lname)s'), []),
1189 messages[0])
1190 self.assertEqual((7, 'ngettext', ('Foo %(fname)s %(lname)s',
1191 'Foos %(fname)s %(lname)s'), []),
1192 messages[1])
1193
1194 def test_extract_i18n_choose_as_directive_with_params_and_domain_as_directive(self):
1195 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1196 xmlns:i18n="http://genshi.edgewall.org/i18n">
1197 <i18n:domain name="foo">
1198 <i18n:choose numeral="two" params="fname, lname">
1199 <p i18n:singular="">Foo ${fname} ${lname}</p>
1200 <p i18n:plural="">Foos ${fname} ${lname}</p>
1201 </i18n:choose>
1202 </i18n:domain>
1203 <i18n:choose numeral="one" params="fname, lname">
1204 <p i18n:singular="">Foo ${fname} ${lname}</p>
1205 <p i18n:plural="">Foos ${fname} ${lname}</p>
1206 </i18n:choose>
1207 </html>""")
1208 translator = Translator()
1209 tmpl.add_directives(Translator.NAMESPACE, translator)
1210 messages = list(translator.extract(tmpl.stream))
1211 self.assertEqual(2, len(messages))
1212 self.assertEqual((4, 'ngettext', ('Foo %(fname)s %(lname)s',
1213 'Foos %(fname)s %(lname)s'), []),
1214 messages[0])
1215 self.assertEqual((9, 'ngettext', ('Foo %(fname)s %(lname)s',
1216 'Foos %(fname)s %(lname)s'), []),
1217 messages[1])
1218
1219 def test_extract_i18n_choose_as_attribute_with_params_and_comment(self):
1220 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1221 xmlns:i18n="http://genshi.edgewall.org/i18n">
1222 <div i18n:choose="two; fname, lname" i18n:comment="As in Foo Bar">
1223 <p i18n:singular="">Foo $fname $lname</p>
1224 <p i18n:plural="">Foos $fname $lname</p>
1225 </div>
1226 </html>""")
1227 translator = Translator()
1228 tmpl.add_directives(Translator.NAMESPACE, translator)
1229 messages = list(translator.extract(tmpl.stream))
1230 self.assertEqual(1, len(messages))
1231 self.assertEqual((3, 'ngettext', ('Foo %(fname)s %(lname)s',
1232 'Foos %(fname)s %(lname)s'),
1233 ['As in Foo Bar']),
1234 messages[0])
1235
1236 def test_extract_i18n_choose_as_directive_with_params_and_comment(self):
1237 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1238 xmlns:i18n="http://genshi.edgewall.org/i18n">
1239 <i18n:choose numeral="two" params="fname, lname" i18n:comment="As in Foo Bar">
1240 <p i18n:singular="">Foo ${fname} ${lname}</p>
1241 <p i18n:plural="">Foos ${fname} ${lname}</p>
1242 </i18n:choose>
1243 </html>""")
1244 translator = Translator()
1245 tmpl.add_directives(Translator.NAMESPACE, translator)
1246 messages = list(translator.extract(tmpl.stream))
1247 self.assertEqual(1, len(messages))
1248 self.assertEqual((3, 'ngettext', ('Foo %(fname)s %(lname)s',
1249 'Foos %(fname)s %(lname)s'),
1250 ['As in Foo Bar']),
1251 messages[0])
1252
1253 def test_extract_i18n_choose_with_attributes(self):
1254 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1255 xmlns:i18n="http://genshi.edgewall.org/i18n">
1256 <p i18n:choose="num; num" title="Things">
1257 <i18n:singular>
1258 There is <a href="$link" title="View thing">${num} thing</a>.
1259 </i18n:singular>
1260 <i18n:plural>
1261 There are <a href="$link" title="View things">${num} things</a>.
1262 </i18n:plural>
1263 </p>
1264 </html>""")
1265 translator = Translator()
1266 translator.setup(tmpl)
1267 messages = list(translator.extract(tmpl.stream))
1268 self.assertEqual(4, len(messages))
1269 self.assertEqual((3, None, 'Things', []), messages[0])
1270 self.assertEqual((5, None, 'View thing', []), messages[1])
1271 self.assertEqual((8, None, 'View things', []), messages[2])
1272 self.assertEqual(
1273 (3, 'ngettext', ('There is [1:%(num)s thing].',
1274 'There are [1:%(num)s things].'), []),
1275 messages[3])
1276
1277 def test_translate_i18n_choose_with_attributes(self):
1278 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1279 xmlns:i18n="http://genshi.edgewall.org/i18n">
1280 <p i18n:choose="num; num" title="Things">
1281 <i18n:singular>
1282 There is <a href="$link" title="View thing">${num} thing</a>.
1283 </i18n:singular>
1284 <i18n:plural>
1285 There are <a href="$link" title="View things">${num} things</a>.
1286 </i18n:plural>
1287 </p>
1288 </html>""")
1289 translations = DummyTranslations({
1290 'Things': 'Sachen',
1291 'View thing': 'Sache betrachten',
1292 'View things': 'Sachen betrachten',
1293 ('There is [1:%(num)s thing].', 0): 'Da ist [1:%(num)s Sache].',
1294 ('There is [1:%(num)s thing].', 1): 'Da sind [1:%(num)s Sachen].'
1295 })
1296 translator = Translator(translations)
1297 translator.setup(tmpl)
1298 self.assertEqual(u"""<html>
1299 <p title="Sachen">
1300 Da ist <a href="/things" title="Sache betrachten">1 Sache</a>.
1301 </p>
1302 </html>""", tmpl.generate(link="/things", num=1).render(encoding=None))
1303 self.assertEqual(u"""<html>
1304 <p title="Sachen">
1305 Da sind <a href="/things" title="Sachen betrachten">3 Sachen</a>.
1306 </p>
1307 </html>""", tmpl.generate(link="/things", num=3).render(encoding=None))
1308
1309 def test_extract_i18n_choose_as_element_with_attributes(self):
1310 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1311 xmlns:i18n="http://genshi.edgewall.org/i18n">
1312 <i18n:choose numeral="num" params="num">
1313 <p i18n:singular="" title="Things">
1314 There is <a href="$link" title="View thing">${num} thing</a>.
1315 </p>
1316 <p i18n:plural="" title="Things">
1317 There are <a href="$link" title="View things">${num} things</a>.
1318 </p>
1319 </i18n:choose>
1320 </html>""")
1321 translator = Translator()
1322 translator.setup(tmpl)
1323 messages = list(translator.extract(tmpl.stream))
1324 self.assertEqual(5, len(messages))
1325 self.assertEqual((4, None, 'Things', []), messages[0])
1326 self.assertEqual((5, None, 'View thing', []), messages[1])
1327 self.assertEqual((7, None, 'Things', []), messages[2])
1328 self.assertEqual((8, None, 'View things', []), messages[3])
1329 self.assertEqual(
1330 (3, 'ngettext', ('There is [1:%(num)s thing].',
1331 'There are [1:%(num)s things].'), []),
1332 messages[4])
1333
1334 def test_translate_i18n_choose_as_element_with_attributes(self):
1335 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1336 xmlns:i18n="http://genshi.edgewall.org/i18n">
1337 <i18n:choose numeral="num" params="num">
1338 <p i18n:singular="" title="Things">
1339 There is <a href="$link" title="View thing">${num} thing</a>.
1340 </p>
1341 <p i18n:plural="" title="Things">
1342 There are <a href="$link" title="View things">${num} things</a>.
1343 </p>
1344 </i18n:choose>
1345 </html>""")
1346 translations = DummyTranslations({
1347 'Things': 'Sachen',
1348 'View thing': 'Sache betrachten',
1349 'View things': 'Sachen betrachten',
1350 ('There is [1:%(num)s thing].', 0): 'Da ist [1:%(num)s Sache].',
1351 ('There is [1:%(num)s thing].', 1): 'Da sind [1:%(num)s Sachen].'
1352 })
1353 translator = Translator(translations)
1354 translator.setup(tmpl)
1355 self.assertEqual(u"""<html>
1356 <p title="Sachen">Da ist <a href="/things" title="Sache betrachten">1 Sache</a>.</p>
1357 </html>""", tmpl.generate(link="/things", num=1).render(encoding=None))
1358 self.assertEqual(u"""<html>
1359 <p title="Sachen">Da sind <a href="/things" title="Sachen betrachten">3 Sachen</a>.</p>
1360 </html>""", tmpl.generate(link="/things", num=3).render(encoding=None))
1361
1362 def test_translate_i18n_choose_and_py_strip(self):
1363 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1364 xmlns:i18n="http://genshi.edgewall.org/i18n">
1365 <div i18n:choose="two; fname, lname">
1366 <p i18n:singular="">Foo $fname $lname</p>
1367 <p i18n:plural="">Foos $fname $lname</p>
1368 </div>
1369 </html>""")
1370 translations = DummyTranslations({
1371 ('Foo %(fname)s %(lname)s', 0): 'Voh %(fname)s %(lname)s',
1372 ('Foo %(fname)s %(lname)s', 1): 'Vohs %(fname)s %(lname)s',
1373 'Foo %(fname)s %(lname)s': 'Voh %(fname)s %(lname)s',
1374 'Foos %(fname)s %(lname)s': 'Vohs %(fname)s %(lname)s',
1375 })
1376 translator = Translator(translations)
1377 translator.setup(tmpl)
1378 self.assertEqual("""<html>
1379 <div>
1380 <p>Vohs John Doe</p>
1381 </div>
1382 </html>""", tmpl.generate(two=2, fname='John', lname='Doe').render())
1383
1384 def test_translate_i18n_choose_and_domain_and_py_strip(self):
1385 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1386 xmlns:i18n="http://genshi.edgewall.org/i18n"
1387 i18n:domain="foo">
1388 <div i18n:choose="two; fname, lname">
1389 <p i18n:singular="">Foo $fname $lname</p>
1390 <p i18n:plural="">Foos $fname $lname</p>
1391 </div>
1392 </html>""")
1393 translations = DummyTranslations()
1394 translations.add_domain('foo', {
1395 ('Foo %(fname)s %(lname)s', 0): 'Voh %(fname)s %(lname)s',
1396 ('Foo %(fname)s %(lname)s', 1): 'Vohs %(fname)s %(lname)s',
1397 'Foo %(fname)s %(lname)s': 'Voh %(fname)s %(lname)s',
1398 'Foos %(fname)s %(lname)s': 'Vohs %(fname)s %(lname)s',
1399 })
1400 translator = Translator(translations)
1401 translator.setup(tmpl)
1402 self.assertEqual("""<html>
1403 <div>
1404 <p>Vohs John Doe</p>
1405 </div>
1406 </html>""", tmpl.generate(two=2, fname='John', lname='Doe').render())
1407
1408 def test_translate_i18n_choose_and_singular_with_py_strip(self):
1409 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1410 xmlns:i18n="http://genshi.edgewall.org/i18n">
1411 <div i18n:choose="two; fname, lname">
1412 <p i18n:singular="" py:strip="">Foo $fname $lname</p>
1413 <p i18n:plural="">Foos $fname $lname</p>
1414 </div>
1415 <div i18n:choose="one; fname, lname">
1416 <p i18n:singular="" py:strip="">Foo $fname $lname</p>
1417 <p i18n:plural="">Foos $fname $lname</p>
1418 </div>
1419 </html>""")
1420 translations = DummyTranslations({
1421 ('Foo %(fname)s %(lname)s', 0): 'Voh %(fname)s %(lname)s',
1422 ('Foo %(fname)s %(lname)s', 1): 'Vohs %(fname)s %(lname)s',
1423 'Foo %(fname)s %(lname)s': 'Voh %(fname)s %(lname)s',
1424 'Foos %(fname)s %(lname)s': 'Vohs %(fname)s %(lname)s',
1425 })
1426 translator = Translator(translations)
1427 translator.setup(tmpl)
1428 self.assertEqual("""<html>
1429 <div>
1430 <p>Vohs John Doe</p>
1431 </div>
1432 <div>
1433 Voh John Doe
1434 </div>
1435 </html>""", tmpl.generate(
1436 one=1, two=2, fname='John',lname='Doe').render())
1437
1438 def test_translate_i18n_choose_and_plural_with_py_strip(self):
1439 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1440 xmlns:i18n="http://genshi.edgewall.org/i18n">
1441 <div i18n:choose="two; fname, lname">
1442 <p i18n:singular="" py:strip="">Foo $fname $lname</p>
1443 <p i18n:plural="">Foos $fname $lname</p>
1444 </div>
1445 </html>""")
1446 translations = DummyTranslations({
1447 ('Foo %(fname)s %(lname)s', 0): 'Voh %(fname)s %(lname)s',
1448 ('Foo %(fname)s %(lname)s', 1): 'Vohs %(fname)s %(lname)s',
1449 'Foo %(fname)s %(lname)s': 'Voh %(fname)s %(lname)s',
1450 'Foos %(fname)s %(lname)s': 'Vohs %(fname)s %(lname)s',
1451 })
1452 translator = Translator(translations)
1453 translator.setup(tmpl)
1454 self.assertEqual("""<html>
1455 <div>
1456 Voh John Doe
1457 </div>
1458 </html>""", tmpl.generate(two=1, fname='John', lname='Doe').render())
1459
1460 def test_extract_i18n_choose_as_attribute_and_py_strip(self):
1461 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1462 xmlns:i18n="http://genshi.edgewall.org/i18n">
1463 <div i18n:choose="one" py:strip="">
1464 <p i18n:singular="" py:strip="">FooBar</p>
1465 <p i18n:plural="" py:strip="">FooBars</p>
1466 </div>
1467 </html>""")
1468 translator = Translator()
1469 tmpl.add_directives(Translator.NAMESPACE, translator)
1470 messages = list(translator.extract(tmpl.stream))
1471 self.assertEqual(1, len(messages))
1472 self.assertEqual((3, 'ngettext', ('FooBar', 'FooBars'), []), messages[0])
1473
1474
1475 class DomainDirectiveTestCase(unittest.TestCase):
1476
1477 def test_translate_i18n_domain_with_msg_directives(self):
1478 #"""translate with i18n:domain and nested i18n:msg directives """
1479
1480 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1481 xmlns:i18n="http://genshi.edgewall.org/i18n">
1482 <div i18n:domain="foo">
1483 <p i18n:msg="">FooBar</p>
1484 <p i18n:msg="">Bar</p>
1485 </div>
1486 </html>""")
1487 translations = DummyTranslations({'Bar': 'Voh'})
1488 translations.add_domain('foo', {'FooBar': 'BarFoo', 'Bar': 'PT_Foo'})
1489 translator = Translator(translations)
1490 translator.setup(tmpl)
1491 self.assertEqual("""<html>
1492 <div>
1493 <p>BarFoo</p>
1494 <p>PT_Foo</p>
1495 </div>
1496 </html>""", tmpl.generate().render())
1497
1498 def test_translate_i18n_domain_with_inline_directives(self):
1499 #"""translate with inlined i18n:domain and i18n:msg directives"""
1500 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1501 xmlns:i18n="http://genshi.edgewall.org/i18n">
1502 <p i18n:msg="" i18n:domain="foo">FooBar</p>
1503 </html>""")
1504 translations = DummyTranslations({'Bar': 'Voh'})
1505 translations.add_domain('foo', {'FooBar': 'BarFoo'})
1506 translator = Translator(translations)
1507 translator.setup(tmpl)
1508 self.assertEqual("""<html>
1509 <p>BarFoo</p>
1510 </html>""", tmpl.generate().render())
1511
1512 def test_translate_i18n_domain_without_msg_directives(self):
1513 #"""translate domain call without i18n:msg directives still uses current domain"""
1514
1515 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1516 xmlns:i18n="http://genshi.edgewall.org/i18n">
1517 <p i18n:msg="">Bar</p>
1518 <div i18n:domain="foo">
1519 <p i18n:msg="">FooBar</p>
1520 <p i18n:msg="">Bar</p>
1521 <p>Bar</p>
1522 </div>
1523 <p>Bar</p>
1524 </html>""")
1525 translations = DummyTranslations({'Bar': 'Voh'})
1526 translations.add_domain('foo', {'FooBar': 'BarFoo', 'Bar': 'PT_Foo'})
1527 translator = Translator(translations)
1528 translator.setup(tmpl)
466 self.assertEqual("""<html> 1529 self.assertEqual("""<html>
467 <p>Voh</p> 1530 <p>Voh</p>
468 </html>""", tmpl.generate().render()) 1531 <div>
1532 <p>BarFoo</p>
1533 <p>PT_Foo</p>
1534 <p>PT_Foo</p>
1535 </div>
1536 <p>Voh</p>
1537 </html>""", tmpl.generate().render())
1538
1539 def test_translate_i18n_domain_as_directive_not_attribute(self):
1540 #"""translate with domain as directive"""
1541
1542 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1543 xmlns:i18n="http://genshi.edgewall.org/i18n">
1544 <i18n:domain name="foo">
1545 <p i18n:msg="">FooBar</p>
1546 <p i18n:msg="">Bar</p>
1547 <p>Bar</p>
1548 </i18n:domain>
1549 <p>Bar</p>
1550 </html>""")
1551 translations = DummyTranslations({'Bar': 'Voh'})
1552 translations.add_domain('foo', {'FooBar': 'BarFoo', 'Bar': 'PT_Foo'})
1553 translator = Translator(translations)
1554 translator.setup(tmpl)
1555 self.assertEqual("""<html>
1556 <p>BarFoo</p>
1557 <p>PT_Foo</p>
1558 <p>PT_Foo</p>
1559 <p>Voh</p>
1560 </html>""", tmpl.generate().render())
1561
1562 def test_translate_i18n_domain_nested_directives(self):
1563 #"""translate with nested i18n:domain directives"""
1564
1565 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1566 xmlns:i18n="http://genshi.edgewall.org/i18n">
1567 <p i18n:msg="">Bar</p>
1568 <div i18n:domain="foo">
1569 <p i18n:msg="">FooBar</p>
1570 <p i18n:domain="bar" i18n:msg="">Bar</p>
1571 <p>Bar</p>
1572 </div>
1573 <p>Bar</p>
1574 </html>""")
1575 translations = DummyTranslations({'Bar': 'Voh'})
1576 translations.add_domain('foo', {'FooBar': 'BarFoo', 'Bar': 'foo_Bar'})
1577 translations.add_domain('bar', {'Bar': 'bar_Bar'})
1578 translator = Translator(translations)
1579 translator.setup(tmpl)
1580 self.assertEqual("""<html>
1581 <p>Voh</p>
1582 <div>
1583 <p>BarFoo</p>
1584 <p>bar_Bar</p>
1585 <p>foo_Bar</p>
1586 </div>
1587 <p>Voh</p>
1588 </html>""", tmpl.generate().render())
1589
1590 def test_translate_i18n_domain_with_empty_nested_domain_directive(self):
1591 #"""translate with empty nested i18n:domain directive does not use dngettext"""
1592
1593 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1594 xmlns:i18n="http://genshi.edgewall.org/i18n">
1595 <p i18n:msg="">Bar</p>
1596 <div i18n:domain="foo">
1597 <p i18n:msg="">FooBar</p>
1598 <p i18n:domain="" i18n:msg="">Bar</p>
1599 <p>Bar</p>
1600 </div>
1601 <p>Bar</p>
1602 </html>""")
1603 translations = DummyTranslations({'Bar': 'Voh'})
1604 translations.add_domain('foo', {'FooBar': 'BarFoo', 'Bar': 'foo_Bar'})
1605 translations.add_domain('bar', {'Bar': 'bar_Bar'})
1606 translator = Translator(translations)
1607 translator.setup(tmpl)
1608 self.assertEqual("""<html>
1609 <p>Voh</p>
1610 <div>
1611 <p>BarFoo</p>
1612 <p>Voh</p>
1613 <p>foo_Bar</p>
1614 </div>
1615 <p>Voh</p>
1616 </html>""", tmpl.generate().render())
1617
1618 def test_translate_i18n_domain_with_inline_directive_on_START_NS(self):
1619 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1620 xmlns:i18n="http://genshi.edgewall.org/i18n" i18n:domain="foo">
1621 <p i18n:msg="">FooBar</p>
1622 </html>""")
1623 translations = DummyTranslations({'Bar': 'Voh'})
1624 translations.add_domain('foo', {'FooBar': 'BarFoo'})
1625 translator = Translator(translations)
1626 translator.setup(tmpl)
1627 self.assertEqual("""<html>
1628 <p>BarFoo</p>
1629 </html>""", tmpl.generate().render())
1630
1631 def test_translate_i18n_domain_with_inline_directive_on_START_NS_with_py_strip(self):
1632 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
1633 xmlns:i18n="http://genshi.edgewall.org/i18n"
1634 i18n:domain="foo" py:strip="">
1635 <p i18n:msg="">FooBar</p>
1636 </html>""")
1637 translations = DummyTranslations({'Bar': 'Voh'})
1638 translations.add_domain('foo', {'FooBar': 'BarFoo'})
1639 translator = Translator(translations)
1640 translator.setup(tmpl)
1641 self.assertEqual("""
1642 <p>BarFoo</p>
1643 """, tmpl.generate().render())
1644
1645 def test_translate_i18n_domain_with_nested_includes(self):
1646 import os, shutil, tempfile
1647 from genshi.template.loader import TemplateLoader
1648 dirname = tempfile.mkdtemp(suffix='genshi_test')
1649 try:
1650 for idx in range(7):
1651 file1 = open(os.path.join(dirname, 'tmpl%d.html' % idx), 'w')
1652 try:
1653 file1.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
1654 xmlns:py="http://genshi.edgewall.org/"
1655 xmlns:i18n="http://genshi.edgewall.org/i18n" py:strip="">
1656 <div>Included tmpl$idx</div>
1657 <p i18n:msg="idx">Bar $idx</p>
1658 <p i18n:domain="bar">Bar</p>
1659 <p i18n:msg="idx" i18n:domain="">Bar $idx</p>
1660 <p i18n:domain="" i18n:msg="idx">Bar $idx</p>
1661 <py:if test="idx &lt; 6">
1662 <xi:include href="tmpl${idx}.html" py:with="idx = idx+1"/>
1663 </py:if>
1664 </html>""")
1665 finally:
1666 file1.close()
1667
1668 file2 = open(os.path.join(dirname, 'tmpl10.html'), 'w')
1669 try:
1670 file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
1671 xmlns:py="http://genshi.edgewall.org/"
1672 xmlns:i18n="http://genshi.edgewall.org/i18n"
1673 i18n:domain="foo">
1674 <xi:include href="tmpl${idx}.html" py:with="idx = idx+1"/>
1675 </html>""")
1676 finally:
1677 file2.close()
1678
1679 def callback(template):
1680 translations = DummyTranslations({'Bar %(idx)s': 'Voh %(idx)s'})
1681 translations.add_domain('foo', {'Bar %(idx)s': 'foo_Bar %(idx)s'})
1682 translations.add_domain('bar', {'Bar': 'bar_Bar'})
1683 translator = Translator(translations)
1684 translator.setup(template)
1685 loader = TemplateLoader([dirname], callback=callback)
1686 tmpl = loader.load('tmpl10.html')
1687
1688 self.assertEqual("""<html>
1689 <div>Included tmpl0</div>
1690 <p>foo_Bar 0</p>
1691 <p>bar_Bar</p>
1692 <p>Voh 0</p>
1693 <p>Voh 0</p>
1694 <div>Included tmpl1</div>
1695 <p>foo_Bar 1</p>
1696 <p>bar_Bar</p>
1697 <p>Voh 1</p>
1698 <p>Voh 1</p>
1699 <div>Included tmpl2</div>
1700 <p>foo_Bar 2</p>
1701 <p>bar_Bar</p>
1702 <p>Voh 2</p>
1703 <p>Voh 2</p>
1704 <div>Included tmpl3</div>
1705 <p>foo_Bar 3</p>
1706 <p>bar_Bar</p>
1707 <p>Voh 3</p>
1708 <p>Voh 3</p>
1709 <div>Included tmpl4</div>
1710 <p>foo_Bar 4</p>
1711 <p>bar_Bar</p>
1712 <p>Voh 4</p>
1713 <p>Voh 4</p>
1714 <div>Included tmpl5</div>
1715 <p>foo_Bar 5</p>
1716 <p>bar_Bar</p>
1717 <p>Voh 5</p>
1718 <p>Voh 5</p>
1719 <div>Included tmpl6</div>
1720 <p>foo_Bar 6</p>
1721 <p>bar_Bar</p>
1722 <p>Voh 6</p>
1723 <p>Voh 6</p>
1724 </html>""", tmpl.generate(idx=-1).render())
1725 finally:
1726 shutil.rmtree(dirname)
1727
1728 def test_translate_i18n_domain_with_nested_includes_with_translatable_attrs(self):
1729 import os, shutil, tempfile
1730 from genshi.template.loader import TemplateLoader
1731 dirname = tempfile.mkdtemp(suffix='genshi_test')
1732 try:
1733 for idx in range(4):
1734 file1 = open(os.path.join(dirname, 'tmpl%d.html' % idx), 'w')
1735 try:
1736 file1.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
1737 xmlns:py="http://genshi.edgewall.org/"
1738 xmlns:i18n="http://genshi.edgewall.org/i18n" py:strip="">
1739 <div>Included tmpl$idx</div>
1740 <p title="${dg('foo', 'Bar %(idx)s') % dict(idx=idx)}" i18n:msg="idx">Bar $idx</p>
1741 <p title="Bar" i18n:domain="bar">Bar</p>
1742 <p title="Bar" i18n:msg="idx" i18n:domain="">Bar $idx</p>
1743 <p i18n:msg="idx" i18n:domain="" title="Bar">Bar $idx</p>
1744 <p i18n:domain="" i18n:msg="idx" title="Bar">Bar $idx</p>
1745 <py:if test="idx &lt; 3">
1746 <xi:include href="tmpl${idx}.html" py:with="idx = idx+1"/>
1747 </py:if>
1748 </html>""")
1749 finally:
1750 file1.close()
1751
1752 file2 = open(os.path.join(dirname, 'tmpl10.html'), 'w')
1753 try:
1754 file2.write("""<html xmlns:xi="http://www.w3.org/2001/XInclude"
1755 xmlns:py="http://genshi.edgewall.org/"
1756 xmlns:i18n="http://genshi.edgewall.org/i18n"
1757 i18n:domain="foo">
1758 <xi:include href="tmpl${idx}.html" py:with="idx = idx+1"/>
1759 </html>""")
1760 finally:
1761 file2.close()
1762
1763 translations = DummyTranslations({'Bar %(idx)s': 'Voh %(idx)s',
1764 'Bar': 'Voh'})
1765 translations.add_domain('foo', {'Bar %(idx)s': 'foo_Bar %(idx)s'})
1766 translations.add_domain('bar', {'Bar': 'bar_Bar'})
1767 translator = Translator(translations)
1768
1769 def callback(template):
1770 translator.setup(template)
1771 loader = TemplateLoader([dirname], callback=callback)
1772 tmpl = loader.load('tmpl10.html')
1773
1774 self.assertEqual("""<html>
1775 <div>Included tmpl0</div>
1776 <p title="foo_Bar 0">foo_Bar 0</p>
1777 <p title="bar_Bar">bar_Bar</p>
1778 <p title="Voh">Voh 0</p>
1779 <p title="Voh">Voh 0</p>
1780 <p title="Voh">Voh 0</p>
1781 <div>Included tmpl1</div>
1782 <p title="foo_Bar 1">foo_Bar 1</p>
1783 <p title="bar_Bar">bar_Bar</p>
1784 <p title="Voh">Voh 1</p>
1785 <p title="Voh">Voh 1</p>
1786 <p title="Voh">Voh 1</p>
1787 <div>Included tmpl2</div>
1788 <p title="foo_Bar 2">foo_Bar 2</p>
1789 <p title="bar_Bar">bar_Bar</p>
1790 <p title="Voh">Voh 2</p>
1791 <p title="Voh">Voh 2</p>
1792 <p title="Voh">Voh 2</p>
1793 <div>Included tmpl3</div>
1794 <p title="foo_Bar 3">foo_Bar 3</p>
1795 <p title="bar_Bar">bar_Bar</p>
1796 <p title="Voh">Voh 3</p>
1797 <p title="Voh">Voh 3</p>
1798 <p title="Voh">Voh 3</p>
1799 </html>""", tmpl.generate(idx=-1,
1800 dg=translations.dugettext).render())
1801 finally:
1802 shutil.rmtree(dirname)
469 1803
470 1804
471 class ExtractTestCase(unittest.TestCase): 1805 class ExtractTestCase(unittest.TestCase):
472 1806
473 def test_markup_template_extraction(self): 1807 def test_markup_template_extraction(self):
481 <p>${ngettext("You have %d item", "You have %d items", num)}</p> 1815 <p>${ngettext("You have %d item", "You have %d items", num)}</p>
482 </body> 1816 </body>
483 </html>""") 1817 </html>""")
484 results = list(extract(buf, ['_', 'ngettext'], [], {})) 1818 results = list(extract(buf, ['_', 'ngettext'], [], {}))
485 self.assertEqual([ 1819 self.assertEqual([
486 (3, None, u'Example', []), 1820 (3, None, 'Example', []),
487 (6, None, u'Example', []), 1821 (6, None, 'Example', []),
488 (7, '_', u'Hello, %(name)s', []), 1822 (7, '_', 'Hello, %(name)s', []),
489 (8, 'ngettext', (u'You have %d item', u'You have %d items', None), 1823 (8, 'ngettext', ('You have %d item', 'You have %d items', None),
490 []), 1824 []),
491 ], results) 1825 ], results)
492 1826
493 def test_extraction_without_text(self): 1827 def test_extraction_without_text(self):
494 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/"> 1828 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/">
497 </html>""") 1831 </html>""")
498 results = list(extract(buf, ['_', 'ngettext'], [], { 1832 results = list(extract(buf, ['_', 'ngettext'], [], {
499 'extract_text': 'no' 1833 'extract_text': 'no'
500 })) 1834 }))
501 self.assertEqual([ 1835 self.assertEqual([
502 (3, 'ngettext', (u'Singular', u'Plural', None), []), 1836 (3, 'ngettext', ('Singular', 'Plural', None), []),
503 ], results) 1837 ], results)
504 1838
505 def test_text_template_extraction(self): 1839 def test_text_template_extraction(self):
506 buf = StringIO("""${_("Dear %(name)s") % {'name': name}}, 1840 buf = StringIO("""${_("Dear %(name)s") % {'name': name}},
507 1841
508 ${ngettext("Your item:", "Your items", len(items))} 1842 ${ngettext("Your item:", "Your items", len(items))}
509 #for item in items 1843 #for item in items
510 * $item 1844 * $item
511 #end 1845 #end
512 1846
513 All the best, 1847 All the best,
514 Foobar""") 1848 Foobar""")
515 results = list(extract(buf, ['_', 'ngettext'], [], { 1849 results = list(extract(buf, ['_', 'ngettext'], [], {
516 'template_class': 'genshi.template:TextTemplate' 1850 'template_class': 'genshi.template:TextTemplate'
517 })) 1851 }))
518 self.assertEqual([ 1852 self.assertEqual([
519 (1, '_', u'Dear %(name)s', []), 1853 (1, '_', 'Dear %(name)s', []),
520 (3, 'ngettext', (u'Your item:', u'Your items', None), []), 1854 (3, 'ngettext', ('Your item:', 'Your items', None), []),
521 (7, None, u'All the best,\n Foobar', []) 1855 (7, None, 'All the best,\n Foobar', [])
522 ], results) 1856 ], results)
523 1857
524 def test_extraction_with_keyword_arg(self): 1858 def test_extraction_with_keyword_arg(self):
525 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/"> 1859 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/">
526 ${gettext('Foobar', foo='bar')} 1860 ${gettext('Foobar', foo='bar')}
527 </html>""") 1861 </html>""")
528 results = list(extract(buf, ['gettext'], [], {})) 1862 results = list(extract(buf, ['gettext'], [], {}))
529 self.assertEqual([ 1863 self.assertEqual([
530 (2, 'gettext', (u'Foobar'), []), 1864 (2, 'gettext', ('Foobar'), []),
531 ], results) 1865 ], results)
532 1866
533 def test_extraction_with_nonstring_arg(self): 1867 def test_extraction_with_nonstring_arg(self):
534 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/"> 1868 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/">
535 ${dgettext(curdomain, 'Foobar')} 1869 ${dgettext(curdomain, 'Foobar')}
536 </html>""") 1870 </html>""")
537 results = list(extract(buf, ['dgettext'], [], {})) 1871 results = list(extract(buf, ['dgettext'], [], {}))
538 self.assertEqual([ 1872 self.assertEqual([
539 (2, 'dgettext', (None, u'Foobar'), []), 1873 (2, 'dgettext', (None, 'Foobar'), []),
540 ], results) 1874 ], results)
541 1875
542 def test_extraction_inside_ignored_tags(self): 1876 def test_extraction_inside_ignored_tags(self):
543 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/"> 1877 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/">
544 <script type="text/javascript"> 1878 <script type="text/javascript">
548 }); 1882 });
549 </script> 1883 </script>
550 </html>""") 1884 </html>""")
551 results = list(extract(buf, ['_'], [], {})) 1885 results = list(extract(buf, ['_'], [], {}))
552 self.assertEqual([ 1886 self.assertEqual([
553 (5, '_', u'Please wait...', []), 1887 (5, '_', 'Please wait...', []),
554 ], results) 1888 ], results)
555 1889
556 def test_extraction_inside_ignored_tags_with_directives(self): 1890 def test_extraction_inside_ignored_tags_with_directives(self):
557 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/"> 1891 buf = StringIO("""<html xmlns:py="http://genshi.edgewall.org/">
558 <script type="text/javascript"> 1892 <script type="text/javascript">
561 </py:if> 1895 </py:if>
562 </script> 1896 </script>
563 </html>""") 1897 </html>""")
564 self.assertEqual([], list(extract(buf, ['_'], [], {}))) 1898 self.assertEqual([], list(extract(buf, ['_'], [], {})))
565 1899
1900 def test_extract_py_def_directive_with_py_strip(self):
1901 # Failed extraction from Trac
1902 tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/" py:strip="">
1903 <py:def function="diff_options_fields(diff)">
1904 <label for="style">View differences</label>
1905 <select id="style" name="style">
1906 <option selected="${diff.style == 'inline' or None}"
1907 value="inline">inline</option>
1908 <option selected="${diff.style == 'sidebyside' or None}"
1909 value="sidebyside">side by side</option>
1910 </select>
1911 <div class="field">
1912 Show <input type="text" name="contextlines" id="contextlines" size="2"
1913 maxlength="3" value="${diff.options.contextlines &lt; 0 and 'all' or diff.options.contextlines}" />
1914 <label for="contextlines">lines around each change</label>
1915 </div>
1916 <fieldset id="ignore" py:with="options = diff.options">
1917 <legend>Ignore:</legend>
1918 <div class="field">
1919 <input type="checkbox" id="ignoreblanklines" name="ignoreblanklines"
1920 checked="${options.ignoreblanklines or None}" />
1921 <label for="ignoreblanklines">Blank lines</label>
1922 </div>
1923 <div class="field">
1924 <input type="checkbox" id="ignorecase" name="ignorecase"
1925 checked="${options.ignorecase or None}" />
1926 <label for="ignorecase">Case changes</label>
1927 </div>
1928 <div class="field">
1929 <input type="checkbox" id="ignorewhitespace" name="ignorewhitespace"
1930 checked="${options.ignorewhitespace or None}" />
1931 <label for="ignorewhitespace">White space changes</label>
1932 </div>
1933 </fieldset>
1934 <div class="buttons">
1935 <input type="submit" name="update" value="${_('Update')}" />
1936 </div>
1937 </py:def></html>""")
1938 translator = Translator()
1939 tmpl.add_directives(Translator.NAMESPACE, translator)
1940 messages = list(translator.extract(tmpl.stream))
1941 self.assertEqual(10, len(messages))
1942 self.assertEqual([
1943 (3, None, 'View differences', []),
1944 (6, None, 'inline', []),
1945 (8, None, 'side by side', []),
1946 (10, None, 'Show', []),
1947 (13, None, 'lines around each change', []),
1948 (16, None, 'Ignore:', []),
1949 (20, None, 'Blank lines', []),
1950 (25, None, 'Case changes',[]),
1951 (30, None, 'White space changes', []),
1952 (34, '_', 'Update', [])], messages)
1953
566 1954
567 def suite(): 1955 def suite():
568 suite = unittest.TestSuite() 1956 suite = unittest.TestSuite()
569 suite.addTest(doctest.DocTestSuite(Translator.__module__)) 1957 suite.addTest(doctest.DocTestSuite(Translator.__module__))
570 suite.addTest(unittest.makeSuite(TranslatorTestCase, 'test')) 1958 suite.addTest(unittest.makeSuite(TranslatorTestCase, 'test'))
1959 suite.addTest(unittest.makeSuite(MsgDirectiveTestCase, 'test'))
1960 suite.addTest(unittest.makeSuite(ChooseDirectiveTestCase, 'test'))
1961 suite.addTest(unittest.makeSuite(DomainDirectiveTestCase, 'test'))
571 suite.addTest(unittest.makeSuite(ExtractTestCase, 'test')) 1962 suite.addTest(unittest.makeSuite(ExtractTestCase, 'test'))
572 return suite 1963 return suite
573 1964
574 if __name__ == '__main__': 1965 if __name__ == '__main__':
575 unittest.main(defaultTest='suite') 1966 unittest.main(defaultTest='suite')
Copyright (C) 2012-2017 Edgewall Software