_make_boundary(): Fix for SF bug #745478, broken boundary calculation
[python/dscho.git] / Lib / test / test_gettext.py
blob4a17230546b098643b2dfed1560dce43de4cbac9
1 import os
2 import base64
3 import shutil
4 import gettext
5 import unittest
7 from test.test_support import run_suite
10 # TODO:
11 # - Add new tests, for example for "dgettext"
12 # - Remove dummy tests, for example testing for single and double quotes
13 # has no sense, it would have if we were testing a parser (i.e. pygettext)
14 # - Tests should have only one assert.
16 GNU_MO_DATA = '''\
17 3hIElQAAAAAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj
18 AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD
19 AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh
20 eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU
21 aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u
22 CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh
23 Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51
24 ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt
25 MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k
26 YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN
27 SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4
28 NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0
29 ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0
30 d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo
31 eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn
32 IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1
33 ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA==
34 '''
36 UMO_DATA = '''\
37 3hIElQAAAAACAAAAHAAAACwAAAAFAAAAPAAAAAAAAABQAAAABAAAAFEAAAAPAQAAVgAAAAQAAABm
38 AQAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAYWLDngBQcm9qZWN0LUlkLVZlcnNpb246IDIuMApQTy1S
39 ZXZpc2lvbi1EYXRlOiAyMDAzLTA0LTExIDEyOjQyLTA0MDAKTGFzdC1UcmFuc2xhdG9yOiBCYXJy
40 eSBBLiBXQXJzYXcgPGJhcnJ5QHB5dGhvbi5vcmc+Ckxhbmd1YWdlLVRlYW06IFhYIDxweXRob24t
41 ZGV2QHB5dGhvbi5vcmc+Ck1JTUUtVmVyc2lvbjogMS4wCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFp
42 bjsgY2hhcnNldD11dGYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA3Yml0CkdlbmVyYXRl
43 ZC1CeTogbWFudWFsbHkKAMKkeXoA
44 '''
46 MMO_DATA = '''\
47 3hIElQAAAAABAAAAHAAAACQAAAADAAAALAAAAAAAAAA4AAAAeAEAADkAAAABAAAAAAAAAAAAAAAA
48 UHJvamVjdC1JZC1WZXJzaW9uOiBObyBQcm9qZWN0IDAuMApQT1QtQ3JlYXRpb24tRGF0ZTogV2Vk
49 IERlYyAxMSAwNzo0NDoxNSAyMDAyClBPLVJldmlzaW9uLURhdGU6IDIwMDItMDgtMTQgMDE6MTg6
50 NTgrMDA6MDAKTGFzdC1UcmFuc2xhdG9yOiBKb2huIERvZSA8amRvZUBleGFtcGxlLmNvbT4KSmFu
51 ZSBGb29iYXIgPGpmb29iYXJAZXhhbXBsZS5jb20+Ckxhbmd1YWdlLVRlYW06IHh4IDx4eEBleGFt
52 cGxlLmNvbT4KTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFy
53 c2V0PWlzby04ODU5LTE1CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFi
54 bGUKR2VuZXJhdGVkLUJ5OiBweWdldHRleHQucHkgMS4zCgA=
55 '''
57 LOCALEDIR = os.path.join('xx', 'LC_MESSAGES')
58 MOFILE = os.path.join(LOCALEDIR, 'gettext.mo')
59 UMOFILE = os.path.join(LOCALEDIR, 'ugettext.mo')
60 MMOFILE = os.path.join(LOCALEDIR, 'metadata.mo')
61 try:
62 LANG = os.environ['LANGUAGE']
63 except:
64 LANG = 'en'
67 class GettextBaseTest(unittest.TestCase):
68 def setUp(self):
69 os.makedirs(LOCALEDIR)
70 fp = open(MOFILE, 'wb')
71 fp.write(base64.decodestring(GNU_MO_DATA))
72 fp.close()
73 fp = open(UMOFILE, 'wb')
74 fp.write(base64.decodestring(UMO_DATA))
75 fp.close()
76 fp = open(MMOFILE, 'wb')
77 fp.write(base64.decodestring(MMO_DATA))
78 fp.close()
79 os.environ['LANGUAGE'] = 'xx'
81 def tearDown(self):
82 os.environ['LANGUAGE'] = LANG
83 shutil.rmtree(os.path.split(LOCALEDIR)[0])
86 class GettextTestCase1(GettextBaseTest):
87 def setUp(self):
88 GettextBaseTest.setUp(self)
89 self.localedir = os.curdir
90 self.mofile = MOFILE
91 gettext.install('gettext', self.localedir)
93 def test_some_translations(self):
94 eq = self.assertEqual
95 # test some translations
96 eq(_('albatross'), 'albatross')
97 eq(_(u'mullusk'), 'bacon')
98 eq(_(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove')
99 eq(_(ur'nudge nudge'), 'wink wink')
101 def test_double_quotes(self):
102 eq = self.assertEqual
103 # double quotes
104 eq(_("albatross"), 'albatross')
105 eq(_(u"mullusk"), 'bacon')
106 eq(_(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
107 eq(_(ur"nudge nudge"), 'wink wink')
109 def test_triple_single_quotes(self):
110 eq = self.assertEqual
111 # triple single quotes
112 eq(_('''albatross'''), 'albatross')
113 eq(_(u'''mullusk'''), 'bacon')
114 eq(_(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
115 eq(_(ur'''nudge nudge'''), 'wink wink')
117 def test_triple_double_quotes(self):
118 eq = self.assertEqual
119 # triple double quotes
120 eq(_("""albatross"""), 'albatross')
121 eq(_(u"""mullusk"""), 'bacon')
122 eq(_(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
123 eq(_(ur"""nudge nudge"""), 'wink wink')
125 def test_multiline_strings(self):
126 eq = self.assertEqual
127 # multiline strings
128 eq(_('''This module provides internationalization and localization
129 support for your Python programs by providing an interface to the GNU
130 gettext message catalog library.'''),
131 '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba
132 fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH
133 trggrkg zrffntr pngnybt yvoenel.''')
135 def test_the_alternative_interface(self):
136 eq = self.assertEqual
137 # test the alternative interface
138 fp = open(self.mofile, 'rb')
139 t = gettext.GNUTranslations(fp)
140 fp.close()
141 # Install the translation object
142 t.install()
143 eq(_('nudge nudge'), 'wink wink')
144 # Try unicode return type
145 t.install(unicode=True)
146 eq(_('mullusk'), 'bacon')
149 class GettextTestCase2(GettextBaseTest):
150 def setUp(self):
151 GettextBaseTest.setUp(self)
152 self.localedir = os.curdir
153 # Set up the bindings
154 gettext.bindtextdomain('gettext', self.localedir)
155 gettext.textdomain('gettext')
156 # For convenience
157 self._ = gettext.gettext
159 def test_bindtextdomain(self):
160 self.assertEqual(gettext.bindtextdomain('gettext'), self.localedir)
162 def test_textdomain(self):
163 self.assertEqual(gettext.textdomain(), 'gettext')
165 def test_some_translations(self):
166 eq = self.assertEqual
167 # test some translations
168 eq(self._('albatross'), 'albatross')
169 eq(self._(u'mullusk'), 'bacon')
170 eq(self._(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove')
171 eq(self._(ur'nudge nudge'), 'wink wink')
173 def test_double_quotes(self):
174 eq = self.assertEqual
175 # double quotes
176 eq(self._("albatross"), 'albatross')
177 eq(self._(u"mullusk"), 'bacon')
178 eq(self._(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
179 eq(self._(ur"nudge nudge"), 'wink wink')
181 def test_triple_single_quotes(self):
182 eq = self.assertEqual
183 # triple single quotes
184 eq(self._('''albatross'''), 'albatross')
185 eq(self._(u'''mullusk'''), 'bacon')
186 eq(self._(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
187 eq(self._(ur'''nudge nudge'''), 'wink wink')
189 def test_triple_double_quotes(self):
190 eq = self.assertEqual
191 # triple double quotes
192 eq(self._("""albatross"""), 'albatross')
193 eq(self._(u"""mullusk"""), 'bacon')
194 eq(self._(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
195 eq(self._(ur"""nudge nudge"""), 'wink wink')
197 def test_multiline_strings(self):
198 eq = self.assertEqual
199 # multiline strings
200 eq(self._('''This module provides internationalization and localization
201 support for your Python programs by providing an interface to the GNU
202 gettext message catalog library.'''),
203 '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba
204 fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH
205 trggrkg zrffntr pngnybt yvoenel.''')
208 class PluralFormsTestCase(GettextBaseTest):
209 def setUp(self):
210 GettextBaseTest.setUp(self)
211 self.mofile = MOFILE
213 def test_plural_forms1(self):
214 eq = self.assertEqual
215 x = gettext.ngettext('There is %s file', 'There are %s files', 1)
216 eq(x, 'Hay %s fichero')
217 x = gettext.ngettext('There is %s file', 'There are %s files', 2)
218 eq(x, 'Hay %s ficheros')
220 def test_plural_forms2(self):
221 eq = self.assertEqual
222 fp = open(self.mofile, 'rb')
223 t = gettext.GNUTranslations(fp)
224 fp.close()
225 x = t.ngettext('There is %s file', 'There are %s files', 1)
226 eq(x, 'Hay %s fichero')
227 x = t.ngettext('There is %s file', 'There are %s files', 2)
228 eq(x, 'Hay %s ficheros')
230 def test_hu(self):
231 eq = self.assertEqual
232 f = gettext.c2py('0')
233 s = ''.join([ str(f(x)) for x in range(200) ])
234 eq(s, "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
236 def test_de(self):
237 eq = self.assertEqual
238 f = gettext.c2py('n != 1')
239 s = ''.join([ str(f(x)) for x in range(200) ])
240 eq(s, "10111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
242 def test_fr(self):
243 eq = self.assertEqual
244 f = gettext.c2py('n>1')
245 s = ''.join([ str(f(x)) for x in range(200) ])
246 eq(s, "00111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
248 def test_gd(self):
249 eq = self.assertEqual
250 f = gettext.c2py('n==1 ? 0 : n==2 ? 1 : 2')
251 s = ''.join([ str(f(x)) for x in range(200) ])
252 eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
254 def test_gd2(self):
255 eq = self.assertEqual
256 # Tests the combination of parentheses and "?:"
257 f = gettext.c2py('n==1 ? 0 : (n==2 ? 1 : 2)')
258 s = ''.join([ str(f(x)) for x in range(200) ])
259 eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
261 def test_lt(self):
262 eq = self.assertEqual
263 f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2')
264 s = ''.join([ str(f(x)) for x in range(200) ])
265 eq(s, "20111111112222222222201111111120111111112011111111201111111120111111112011111111201111111120111111112011111111222222222220111111112011111111201111111120111111112011111111201111111120111111112011111111")
267 def test_ru(self):
268 eq = self.assertEqual
269 f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2')
270 s = ''.join([ str(f(x)) for x in range(200) ])
271 eq(s, "20111222222222222222201112222220111222222011122222201112222220111222222011122222201112222220111222222011122222222222222220111222222011122222201112222220111222222011122222201112222220111222222011122222")
273 def test_pl(self):
274 eq = self.assertEqual
275 f = gettext.c2py('n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2')
276 s = ''.join([ str(f(x)) for x in range(200) ])
277 eq(s, "20111222222222222222221112222222111222222211122222221112222222111222222211122222221112222222111222222211122222222222222222111222222211122222221112222222111222222211122222221112222222111222222211122222")
279 def test_sl(self):
280 eq = self.assertEqual
281 f = gettext.c2py('n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3')
282 s = ''.join([ str(f(x)) for x in range(200) ])
283 eq(s, "30122333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333012233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333")
285 def test_security(self):
286 raises = self.assertRaises
287 # Test for a dangerous expression
288 raises(ValueError, gettext.c2py, "os.chmod('/etc/passwd',0777)")
291 class UnicodeTranslationsTest(GettextBaseTest):
292 def setUp(self):
293 GettextBaseTest.setUp(self)
294 fp = open(UMOFILE, 'rb')
295 try:
296 self.t = gettext.GNUTranslations(fp)
297 finally:
298 fp.close()
299 self._ = self.t.ugettext
301 def test_unicode_msgid(self):
302 unless = self.failUnless
303 unless(isinstance(self._(''), unicode))
304 unless(isinstance(self._(u''), unicode))
306 def test_unicode_msgstr(self):
307 eq = self.assertEqual
308 eq(self._(u'ab\xde'), u'\xa4yz')
311 class WeirdMetadataTest(GettextBaseTest):
312 def setUp(self):
313 GettextBaseTest.setUp(self)
314 fp = open(MMOFILE, 'rb')
315 try:
316 try:
317 self.t = gettext.GNUTranslations(fp)
318 except:
319 self.tearDown()
320 raise
321 finally:
322 fp.close()
324 def test_weird_metadata(self):
325 info = self.t.info()
326 self.assertEqual(info['last-translator'],
327 'John Doe <jdoe@example.com>\nJane Foobar <jfoobar@example.com>')
330 def suite():
331 suite = unittest.TestSuite()
332 suite.addTest(unittest.makeSuite(GettextTestCase1))
333 suite.addTest(unittest.makeSuite(GettextTestCase2))
334 suite.addTest(unittest.makeSuite(PluralFormsTestCase))
335 suite.addTest(unittest.makeSuite(UnicodeTranslationsTest))
336 suite.addTest(unittest.makeSuite(WeirdMetadataTest))
337 return suite
340 def test_main():
341 run_suite(suite())
344 if __name__ == '__main__':
345 test_main()
348 # For reference, here's the .po file used to created the GNU_MO_DATA above.
350 # The original version was automatically generated from the sources with
351 # pygettext. Later it was manually modified to add plural forms support.
354 # Dummy translation for the Python test_gettext.py module.
355 # Copyright (C) 2001 Python Software Foundation
356 # Barry Warsaw <barry@python.org>, 2000.
358 msgid ""
359 msgstr ""
360 "Project-Id-Version: 2.0\n"
361 "PO-Revision-Date: 2003-04-11 14:32-0400\n"
362 "Last-Translator: J. David Ibanez <j-david@noos.fr>\n"
363 "Language-Team: XX <python-dev@python.org>\n"
364 "MIME-Version: 1.0\n"
365 "Content-Type: text/plain; charset=iso-8859-1\n"
366 "Content-Transfer-Encoding: 8bit\n"
367 "Generated-By: pygettext.py 1.1\n"
368 "Plural-Forms: nplurals=2; plural=n!=1;\n"
370 #: test_gettext.py:19 test_gettext.py:25 test_gettext.py:31 test_gettext.py:37
371 #: test_gettext.py:51 test_gettext.py:80 test_gettext.py:86 test_gettext.py:92
372 #: test_gettext.py:98
373 msgid "nudge nudge"
374 msgstr "wink wink"
376 #: test_gettext.py:16 test_gettext.py:22 test_gettext.py:28 test_gettext.py:34
377 #: test_gettext.py:77 test_gettext.py:83 test_gettext.py:89 test_gettext.py:95
378 msgid "albatross"
379 msgstr ""
381 #: test_gettext.py:18 test_gettext.py:24 test_gettext.py:30 test_gettext.py:36
382 #: test_gettext.py:79 test_gettext.py:85 test_gettext.py:91 test_gettext.py:97
383 msgid "Raymond Luxury Yach-t"
384 msgstr "Throatwobbler Mangrove"
386 #: test_gettext.py:17 test_gettext.py:23 test_gettext.py:29 test_gettext.py:35
387 #: test_gettext.py:56 test_gettext.py:78 test_gettext.py:84 test_gettext.py:90
388 #: test_gettext.py:96
389 msgid "mullusk"
390 msgstr "bacon"
392 #: test_gettext.py:40 test_gettext.py:101
393 msgid ""
394 "This module provides internationalization and localization\n"
395 "support for your Python programs by providing an interface to the GNU\n"
396 "gettext message catalog library."
397 msgstr ""
398 "Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba\n"
399 "fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH\n"
400 "trggrkg zrffntr pngnybt yvoenel."
402 # Manually added, as neither pygettext nor xgettext support plural forms
403 # in Python.
404 msgid "There is %s file"
405 msgid_plural "There are %s files"
406 msgstr[0] "Hay %s fichero"
407 msgstr[1] "Hay %s ficheros"
410 # Here's the second example po file example, used to generate the UMO_DATA
411 # containing utf-8 encoded Unicode strings
414 # Dummy translation for the Python test_gettext.py module.
415 # Copyright (C) 2001 Python Software Foundation
416 # Barry Warsaw <barry@python.org>, 2000.
418 msgid ""
419 msgstr ""
420 "Project-Id-Version: 2.0\n"
421 "PO-Revision-Date: 2003-04-11 12:42-0400\n"
422 "Last-Translator: Barry A. WArsaw <barry@python.org>\n"
423 "Language-Team: XX <python-dev@python.org>\n"
424 "MIME-Version: 1.0\n"
425 "Content-Type: text/plain; charset=utf-8\n"
426 "Content-Transfer-Encoding: 7bit\n"
427 "Generated-By: manually\n"
429 #: nofile:0
430 msgid "ab\xc3\x9e"
431 msgstr "\xc2\xa4yz"
434 # Here's the third example po file, used to generate MMO_DATA
437 msgid ""
438 msgstr ""
439 "Project-Id-Version: No Project 0.0\n"
440 "POT-Creation-Date: Wed Dec 11 07:44:15 2002\n"
441 "PO-Revision-Date: 2002-08-14 01:18:58+00:00\n"
442 "Last-Translator: John Doe <jdoe@example.com>\n"
443 "Jane Foobar <jfoobar@example.com>\n"
444 "Language-Team: xx <xx@example.com>\n"
445 "MIME-Version: 1.0\n"
446 "Content-Type: text/plain; charset=iso-8859-15\n"
447 "Content-Transfer-Encoding: quoted-printable\n"
448 "Generated-By: pygettext.py 1.3\n"