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
83GNU_MO_DATA_ISSUE_17898 = b'''\
843hIElQAAAAABAAAAHAAAACQAAAAAAAAAAAAAAAAAAAAsAAAAggAAAC0AAAAAUGx1cmFsLUZvcm1z
85OiBucGx1cmFscz0yOyBwbHVyYWw9KG4gIT0gMSk7CiMtIy0jLSMtIyAgbWVzc2FnZXMucG8gKEVk
86WCBTdHVkaW8pICAjLSMtIy0jLSMKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PVVU
87Ri04CgA=
88'''
89
90class GettextTestCase1(GettextBaseTest):
91    def setUp(self):
92        GettextBaseTest.setUp(self)
93        self.localedir = os.curdir
94        self.mofile = MOFILE
95        gettext.install('gettext', self.localedir)
96
97    def test_some_translations(self):
98        eq = self.assertEqual
99        # test some translations
100        eq(_('albatross'), 'albatross')
101        eq(_(u'mullusk'), 'bacon')
102        eq(_(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove')
103        eq(_(ur'nudge nudge'), 'wink wink')
104
105    def test_double_quotes(self):
106        eq = self.assertEqual
107        # double quotes
108        eq(_("albatross"), 'albatross')
109        eq(_(u"mullusk"), 'bacon')
110        eq(_(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
111        eq(_(ur"nudge nudge"), 'wink wink')
112
113    def test_triple_single_quotes(self):
114        eq = self.assertEqual
115        # triple single quotes
116        eq(_('''albatross'''), 'albatross')
117        eq(_(u'''mullusk'''), 'bacon')
118        eq(_(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
119        eq(_(ur'''nudge nudge'''), 'wink wink')
120
121    def test_triple_double_quotes(self):
122        eq = self.assertEqual
123        # triple double quotes
124        eq(_("""albatross"""), 'albatross')
125        eq(_(u"""mullusk"""), 'bacon')
126        eq(_(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
127        eq(_(ur"""nudge nudge"""), 'wink wink')
128
129    def test_multiline_strings(self):
130        eq = self.assertEqual
131        # multiline strings
132        eq(_('''This module provides internationalization and localization
133support for your Python programs by providing an interface to the GNU
134gettext message catalog library.'''),
135           '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba
136fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH
137trggrkg zrffntr pngnybt yvoenel.''')
138
139    def test_the_alternative_interface(self):
140        eq = self.assertEqual
141        # test the alternative interface
142        with open(self.mofile, 'rb') as fp:
143            t = gettext.GNUTranslations(fp)
144        # Install the translation object
145        t.install()
146        eq(_('nudge nudge'), 'wink wink')
147        # Try unicode return type
148        t.install(unicode=True)
149        eq(_('mullusk'), 'bacon')
150        # Test installation of other methods
151        import __builtin__
152        t.install(unicode=True, names=["gettext", "lgettext"])
153        eq(_, t.ugettext)
154        eq(__builtin__.gettext, t.ugettext)
155        eq(lgettext, t.lgettext)
156        del __builtin__.gettext
157        del __builtin__.lgettext
158
159
160class GettextTestCase2(GettextBaseTest):
161    def setUp(self):
162        GettextBaseTest.setUp(self)
163        self.localedir = os.curdir
164        # Set up the bindings
165        gettext.bindtextdomain('gettext', self.localedir)
166        gettext.textdomain('gettext')
167        # For convenience
168        self._ = gettext.gettext
169
170    def test_bindtextdomain(self):
171        self.assertEqual(gettext.bindtextdomain('gettext'), self.localedir)
172
173    def test_textdomain(self):
174        self.assertEqual(gettext.textdomain(), 'gettext')
175
176    def test_some_translations(self):
177        eq = self.assertEqual
178        # test some translations
179        eq(self._('albatross'), 'albatross')
180        eq(self._(u'mullusk'), 'bacon')
181        eq(self._(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove')
182        eq(self._(ur'nudge nudge'), 'wink wink')
183
184    def test_double_quotes(self):
185        eq = self.assertEqual
186        # double quotes
187        eq(self._("albatross"), 'albatross')
188        eq(self._(u"mullusk"), 'bacon')
189        eq(self._(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
190        eq(self._(ur"nudge nudge"), 'wink wink')
191
192    def test_triple_single_quotes(self):
193        eq = self.assertEqual
194        # triple single quotes
195        eq(self._('''albatross'''), 'albatross')
196        eq(self._(u'''mullusk'''), 'bacon')
197        eq(self._(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
198        eq(self._(ur'''nudge nudge'''), 'wink wink')
199
200    def test_triple_double_quotes(self):
201        eq = self.assertEqual
202        # triple double quotes
203        eq(self._("""albatross"""), 'albatross')
204        eq(self._(u"""mullusk"""), 'bacon')
205        eq(self._(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
206        eq(self._(ur"""nudge nudge"""), 'wink wink')
207
208    def test_multiline_strings(self):
209        eq = self.assertEqual
210        # multiline strings
211        eq(self._('''This module provides internationalization and localization
212support for your Python programs by providing an interface to the GNU
213gettext message catalog library.'''),
214           '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba
215fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH
216trggrkg zrffntr pngnybt yvoenel.''')
217
218
219class PluralFormsTestCase(GettextBaseTest):
220    def setUp(self):
221        GettextBaseTest.setUp(self)
222        self.mofile = MOFILE
223
224    def test_plural_forms1(self):
225        eq = self.assertEqual
226        x = gettext.ngettext('There is %s file', 'There are %s files', 1)
227        eq(x, 'Hay %s fichero')
228        x = gettext.ngettext('There is %s file', 'There are %s files', 2)
229        eq(x, 'Hay %s ficheros')
230
231    def test_plural_forms2(self):
232        eq = self.assertEqual
233        with open(self.mofile, 'rb') as fp:
234            t = gettext.GNUTranslations(fp)
235        x = t.ngettext('There is %s file', 'There are %s files', 1)
236        eq(x, 'Hay %s fichero')
237        x = t.ngettext('There is %s file', 'There are %s files', 2)
238        eq(x, 'Hay %s ficheros')
239
240    # Examples from http://www.gnu.org/software/gettext/manual/gettext.html
241
242    def test_ja(self):
243        eq = self.assertEqual
244        f = gettext.c2py('0')
245        s = ''.join([ str(f(x)) for x in range(200) ])
246        eq(s, "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
247
248    def test_de(self):
249        eq = self.assertEqual
250        f = gettext.c2py('n != 1')
251        s = ''.join([ str(f(x)) for x in range(200) ])
252        eq(s, "10111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
253
254    def test_fr(self):
255        eq = self.assertEqual
256        f = gettext.c2py('n>1')
257        s = ''.join([ str(f(x)) for x in range(200) ])
258        eq(s, "00111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
259
260    def test_lv(self):
261        eq = self.assertEqual
262        f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2')
263        s = ''.join([ str(f(x)) for x in range(200) ])
264        eq(s, "20111111111111111111101111111110111111111011111111101111111110111111111011111111101111111110111111111011111111111111111110111111111011111111101111111110111111111011111111101111111110111111111011111111")
265
266    def test_gd(self):
267        eq = self.assertEqual
268        f = gettext.c2py('n==1 ? 0 : n==2 ? 1 : 2')
269        s = ''.join([ str(f(x)) for x in range(200) ])
270        eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
271
272    def test_gd2(self):
273        eq = self.assertEqual
274        # Tests the combination of parentheses and "?:"
275        f = gettext.c2py('n==1 ? 0 : (n==2 ? 1 : 2)')
276        s = ''.join([ str(f(x)) for x in range(200) ])
277        eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
278
279    def test_ro(self):
280        eq = self.assertEqual
281        f = gettext.c2py('n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2')
282        s = ''.join([ str(f(x)) for x in range(200) ])
283        eq(s, "10111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222")
284
285    def test_lt(self):
286        eq = self.assertEqual
287        f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2')
288        s = ''.join([ str(f(x)) for x in range(200) ])
289        eq(s, "20111111112222222222201111111120111111112011111111201111111120111111112011111111201111111120111111112011111111222222222220111111112011111111201111111120111111112011111111201111111120111111112011111111")
290
291    def test_ru(self):
292        eq = self.assertEqual
293        f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2')
294        s = ''.join([ str(f(x)) for x in range(200) ])
295        eq(s, "20111222222222222222201112222220111222222011122222201112222220111222222011122222201112222220111222222011122222222222222220111222222011122222201112222220111222222011122222201112222220111222222011122222")
296
297    def test_cs(self):
298        eq = self.assertEqual
299        f = gettext.c2py('(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2')
300        s = ''.join([ str(f(x)) for x in range(200) ])
301        eq(s, "20111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
302
303    def test_pl(self):
304        eq = self.assertEqual
305        f = gettext.c2py('n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2')
306        s = ''.join([ str(f(x)) for x in range(200) ])
307        eq(s, "20111222222222222222221112222222111222222211122222221112222222111222222211122222221112222222111222222211122222222222222222111222222211122222221112222222111222222211122222221112222222111222222211122222")
308
309    def test_sl(self):
310        eq = self.assertEqual
311        f = gettext.c2py('n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3')
312        s = ''.join([ str(f(x)) for x in range(200) ])
313        eq(s, "30122333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333012233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333")
314
315    def test_ar(self):
316        eq = self.assertEqual
317        f = gettext.c2py('n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5')
318        s = ''.join([ str(f(x)) for x in range(200) ])
319        eq(s, "01233333333444444444444444444444444444444444444444444444444444444444444444444444444444444444444444445553333333344444444444444444444444444444444444444444444444444444444444444444444444444444444444444444")
320
321    def test_security(self):
322        raises = self.assertRaises
323        # Test for a dangerous expression
324        raises(ValueError, gettext.c2py, "os.chmod('/etc/passwd',0777)")
325        # issue28563
326        raises(ValueError, gettext.c2py, '"(eval(foo) && ""')
327        raises(ValueError, gettext.c2py, 'f"{os.system(\'sh\')}"')
328        # Maximum recursion depth exceeded during compilation
329        raises(ValueError, gettext.c2py, 'n+'*10000 + 'n')
330        self.assertEqual(gettext.c2py('n+'*100 + 'n')(1), 101)
331        # MemoryError during compilation
332        raises(ValueError, gettext.c2py, '('*100 + 'n' + ')'*100)
333        # Maximum recursion depth exceeded in C to Python translator
334        raises(ValueError, gettext.c2py, '('*10000 + 'n' + ')'*10000)
335        self.assertEqual(gettext.c2py('('*20 + 'n' + ')'*20)(1), 1)
336
337    def test_chained_comparison(self):
338        # C doesn't chain comparison as Python so 2 == 2 == 2 gets different results
339        f = gettext.c2py('n == n == n')
340        self.assertEqual(''.join(str(f(x)) for x in range(3)), '010')
341        f = gettext.c2py('1 < n == n')
342        self.assertEqual(''.join(str(f(x)) for x in range(3)), '100')
343        f = gettext.c2py('n == n < 2')
344        self.assertEqual(''.join(str(f(x)) for x in range(3)), '010')
345        f = gettext.c2py('0 < n < 2')
346        self.assertEqual(''.join(str(f(x)) for x in range(3)), '111')
347
348    def test_decimal_number(self):
349        self.assertEqual(gettext.c2py('0123')(1), 123)
350
351    def test_invalid_syntax(self):
352        invalid_expressions = [
353            'x>1', '(n>1', 'n>1)', '42**42**42', '0xa', '1.0', '1e2',
354            'n>0x1', '+n', '-n', 'n()', 'n(1)', '1+', 'nn', 'n n',
355        ]
356        for expr in invalid_expressions:
357            with self.assertRaises(ValueError):
358                gettext.c2py(expr)
359
360    def test_nested_condition_operator(self):
361        self.assertEqual(gettext.c2py('n?1?2:3:4')(0), 4)
362        self.assertEqual(gettext.c2py('n?1?2:3:4')(1), 2)
363        self.assertEqual(gettext.c2py('n?1:3?4:5')(0), 4)
364        self.assertEqual(gettext.c2py('n?1:3?4:5')(1), 1)
365
366    def test_division(self):
367        f = gettext.c2py('2/n*3')
368        self.assertEqual(f(1), 6)
369        self.assertEqual(f(2), 3)
370        self.assertEqual(f(3), 0)
371        self.assertEqual(f(-1), -6)
372        self.assertRaises(ZeroDivisionError, f, 0)
373
374    def test_plural_number(self):
375        f = gettext.c2py('n != 1')
376        self.assertEqual(f(1), 0)
377        self.assertEqual(f(2), 1)
378        self.assertEqual(f(1.0), 0)
379        self.assertEqual(f(2.0), 1)
380        self.assertEqual(f(1.1), 1)
381        self.assertRaises(TypeError, f, '2')
382        self.assertRaises(TypeError, f, b'2')
383        self.assertRaises(TypeError, f, [])
384        self.assertRaises(TypeError, f, object())
385
386
387class GNUTranslationParsingTest(GettextBaseTest):
388    def test_plural_form_error_issue17898(self):
389        with open(MOFILE, 'wb') as fp:
390            fp.write(base64.decodestring(GNU_MO_DATA_ISSUE_17898))
391        with open(MOFILE, 'rb') as fp:
392            # If this runs cleanly, the bug is fixed.
393            t = gettext.GNUTranslations(fp)
394
395
396class UnicodeTranslationsTest(GettextBaseTest):
397    def setUp(self):
398        GettextBaseTest.setUp(self)
399        with open(UMOFILE, 'rb') as fp:
400            self.t = gettext.GNUTranslations(fp)
401        self._ = self.t.ugettext
402
403    def test_unicode_msgid(self):
404        unless = self.assertTrue
405        unless(isinstance(self._(''), unicode))
406        unless(isinstance(self._(u''), unicode))
407
408    def test_unicode_msgstr(self):
409        eq = self.assertEqual
410        eq(self._(u'ab\xde'), u'\xa4yz')
411
412
413class WeirdMetadataTest(GettextBaseTest):
414    def setUp(self):
415        GettextBaseTest.setUp(self)
416        with open(MMOFILE, 'rb') as fp:
417            try:
418                self.t = gettext.GNUTranslations(fp)
419            except:
420                self.tearDown()
421                raise
422
423    def test_weird_metadata(self):
424        info = self.t.info()
425        self.assertEqual(info['last-translator'],
426           'John Doe <jdoe@example.com>\nJane Foobar <jfoobar@example.com>')
427
428
429class DummyGNUTranslations(gettext.GNUTranslations):
430    def foo(self):
431        return 'foo'
432
433
434class GettextCacheTestCase(GettextBaseTest):
435    def test_cache(self):
436        self.localedir = os.curdir
437        self.mofile = MOFILE
438
439        self.assertEqual(len(gettext._translations), 0)
440
441        t = gettext.translation('gettext', self.localedir)
442
443        self.assertEqual(len(gettext._translations), 1)
444
445        t = gettext.translation('gettext', self.localedir,
446                                class_=DummyGNUTranslations)
447
448        self.assertEqual(len(gettext._translations), 2)
449        self.assertEqual(t.__class__, DummyGNUTranslations)
450
451        # Calling it again doesn't add to the cache
452
453        t = gettext.translation('gettext', self.localedir,
454                                class_=DummyGNUTranslations)
455
456        self.assertEqual(len(gettext._translations), 2)
457        self.assertEqual(t.__class__, DummyGNUTranslations)
458
459
460def test_main():
461    test_support.run_unittest(__name__)
462
463if __name__ == '__main__':
464    test_main()
465
466
467# For reference, here's the .po file used to created the GNU_MO_DATA above.
468#
469# The original version was automatically generated from the sources with
470# pygettext. Later it was manually modified to add plural forms support.
471
472'''
473# Dummy translation for the Python test_gettext.py module.
474# Copyright (C) 2001 Python Software Foundation
475# Barry Warsaw <barry@python.org>, 2000.
476#
477msgid ""
478msgstr ""
479"Project-Id-Version: 2.0\n"
480"PO-Revision-Date: 2003-04-11 14:32-0400\n"
481"Last-Translator: J. David Ibanez <j-david@noos.fr>\n"
482"Language-Team: XX <python-dev@python.org>\n"
483"MIME-Version: 1.0\n"
484"Content-Type: text/plain; charset=iso-8859-1\n"
485"Content-Transfer-Encoding: 8bit\n"
486"Generated-By: pygettext.py 1.1\n"
487"Plural-Forms: nplurals=2; plural=n!=1;\n"
488
489#: test_gettext.py:19 test_gettext.py:25 test_gettext.py:31 test_gettext.py:37
490#: test_gettext.py:51 test_gettext.py:80 test_gettext.py:86 test_gettext.py:92
491#: test_gettext.py:98
492msgid "nudge nudge"
493msgstr "wink wink"
494
495#: test_gettext.py:16 test_gettext.py:22 test_gettext.py:28 test_gettext.py:34
496#: test_gettext.py:77 test_gettext.py:83 test_gettext.py:89 test_gettext.py:95
497msgid "albatross"
498msgstr ""
499
500#: test_gettext.py:18 test_gettext.py:24 test_gettext.py:30 test_gettext.py:36
501#: test_gettext.py:79 test_gettext.py:85 test_gettext.py:91 test_gettext.py:97
502msgid "Raymond Luxury Yach-t"
503msgstr "Throatwobbler Mangrove"
504
505#: test_gettext.py:17 test_gettext.py:23 test_gettext.py:29 test_gettext.py:35
506#: test_gettext.py:56 test_gettext.py:78 test_gettext.py:84 test_gettext.py:90
507#: test_gettext.py:96
508msgid "mullusk"
509msgstr "bacon"
510
511#: test_gettext.py:40 test_gettext.py:101
512msgid ""
513"This module provides internationalization and localization\n"
514"support for your Python programs by providing an interface to the GNU\n"
515"gettext message catalog library."
516msgstr ""
517"Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba\n"
518"fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH\n"
519"trggrkg zrffntr pngnybt yvoenel."
520
521# Manually added, as neither pygettext nor xgettext support plural forms
522# in Python.
523msgid "There is %s file"
524msgid_plural "There are %s files"
525msgstr[0] "Hay %s fichero"
526msgstr[1] "Hay %s ficheros"
527'''
528
529# Here's the second example po file example, used to generate the UMO_DATA
530# containing utf-8 encoded Unicode strings
531
532'''
533# Dummy translation for the Python test_gettext.py module.
534# Copyright (C) 2001 Python Software Foundation
535# Barry Warsaw <barry@python.org>, 2000.
536#
537msgid ""
538msgstr ""
539"Project-Id-Version: 2.0\n"
540"PO-Revision-Date: 2003-04-11 12:42-0400\n"
541"Last-Translator: Barry A. WArsaw <barry@python.org>\n"
542"Language-Team: XX <python-dev@python.org>\n"
543"MIME-Version: 1.0\n"
544"Content-Type: text/plain; charset=utf-8\n"
545"Content-Transfer-Encoding: 7bit\n"
546"Generated-By: manually\n"
547
548#: nofile:0
549msgid "ab\xc3\x9e"
550msgstr "\xc2\xa4yz"
551'''
552
553# Here's the third example po file, used to generate MMO_DATA
554
555'''
556msgid ""
557msgstr ""
558"Project-Id-Version: No Project 0.0\n"
559"POT-Creation-Date: Wed Dec 11 07:44:15 2002\n"
560"PO-Revision-Date: 2002-08-14 01:18:58+00:00\n"
561"Last-Translator: John Doe <jdoe@example.com>\n"
562"Jane Foobar <jfoobar@example.com>\n"
563"Language-Team: xx <xx@example.com>\n"
564"MIME-Version: 1.0\n"
565"Content-Type: text/plain; charset=iso-8859-15\n"
566"Content-Transfer-Encoding: quoted-printable\n"
567"Generated-By: pygettext.py 1.3\n"
568'''
569
570#
571# messages.po, used for bug 17898
572#
573
574'''
575# test file for http://bugs.python.org/issue17898
576msgid ""
577msgstr ""
578"Plural-Forms: nplurals=2; plural=(n != 1);\n"
579"#-#-#-#-#  messages.po (EdX Studio)  #-#-#-#-#\n"
580"Content-Type: text/plain; charset=UTF-8\n"
581'''
582