source: python/trunk/Lib/test/test_gettext.py

Last change on this file was 391, checked in by dmik, 11 years ago

python: Merge vendor 2.7.6 to trunk.

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