• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 import os
2 import base64
3 import contextlib
4 import gettext
5 import unittest
6 
7 from test import 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 
16 GNU_MO_DATA = b'''\
17 3hIElQAAAAAJAAAAHAAAAGQAAAAAAAAArAAAAAAAAACsAAAAFQAAAK0AAAAjAAAAwwAAAKEAAADn
18 AAAAMAAAAIkBAAAHAAAAugEAABYAAADCAQAAHAAAANkBAAALAAAA9gEAAEIBAAACAgAAFgAAAEUD
19 AAAeAAAAXAMAAKEAAAB7AwAAMgAAAB0EAAAFAAAAUAQAABsAAABWBAAAIQAAAHIEAAAJAAAAlAQA
20 AABSYXltb25kIEx1eHVyeSBZYWNoLXQAVGhlcmUgaXMgJXMgZmlsZQBUaGVyZSBhcmUgJXMgZmls
21 ZXMAVGhpcyBtb2R1bGUgcHJvdmlkZXMgaW50ZXJuYXRpb25hbGl6YXRpb24gYW5kIGxvY2FsaXph
22 dGlvbgpzdXBwb3J0IGZvciB5b3VyIFB5dGhvbiBwcm9ncmFtcyBieSBwcm92aWRpbmcgYW4gaW50
23 ZXJmYWNlIHRvIHRoZSBHTlUKZ2V0dGV4dCBtZXNzYWdlIGNhdGFsb2cgbGlicmFyeS4AV2l0aCBj
24 b250ZXh0BFRoZXJlIGlzICVzIGZpbGUAVGhlcmUgYXJlICVzIGZpbGVzAG11bGx1c2sAbXkgY29u
25 dGV4dARudWRnZSBudWRnZQBteSBvdGhlciBjb250ZXh0BG51ZGdlIG51ZGdlAG51ZGdlIG51ZGdl
26 AFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDMtMDQtMTEgMTQ6
27 MzItMDQwMApMYXN0LVRyYW5zbGF0b3I6IEouIERhdmlkIEliYW5leiA8ai1kYXZpZEBub29zLmZy
28 PgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpNSU1FLVZlcnNpb246
29 IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4NTktMQpDb250ZW50
30 LVRyYW5zZmVyLUVuY29kaW5nOiA4Yml0CkdlbmVyYXRlZC1CeTogcHlnZXR0ZXh0LnB5IDEuMQpQ
31 bHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0d29iYmxlciBNYW5n
32 cm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFoeXIgY2ViaXZxcmYg
33 dmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVnIHNiZSBsYmhlIENs
34 Z3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1ciBUQUgKdHJnZ3Jr
35 ZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4ASGF5ICVzIGZpY2hlcm8gKGNvbnRleHQpAEhheSAl
36 cyBmaWNoZXJvcyAoY29udGV4dCkAYmFjb24Ad2luayB3aW5rIChpbiAibXkgY29udGV4dCIpAHdp
37 bmsgd2luayAoaW4gIm15IG90aGVyIGNvbnRleHQiKQB3aW5rIHdpbmsA
38 '''
39 
40 # This data contains an invalid major version number (5)
41 # An unexpected major version number should be treated as an error when
42 # parsing a .mo file
43 
44 GNU_MO_DATA_BAD_MAJOR_VERSION = b'''\
45 3hIElQAABQAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj
46 AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD
47 AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh
48 eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU
49 aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u
50 CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh
51 Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51
52 ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt
53 MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k
54 YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN
55 SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4
56 NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0
57 ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0
58 d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo
59 eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn
60 IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1
61 ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA==
62 '''
63 
64 # This data contains an invalid minor version number (7)
65 # An unexpected minor version number only indicates that some of the file's
66 # contents may not be able to be read. It does not indicate an error.
67 
68 GNU_MO_DATA_BAD_MINOR_VERSION = b'''\
69 3hIElQcAAAAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj
70 AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD
71 AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh
72 eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU
73 aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u
74 CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh
75 Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51
76 ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt
77 MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k
78 YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN
79 SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4
80 NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0
81 ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0
82 d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo
83 eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn
84 IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1
85 ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA==
86 '''
87 
88 
89 UMO_DATA = b'''\
90 3hIElQAAAAADAAAAHAAAADQAAAAAAAAAAAAAAAAAAABMAAAABAAAAE0AAAAQAAAAUgAAAA8BAABj
91 AAAABAAAAHMBAAAWAAAAeAEAAABhYsOeAG15Y29udGV4dMOeBGFiw54AUHJvamVjdC1JZC1WZXJz
92 aW9uOiAyLjAKUE8tUmV2aXNpb24tRGF0ZTogMjAwMy0wNC0xMSAxMjo0Mi0wNDAwCkxhc3QtVHJh
93 bnNsYXRvcjogQmFycnkgQS4gV0Fyc2F3IDxiYXJyeUBweXRob24ub3JnPgpMYW5ndWFnZS1UZWFt
94 OiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpNSU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5
95 cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzog
96 N2JpdApHZW5lcmF0ZWQtQnk6IG1hbnVhbGx5CgDCpHl6AMKkeXogKGNvbnRleHQgdmVyc2lvbikA
97 '''
98 
99 MMO_DATA = b'''\
100 3hIElQAAAAABAAAAHAAAACQAAAADAAAALAAAAAAAAAA4AAAAeAEAADkAAAABAAAAAAAAAAAAAAAA
101 UHJvamVjdC1JZC1WZXJzaW9uOiBObyBQcm9qZWN0IDAuMApQT1QtQ3JlYXRpb24tRGF0ZTogV2Vk
102 IERlYyAxMSAwNzo0NDoxNSAyMDAyClBPLVJldmlzaW9uLURhdGU6IDIwMDItMDgtMTQgMDE6MTg6
103 NTgrMDA6MDAKTGFzdC1UcmFuc2xhdG9yOiBKb2huIERvZSA8amRvZUBleGFtcGxlLmNvbT4KSmFu
104 ZSBGb29iYXIgPGpmb29iYXJAZXhhbXBsZS5jb20+Ckxhbmd1YWdlLVRlYW06IHh4IDx4eEBleGFt
105 cGxlLmNvbT4KTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFy
106 c2V0PWlzby04ODU5LTE1CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFi
107 bGUKR2VuZXJhdGVkLUJ5OiBweWdldHRleHQucHkgMS4zCgA=
108 '''
109 
110 LOCALEDIR = os.path.join('xx', 'LC_MESSAGES')
111 MOFILE = os.path.join(LOCALEDIR, 'gettext.mo')
112 MOFILE_BAD_MAJOR_VERSION = os.path.join(LOCALEDIR, 'gettext_bad_major_version.mo')
113 MOFILE_BAD_MINOR_VERSION = os.path.join(LOCALEDIR, 'gettext_bad_minor_version.mo')
114 UMOFILE = os.path.join(LOCALEDIR, 'ugettext.mo')
115 MMOFILE = os.path.join(LOCALEDIR, 'metadata.mo')
116 
117 
118 class GettextBaseTest(unittest.TestCase):
119     def setUp(self):
120         if not os.path.isdir(LOCALEDIR):
121             os.makedirs(LOCALEDIR)
122         with open(MOFILE, 'wb') as fp:
123             fp.write(base64.decodebytes(GNU_MO_DATA))
124         with open(MOFILE_BAD_MAJOR_VERSION, 'wb') as fp:
125             fp.write(base64.decodebytes(GNU_MO_DATA_BAD_MAJOR_VERSION))
126         with open(MOFILE_BAD_MINOR_VERSION, 'wb') as fp:
127             fp.write(base64.decodebytes(GNU_MO_DATA_BAD_MINOR_VERSION))
128         with open(UMOFILE, 'wb') as fp:
129             fp.write(base64.decodebytes(UMO_DATA))
130         with open(MMOFILE, 'wb') as fp:
131             fp.write(base64.decodebytes(MMO_DATA))
132         self.env = support.EnvironmentVarGuard()
133         self.env['LANGUAGE'] = 'xx'
134         gettext._translations.clear()
135 
136     def tearDown(self):
137         self.env.__exit__()
138         del self.env
139         support.rmtree(os.path.split(LOCALEDIR)[0])
140 
141 GNU_MO_DATA_ISSUE_17898 = b'''\
142 3hIElQAAAAABAAAAHAAAACQAAAAAAAAAAAAAAAAAAAAsAAAAggAAAC0AAAAAUGx1cmFsLUZvcm1z
143 OiBucGx1cmFscz0yOyBwbHVyYWw9KG4gIT0gMSk7CiMtIy0jLSMtIyAgbWVzc2FnZXMucG8gKEVk
144 WCBTdHVkaW8pICAjLSMtIy0jLSMKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PVVU
145 Ri04CgA=
146 '''
147 
148 class GettextTestCase1(GettextBaseTest):
149     def setUp(self):
150         GettextBaseTest.setUp(self)
151         self.localedir = os.curdir
152         self.mofile = MOFILE
153         gettext.install('gettext', self.localedir, names=['pgettext'])
154 
155     def test_some_translations(self):
156         eq = self.assertEqual
157         # test some translations
158         eq(_('albatross'), 'albatross')
159         eq(_('mullusk'), 'bacon')
160         eq(_(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove')
161         eq(_(r'nudge nudge'), 'wink wink')
162 
163     def test_some_translations_with_context(self):
164         eq = self.assertEqual
165         eq(pgettext('my context', 'nudge nudge'),
166            'wink wink (in "my context")')
167         eq(pgettext('my other context', 'nudge nudge'),
168            'wink wink (in "my other context")')
169 
170     def test_double_quotes(self):
171         eq = self.assertEqual
172         # double quotes
173         eq(_("albatross"), 'albatross')
174         eq(_("mullusk"), 'bacon')
175         eq(_(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
176         eq(_(r"nudge nudge"), 'wink wink')
177 
178     def test_triple_single_quotes(self):
179         eq = self.assertEqual
180         # triple single quotes
181         eq(_('''albatross'''), 'albatross')
182         eq(_('''mullusk'''), 'bacon')
183         eq(_(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
184         eq(_(r'''nudge nudge'''), 'wink wink')
185 
186     def test_triple_double_quotes(self):
187         eq = self.assertEqual
188         # triple double quotes
189         eq(_("""albatross"""), 'albatross')
190         eq(_("""mullusk"""), 'bacon')
191         eq(_(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
192         eq(_(r"""nudge nudge"""), 'wink wink')
193 
194     def test_multiline_strings(self):
195         eq = self.assertEqual
196         # multiline strings
197         eq(_('''This module provides internationalization and localization
198 support for your Python programs by providing an interface to the GNU
199 gettext message catalog library.'''),
200            '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba
201 fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH
202 trggrkg zrffntr pngnybt yvoenel.''')
203 
204     def test_the_alternative_interface(self):
205         eq = self.assertEqual
206         # test the alternative interface
207         with open(self.mofile, 'rb') as fp:
208             t = gettext.GNUTranslations(fp)
209         # Install the translation object
210         t.install()
211         eq(_('nudge nudge'), 'wink wink')
212         # Try unicode return type
213         t.install()
214         eq(_('mullusk'), 'bacon')
215         # Test installation of other methods
216         import builtins
217         t.install(names=["gettext", "lgettext"])
218         eq(_, t.gettext)
219         eq(builtins.gettext, t.gettext)
220         eq(lgettext, t.lgettext)
221         del builtins.gettext
222         del builtins.lgettext
223 
224 
225 class GettextTestCase2(GettextBaseTest):
226     def setUp(self):
227         GettextBaseTest.setUp(self)
228         self.localedir = os.curdir
229         # Set up the bindings
230         gettext.bindtextdomain('gettext', self.localedir)
231         gettext.textdomain('gettext')
232         # For convenience
233         self._ = gettext.gettext
234 
235     def test_bindtextdomain(self):
236         self.assertEqual(gettext.bindtextdomain('gettext'), self.localedir)
237 
238     def test_textdomain(self):
239         self.assertEqual(gettext.textdomain(), 'gettext')
240 
241     def test_bad_major_version(self):
242         with open(MOFILE_BAD_MAJOR_VERSION, 'rb') as fp:
243             with self.assertRaises(OSError) as cm:
244                 gettext.GNUTranslations(fp)
245 
246             exception = cm.exception
247             self.assertEqual(exception.errno, 0)
248             self.assertEqual(exception.strerror, "Bad version number 5")
249             self.assertEqual(exception.filename, MOFILE_BAD_MAJOR_VERSION)
250 
251     def test_bad_minor_version(self):
252         with open(MOFILE_BAD_MINOR_VERSION, 'rb') as fp:
253             # Check that no error is thrown with a bad minor version number
254             gettext.GNUTranslations(fp)
255 
256     def test_some_translations(self):
257         eq = self.assertEqual
258         # test some translations
259         eq(self._('albatross'), 'albatross')
260         eq(self._('mullusk'), 'bacon')
261         eq(self._(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove')
262         eq(self._(r'nudge nudge'), 'wink wink')
263 
264     def test_some_translations_with_context(self):
265         eq = self.assertEqual
266         eq(gettext.pgettext('my context', 'nudge nudge'),
267            'wink wink (in "my context")')
268         eq(gettext.pgettext('my other context', 'nudge nudge'),
269            'wink wink (in "my other context")')
270 
271     def test_some_translations_with_context_and_domain(self):
272         eq = self.assertEqual
273         eq(gettext.dpgettext('gettext', 'my context', 'nudge nudge'),
274            'wink wink (in "my context")')
275         eq(gettext.dpgettext('gettext', 'my other context', 'nudge nudge'),
276            'wink wink (in "my other context")')
277 
278     def test_double_quotes(self):
279         eq = self.assertEqual
280         # double quotes
281         eq(self._("albatross"), 'albatross')
282         eq(self._("mullusk"), 'bacon')
283         eq(self._(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove')
284         eq(self._(r"nudge nudge"), 'wink wink')
285 
286     def test_triple_single_quotes(self):
287         eq = self.assertEqual
288         # triple single quotes
289         eq(self._('''albatross'''), 'albatross')
290         eq(self._('''mullusk'''), 'bacon')
291         eq(self._(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove')
292         eq(self._(r'''nudge nudge'''), 'wink wink')
293 
294     def test_triple_double_quotes(self):
295         eq = self.assertEqual
296         # triple double quotes
297         eq(self._("""albatross"""), 'albatross')
298         eq(self._("""mullusk"""), 'bacon')
299         eq(self._(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove')
300         eq(self._(r"""nudge nudge"""), 'wink wink')
301 
302     def test_multiline_strings(self):
303         eq = self.assertEqual
304         # multiline strings
305         eq(self._('''This module provides internationalization and localization
306 support for your Python programs by providing an interface to the GNU
307 gettext message catalog library.'''),
308            '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba
309 fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH
310 trggrkg zrffntr pngnybt yvoenel.''')
311 
312 
313 class PluralFormsTestCase(GettextBaseTest):
314     def setUp(self):
315         GettextBaseTest.setUp(self)
316         self.mofile = MOFILE
317 
318     def test_plural_forms1(self):
319         eq = self.assertEqual
320         x = gettext.ngettext('There is %s file', 'There are %s files', 1)
321         eq(x, 'Hay %s fichero')
322         x = gettext.ngettext('There is %s file', 'There are %s files', 2)
323         eq(x, 'Hay %s ficheros')
324 
325     def test_plural_context_forms1(self):
326         eq = self.assertEqual
327         x = gettext.npgettext('With context',
328                               'There is %s file', 'There are %s files', 1)
329         eq(x, 'Hay %s fichero (context)')
330         x = gettext.npgettext('With context',
331                               'There is %s file', 'There are %s files', 2)
332         eq(x, 'Hay %s ficheros (context)')
333 
334     def test_plural_forms2(self):
335         eq = self.assertEqual
336         with open(self.mofile, 'rb') as fp:
337             t = gettext.GNUTranslations(fp)
338         x = t.ngettext('There is %s file', 'There are %s files', 1)
339         eq(x, 'Hay %s fichero')
340         x = t.ngettext('There is %s file', 'There are %s files', 2)
341         eq(x, 'Hay %s ficheros')
342 
343     def test_plural_context_forms2(self):
344         eq = self.assertEqual
345         with open(self.mofile, 'rb') as fp:
346             t = gettext.GNUTranslations(fp)
347         x = t.npgettext('With context',
348                         'There is %s file', 'There are %s files', 1)
349         eq(x, 'Hay %s fichero (context)')
350         x = t.npgettext('With context',
351                         'There is %s file', 'There are %s files', 2)
352         eq(x, 'Hay %s ficheros (context)')
353 
354     # Examples from http://www.gnu.org/software/gettext/manual/gettext.html
355 
356     def test_ja(self):
357         eq = self.assertEqual
358         f = gettext.c2py('0')
359         s = ''.join([ str(f(x)) for x in range(200) ])
360         eq(s, "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
361 
362     def test_de(self):
363         eq = self.assertEqual
364         f = gettext.c2py('n != 1')
365         s = ''.join([ str(f(x)) for x in range(200) ])
366         eq(s, "10111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
367 
368     def test_fr(self):
369         eq = self.assertEqual
370         f = gettext.c2py('n>1')
371         s = ''.join([ str(f(x)) for x in range(200) ])
372         eq(s, "00111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")
373 
374     def test_lv(self):
375         eq = self.assertEqual
376         f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2')
377         s = ''.join([ str(f(x)) for x in range(200) ])
378         eq(s, "20111111111111111111101111111110111111111011111111101111111110111111111011111111101111111110111111111011111111111111111110111111111011111111101111111110111111111011111111101111111110111111111011111111")
379 
380     def test_gd(self):
381         eq = self.assertEqual
382         f = gettext.c2py('n==1 ? 0 : n==2 ? 1 : 2')
383         s = ''.join([ str(f(x)) for x in range(200) ])
384         eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
385 
386     def test_gd2(self):
387         eq = self.assertEqual
388         # Tests the combination of parentheses and "?:"
389         f = gettext.c2py('n==1 ? 0 : (n==2 ? 1 : 2)')
390         s = ''.join([ str(f(x)) for x in range(200) ])
391         eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
392 
393     def test_ro(self):
394         eq = self.assertEqual
395         f = gettext.c2py('n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2')
396         s = ''.join([ str(f(x)) for x in range(200) ])
397         eq(s, "10111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222")
398 
399     def test_lt(self):
400         eq = self.assertEqual
401         f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2')
402         s = ''.join([ str(f(x)) for x in range(200) ])
403         eq(s, "20111111112222222222201111111120111111112011111111201111111120111111112011111111201111111120111111112011111111222222222220111111112011111111201111111120111111112011111111201111111120111111112011111111")
404 
405     def test_ru(self):
406         eq = self.assertEqual
407         f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2')
408         s = ''.join([ str(f(x)) for x in range(200) ])
409         eq(s, "20111222222222222222201112222220111222222011122222201112222220111222222011122222201112222220111222222011122222222222222220111222222011122222201112222220111222222011122222201112222220111222222011122222")
410 
411     def test_cs(self):
412         eq = self.assertEqual
413         f = gettext.c2py('(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2')
414         s = ''.join([ str(f(x)) for x in range(200) ])
415         eq(s, "20111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222")
416 
417     def test_pl(self):
418         eq = self.assertEqual
419         f = gettext.c2py('n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2')
420         s = ''.join([ str(f(x)) for x in range(200) ])
421         eq(s, "20111222222222222222221112222222111222222211122222221112222222111222222211122222221112222222111222222211122222222222222222111222222211122222221112222222111222222211122222221112222222111222222211122222")
422 
423     def test_sl(self):
424         eq = self.assertEqual
425         f = gettext.c2py('n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3')
426         s = ''.join([ str(f(x)) for x in range(200) ])
427         eq(s, "30122333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333012233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333")
428 
429     def test_ar(self):
430         eq = self.assertEqual
431         f = gettext.c2py('n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5')
432         s = ''.join([ str(f(x)) for x in range(200) ])
433         eq(s, "01233333333444444444444444444444444444444444444444444444444444444444444444444444444444444444444444445553333333344444444444444444444444444444444444444444444444444444444444444444444444444444444444444444")
434 
435     def test_security(self):
436         raises = self.assertRaises
437         # Test for a dangerous expression
438         raises(ValueError, gettext.c2py, "os.chmod('/etc/passwd',0777)")
439         # issue28563
440         raises(ValueError, gettext.c2py, '"(eval(foo) && ""')
441         raises(ValueError, gettext.c2py, 'f"{os.system(\'sh\')}"')
442         # Maximum recursion depth exceeded during compilation
443         raises(ValueError, gettext.c2py, 'n+'*10000 + 'n')
444         self.assertEqual(gettext.c2py('n+'*100 + 'n')(1), 101)
445         # MemoryError during compilation
446         raises(ValueError, gettext.c2py, '('*100 + 'n' + ')'*100)
447         # Maximum recursion depth exceeded in C to Python translator
448         raises(ValueError, gettext.c2py, '('*10000 + 'n' + ')'*10000)
449         self.assertEqual(gettext.c2py('('*20 + 'n' + ')'*20)(1), 1)
450 
451     def test_chained_comparison(self):
452         # C doesn't chain comparison as Python so 2 == 2 == 2 gets different results
453         f = gettext.c2py('n == n == n')
454         self.assertEqual(''.join(str(f(x)) for x in range(3)), '010')
455         f = gettext.c2py('1 < n == n')
456         self.assertEqual(''.join(str(f(x)) for x in range(3)), '100')
457         f = gettext.c2py('n == n < 2')
458         self.assertEqual(''.join(str(f(x)) for x in range(3)), '010')
459         f = gettext.c2py('0 < n < 2')
460         self.assertEqual(''.join(str(f(x)) for x in range(3)), '111')
461 
462     def test_decimal_number(self):
463         self.assertEqual(gettext.c2py('0123')(1), 123)
464 
465     def test_invalid_syntax(self):
466         invalid_expressions = [
467             'x>1', '(n>1', 'n>1)', '42**42**42', '0xa', '1.0', '1e2',
468             'n>0x1', '+n', '-n', 'n()', 'n(1)', '1+', 'nn', 'n n',
469         ]
470         for expr in invalid_expressions:
471             with self.assertRaises(ValueError):
472                 gettext.c2py(expr)
473 
474     def test_nested_condition_operator(self):
475         self.assertEqual(gettext.c2py('n?1?2:3:4')(0), 4)
476         self.assertEqual(gettext.c2py('n?1?2:3:4')(1), 2)
477         self.assertEqual(gettext.c2py('n?1:3?4:5')(0), 4)
478         self.assertEqual(gettext.c2py('n?1:3?4:5')(1), 1)
479 
480     def test_division(self):
481         f = gettext.c2py('2/n*3')
482         self.assertEqual(f(1), 6)
483         self.assertEqual(f(2), 3)
484         self.assertEqual(f(3), 0)
485         self.assertEqual(f(-1), -6)
486         self.assertRaises(ZeroDivisionError, f, 0)
487 
488     def test_plural_number(self):
489         f = gettext.c2py('n != 1')
490         self.assertEqual(f(1), 0)
491         self.assertEqual(f(2), 1)
492         with self.assertWarns(DeprecationWarning):
493             self.assertEqual(f(1.0), 0)
494         with self.assertWarns(DeprecationWarning):
495             self.assertEqual(f(2.0), 1)
496         with self.assertWarns(DeprecationWarning):
497             self.assertEqual(f(1.1), 1)
498         self.assertRaises(TypeError, f, '2')
499         self.assertRaises(TypeError, f, b'2')
500         self.assertRaises(TypeError, f, [])
501         self.assertRaises(TypeError, f, object())
502 
503 
504 class LGettextTestCase(GettextBaseTest):
505     def setUp(self):
506         GettextBaseTest.setUp(self)
507         self.mofile = MOFILE
508 
509     @contextlib.contextmanager
510     def assertDeprecated(self, name):
511         with self.assertWarnsRegex(DeprecationWarning,
512                                    fr'^{name}\(\) is deprecated'):
513             yield
514 
515     def test_lgettext(self):
516         lgettext = gettext.lgettext
517         ldgettext = gettext.ldgettext
518         with self.assertDeprecated('lgettext'):
519             self.assertEqual(lgettext('mullusk'), b'bacon')
520         with self.assertDeprecated('lgettext'):
521             self.assertEqual(lgettext('spam'), b'spam')
522         with self.assertDeprecated('ldgettext'):
523             self.assertEqual(ldgettext('gettext', 'mullusk'), b'bacon')
524         with self.assertDeprecated('ldgettext'):
525             self.assertEqual(ldgettext('gettext', 'spam'), b'spam')
526 
527     def test_lgettext_2(self):
528         with open(self.mofile, 'rb') as fp:
529             t = gettext.GNUTranslations(fp)
530         lgettext = t.lgettext
531         with self.assertDeprecated('lgettext'):
532             self.assertEqual(lgettext('mullusk'), b'bacon')
533         with self.assertDeprecated('lgettext'):
534             self.assertEqual(lgettext('spam'), b'spam')
535 
536     def test_lgettext_bind_textdomain_codeset(self):
537         lgettext = gettext.lgettext
538         ldgettext = gettext.ldgettext
539         with self.assertDeprecated('bind_textdomain_codeset'):
540             saved_codeset = gettext.bind_textdomain_codeset('gettext')
541         try:
542             with self.assertDeprecated('bind_textdomain_codeset'):
543                 gettext.bind_textdomain_codeset('gettext', 'utf-16')
544             with self.assertDeprecated('lgettext'):
545                 self.assertEqual(lgettext('mullusk'), 'bacon'.encode('utf-16'))
546             with self.assertDeprecated('lgettext'):
547                 self.assertEqual(lgettext('spam'), 'spam'.encode('utf-16'))
548             with self.assertDeprecated('ldgettext'):
549                 self.assertEqual(ldgettext('gettext', 'mullusk'), 'bacon'.encode('utf-16'))
550             with self.assertDeprecated('ldgettext'):
551                 self.assertEqual(ldgettext('gettext', 'spam'), 'spam'.encode('utf-16'))
552         finally:
553             del gettext._localecodesets['gettext']
554             with self.assertDeprecated('bind_textdomain_codeset'):
555                 gettext.bind_textdomain_codeset('gettext', saved_codeset)
556 
557     def test_lgettext_output_encoding(self):
558         with open(self.mofile, 'rb') as fp:
559             t = gettext.GNUTranslations(fp)
560         lgettext = t.lgettext
561         with self.assertDeprecated('set_output_charset'):
562             t.set_output_charset('utf-16')
563         with self.assertDeprecated('lgettext'):
564             self.assertEqual(lgettext('mullusk'), 'bacon'.encode('utf-16'))
565         with self.assertDeprecated('lgettext'):
566             self.assertEqual(lgettext('spam'), 'spam'.encode('utf-16'))
567 
568     def test_lngettext(self):
569         lngettext = gettext.lngettext
570         ldngettext = gettext.ldngettext
571         with self.assertDeprecated('lngettext'):
572             x = lngettext('There is %s file', 'There are %s files', 1)
573         self.assertEqual(x, b'Hay %s fichero')
574         with self.assertDeprecated('lngettext'):
575             x = lngettext('There is %s file', 'There are %s files', 2)
576         self.assertEqual(x, b'Hay %s ficheros')
577         with self.assertDeprecated('lngettext'):
578             x = lngettext('There is %s directory', 'There are %s directories', 1)
579         self.assertEqual(x, b'There is %s directory')
580         with self.assertDeprecated('lngettext'):
581             x = lngettext('There is %s directory', 'There are %s directories', 2)
582         self.assertEqual(x, b'There are %s directories')
583         with self.assertDeprecated('ldngettext'):
584             x = ldngettext('gettext', 'There is %s file', 'There are %s files', 1)
585         self.assertEqual(x, b'Hay %s fichero')
586         with self.assertDeprecated('ldngettext'):
587             x = ldngettext('gettext', 'There is %s file', 'There are %s files', 2)
588         self.assertEqual(x, b'Hay %s ficheros')
589         with self.assertDeprecated('ldngettext'):
590             x = ldngettext('gettext', 'There is %s directory', 'There are %s directories', 1)
591         self.assertEqual(x, b'There is %s directory')
592         with self.assertDeprecated('ldngettext'):
593             x = ldngettext('gettext', 'There is %s directory', 'There are %s directories', 2)
594         self.assertEqual(x, b'There are %s directories')
595 
596     def test_lngettext_2(self):
597         with open(self.mofile, 'rb') as fp:
598             t = gettext.GNUTranslations(fp)
599         lngettext = t.lngettext
600         with self.assertDeprecated('lngettext'):
601             x = lngettext('There is %s file', 'There are %s files', 1)
602         self.assertEqual(x, b'Hay %s fichero')
603         with self.assertDeprecated('lngettext'):
604             x = lngettext('There is %s file', 'There are %s files', 2)
605         self.assertEqual(x, b'Hay %s ficheros')
606         with self.assertDeprecated('lngettext'):
607             x = lngettext('There is %s directory', 'There are %s directories', 1)
608         self.assertEqual(x, b'There is %s directory')
609         with self.assertDeprecated('lngettext'):
610             x = lngettext('There is %s directory', 'There are %s directories', 2)
611         self.assertEqual(x, b'There are %s directories')
612 
613     def test_lngettext_bind_textdomain_codeset(self):
614         lngettext = gettext.lngettext
615         ldngettext = gettext.ldngettext
616         with self.assertDeprecated('bind_textdomain_codeset'):
617             saved_codeset = gettext.bind_textdomain_codeset('gettext')
618         try:
619             with self.assertDeprecated('bind_textdomain_codeset'):
620                 gettext.bind_textdomain_codeset('gettext', 'utf-16')
621             with self.assertDeprecated('lngettext'):
622                 x = lngettext('There is %s file', 'There are %s files', 1)
623             self.assertEqual(x, 'Hay %s fichero'.encode('utf-16'))
624             with self.assertDeprecated('lngettext'):
625                 x = lngettext('There is %s file', 'There are %s files', 2)
626             self.assertEqual(x, 'Hay %s ficheros'.encode('utf-16'))
627             with self.assertDeprecated('lngettext'):
628                 x = lngettext('There is %s directory', 'There are %s directories', 1)
629             self.assertEqual(x, 'There is %s directory'.encode('utf-16'))
630             with self.assertDeprecated('lngettext'):
631                 x = lngettext('There is %s directory', 'There are %s directories', 2)
632             self.assertEqual(x, 'There are %s directories'.encode('utf-16'))
633             with self.assertDeprecated('ldngettext'):
634                 x = ldngettext('gettext', 'There is %s file', 'There are %s files', 1)
635             self.assertEqual(x, 'Hay %s fichero'.encode('utf-16'))
636             with self.assertDeprecated('ldngettext'):
637                 x = ldngettext('gettext', 'There is %s file', 'There are %s files', 2)
638             self.assertEqual(x, 'Hay %s ficheros'.encode('utf-16'))
639             with self.assertDeprecated('ldngettext'):
640                 x = ldngettext('gettext', 'There is %s directory', 'There are %s directories', 1)
641             self.assertEqual(x, 'There is %s directory'.encode('utf-16'))
642             with self.assertDeprecated('ldngettext'):
643                 x = ldngettext('gettext', 'There is %s directory', 'There are %s directories', 2)
644             self.assertEqual(x, 'There are %s directories'.encode('utf-16'))
645         finally:
646             del gettext._localecodesets['gettext']
647             with self.assertDeprecated('bind_textdomain_codeset'):
648                 gettext.bind_textdomain_codeset('gettext', saved_codeset)
649 
650     def test_lngettext_output_encoding(self):
651         with open(self.mofile, 'rb') as fp:
652             t = gettext.GNUTranslations(fp)
653         lngettext = t.lngettext
654         with self.assertDeprecated('set_output_charset'):
655             t.set_output_charset('utf-16')
656         with self.assertDeprecated('lngettext'):
657             x = lngettext('There is %s file', 'There are %s files', 1)
658         self.assertEqual(x, 'Hay %s fichero'.encode('utf-16'))
659         with self.assertDeprecated('lngettext'):
660             x = lngettext('There is %s file', 'There are %s files', 2)
661         self.assertEqual(x, 'Hay %s ficheros'.encode('utf-16'))
662         with self.assertDeprecated('lngettext'):
663             x = lngettext('There is %s directory', 'There are %s directories', 1)
664         self.assertEqual(x, 'There is %s directory'.encode('utf-16'))
665         with self.assertDeprecated('lngettext'):
666             x = lngettext('There is %s directory', 'There are %s directories', 2)
667         self.assertEqual(x, 'There are %s directories'.encode('utf-16'))
668 
669     def test_output_encoding(self):
670         with open(self.mofile, 'rb') as fp:
671             t = gettext.GNUTranslations(fp)
672         with self.assertDeprecated('set_output_charset'):
673             t.set_output_charset('utf-16')
674         with self.assertDeprecated('output_charset'):
675             self.assertEqual(t.output_charset(), 'utf-16')
676 
677 
678 class GNUTranslationParsingTest(GettextBaseTest):
679     def test_plural_form_error_issue17898(self):
680         with open(MOFILE, 'wb') as fp:
681             fp.write(base64.decodebytes(GNU_MO_DATA_ISSUE_17898))
682         with open(MOFILE, 'rb') as fp:
683             # If this runs cleanly, the bug is fixed.
684             t = gettext.GNUTranslations(fp)
685 
686     def test_ignore_comments_in_headers_issue36239(self):
687         """Checks that comments like:
688 
689             #-#-#-#-#  messages.po (EdX Studio)  #-#-#-#-#
690 
691         are ignored.
692         """
693         with open(MOFILE, 'wb') as fp:
694             fp.write(base64.decodebytes(GNU_MO_DATA_ISSUE_17898))
695         with open(MOFILE, 'rb') as fp:
696             t = gettext.GNUTranslations(fp)
697             self.assertEqual(t.info()["plural-forms"], "nplurals=2; plural=(n != 1);")
698 
699 
700 class UnicodeTranslationsTest(GettextBaseTest):
701     def setUp(self):
702         GettextBaseTest.setUp(self)
703         with open(UMOFILE, 'rb') as fp:
704             self.t = gettext.GNUTranslations(fp)
705         self._ = self.t.gettext
706         self.pgettext = self.t.pgettext
707 
708     def test_unicode_msgid(self):
709         self.assertIsInstance(self._(''), str)
710 
711     def test_unicode_msgstr(self):
712         self.assertEqual(self._('ab\xde'), '\xa4yz')
713 
714     def test_unicode_context_msgstr(self):
715         t = self.pgettext('mycontext\xde', 'ab\xde')
716         self.assertTrue(isinstance(t, str))
717         self.assertEqual(t, '\xa4yz (context version)')
718 
719 
720 class UnicodeTranslationsPluralTest(GettextBaseTest):
721     def setUp(self):
722         GettextBaseTest.setUp(self)
723         with open(MOFILE, 'rb') as fp:
724             self.t = gettext.GNUTranslations(fp)
725         self.ngettext = self.t.ngettext
726         self.npgettext = self.t.npgettext
727 
728     def test_unicode_msgid(self):
729         unless = self.assertTrue
730         unless(isinstance(self.ngettext('', '', 1), str))
731         unless(isinstance(self.ngettext('', '', 2), str))
732 
733     def test_unicode_context_msgid(self):
734         unless = self.assertTrue
735         unless(isinstance(self.npgettext('', '', '', 1), str))
736         unless(isinstance(self.npgettext('', '', '', 2), str))
737 
738     def test_unicode_msgstr(self):
739         eq = self.assertEqual
740         unless = self.assertTrue
741         t = self.ngettext("There is %s file", "There are %s files", 1)
742         unless(isinstance(t, str))
743         eq(t, "Hay %s fichero")
744         unless(isinstance(t, str))
745         t = self.ngettext("There is %s file", "There are %s files", 5)
746         unless(isinstance(t, str))
747         eq(t, "Hay %s ficheros")
748 
749     def test_unicode_msgstr_with_context(self):
750         eq = self.assertEqual
751         unless = self.assertTrue
752         t = self.npgettext("With context",
753                            "There is %s file", "There are %s files", 1)
754         unless(isinstance(t, str))
755         eq(t, "Hay %s fichero (context)")
756         t = self.npgettext("With context",
757                            "There is %s file", "There are %s files", 5)
758         unless(isinstance(t, str))
759         eq(t, "Hay %s ficheros (context)")
760 
761 
762 class WeirdMetadataTest(GettextBaseTest):
763     def setUp(self):
764         GettextBaseTest.setUp(self)
765         with open(MMOFILE, 'rb') as fp:
766             try:
767                 self.t = gettext.GNUTranslations(fp)
768             except:
769                 self.tearDown()
770                 raise
771 
772     def test_weird_metadata(self):
773         info = self.t.info()
774         self.assertEqual(len(info), 9)
775         self.assertEqual(info['last-translator'],
776            'John Doe <jdoe@example.com>\nJane Foobar <jfoobar@example.com>')
777 
778 
779 class DummyGNUTranslations(gettext.GNUTranslations):
780     def foo(self):
781         return 'foo'
782 
783 
784 class GettextCacheTestCase(GettextBaseTest):
785     def test_cache(self):
786         self.localedir = os.curdir
787         self.mofile = MOFILE
788 
789         self.assertEqual(len(gettext._translations), 0)
790 
791         t = gettext.translation('gettext', self.localedir)
792 
793         self.assertEqual(len(gettext._translations), 1)
794 
795         t = gettext.translation('gettext', self.localedir,
796                                 class_=DummyGNUTranslations)
797 
798         self.assertEqual(len(gettext._translations), 2)
799         self.assertEqual(t.__class__, DummyGNUTranslations)
800 
801         # Calling it again doesn't add to the cache
802 
803         t = gettext.translation('gettext', self.localedir,
804                                 class_=DummyGNUTranslations)
805 
806         self.assertEqual(len(gettext._translations), 2)
807         self.assertEqual(t.__class__, DummyGNUTranslations)
808 
809         # Test deprecated parameter codeset
810         with self.assertWarnsRegex(DeprecationWarning, 'parameter codeset'):
811             t = gettext.translation('gettext', self.localedir,
812                                     class_=DummyGNUTranslations,
813                                     codeset='utf-16')
814         self.assertEqual(len(gettext._translations), 2)
815         self.assertEqual(t.__class__, DummyGNUTranslations)
816         with self.assertWarns(DeprecationWarning):
817             self.assertEqual(t.output_charset(), 'utf-16')
818 
819 
820 class MiscTestCase(unittest.TestCase):
821     def test__all__(self):
822         blacklist = {'c2py', 'ENOENT'}
823         support.check__all__(self, gettext, blacklist=blacklist)
824 
825 
826 if __name__ == '__main__':
827     unittest.main()
828 
829 
830 # For reference, here's the .po file used to created the GNU_MO_DATA above.
831 #
832 # The original version was automatically generated from the sources with
833 # pygettext. Later it was manually modified to add plural forms support.
834 
835 b'''
836 # Dummy translation for the Python test_gettext.py module.
837 # Copyright (C) 2001 Python Software Foundation
838 # Barry Warsaw <barry@python.org>, 2000.
839 #
840 msgid ""
841 msgstr ""
842 "Project-Id-Version: 2.0\n"
843 "PO-Revision-Date: 2003-04-11 14:32-0400\n"
844 "Last-Translator: J. David Ibanez <j-david@noos.fr>\n"
845 "Language-Team: XX <python-dev@python.org>\n"
846 "MIME-Version: 1.0\n"
847 "Content-Type: text/plain; charset=iso-8859-1\n"
848 "Content-Transfer-Encoding: 8bit\n"
849 "Generated-By: pygettext.py 1.1\n"
850 "Plural-Forms: nplurals=2; plural=n!=1;\n"
851 
852 #: test_gettext.py:19 test_gettext.py:25 test_gettext.py:31 test_gettext.py:37
853 #: test_gettext.py:51 test_gettext.py:80 test_gettext.py:86 test_gettext.py:92
854 #: test_gettext.py:98
855 msgid "nudge nudge"
856 msgstr "wink wink"
857 
858 msgctxt "my context"
859 msgid "nudge nudge"
860 msgstr "wink wink (in \"my context\")"
861 
862 msgctxt "my other context"
863 msgid "nudge nudge"
864 msgstr "wink wink (in \"my other context\")"
865 
866 #: test_gettext.py:16 test_gettext.py:22 test_gettext.py:28 test_gettext.py:34
867 #: test_gettext.py:77 test_gettext.py:83 test_gettext.py:89 test_gettext.py:95
868 msgid "albatross"
869 msgstr ""
870 
871 #: test_gettext.py:18 test_gettext.py:24 test_gettext.py:30 test_gettext.py:36
872 #: test_gettext.py:79 test_gettext.py:85 test_gettext.py:91 test_gettext.py:97
873 msgid "Raymond Luxury Yach-t"
874 msgstr "Throatwobbler Mangrove"
875 
876 #: test_gettext.py:17 test_gettext.py:23 test_gettext.py:29 test_gettext.py:35
877 #: test_gettext.py:56 test_gettext.py:78 test_gettext.py:84 test_gettext.py:90
878 #: test_gettext.py:96
879 msgid "mullusk"
880 msgstr "bacon"
881 
882 #: test_gettext.py:40 test_gettext.py:101
883 msgid ""
884 "This module provides internationalization and localization\n"
885 "support for your Python programs by providing an interface to the GNU\n"
886 "gettext message catalog library."
887 msgstr ""
888 "Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba\n"
889 "fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH\n"
890 "trggrkg zrffntr pngnybt yvoenel."
891 
892 # Manually added, as neither pygettext nor xgettext support plural forms
893 # in Python.
894 msgid "There is %s file"
895 msgid_plural "There are %s files"
896 msgstr[0] "Hay %s fichero"
897 msgstr[1] "Hay %s ficheros"
898 
899 # Manually added, as neither pygettext nor xgettext support plural forms
900 # and context in Python.
901 msgctxt "With context"
902 msgid "There is %s file"
903 msgid_plural "There are %s files"
904 msgstr[0] "Hay %s fichero (context)"
905 msgstr[1] "Hay %s ficheros (context)"
906 '''
907 
908 # Here's the second example po file example, used to generate the UMO_DATA
909 # containing utf-8 encoded Unicode strings
910 
911 b'''
912 # Dummy translation for the Python test_gettext.py module.
913 # Copyright (C) 2001 Python Software Foundation
914 # Barry Warsaw <barry@python.org>, 2000.
915 #
916 msgid ""
917 msgstr ""
918 "Project-Id-Version: 2.0\n"
919 "PO-Revision-Date: 2003-04-11 12:42-0400\n"
920 "Last-Translator: Barry A. WArsaw <barry@python.org>\n"
921 "Language-Team: XX <python-dev@python.org>\n"
922 "MIME-Version: 1.0\n"
923 "Content-Type: text/plain; charset=utf-8\n"
924 "Content-Transfer-Encoding: 7bit\n"
925 "Generated-By: manually\n"
926 
927 #: nofile:0
928 msgid "ab\xc3\x9e"
929 msgstr "\xc2\xa4yz"
930 
931 #: nofile:1
932 msgctxt "mycontext\xc3\x9e"
933 msgid "ab\xc3\x9e"
934 msgstr "\xc2\xa4yz (context version)"
935 '''
936 
937 # Here's the third example po file, used to generate MMO_DATA
938 
939 b'''
940 msgid ""
941 msgstr ""
942 "Project-Id-Version: No Project 0.0\n"
943 "POT-Creation-Date: Wed Dec 11 07:44:15 2002\n"
944 "PO-Revision-Date: 2002-08-14 01:18:58+00:00\n"
945 "Last-Translator: John Doe <jdoe@example.com>\n"
946 "Jane Foobar <jfoobar@example.com>\n"
947 "Language-Team: xx <xx@example.com>\n"
948 "MIME-Version: 1.0\n"
949 "Content-Type: text/plain; charset=iso-8859-15\n"
950 "Content-Transfer-Encoding: quoted-printable\n"
951 "Generated-By: pygettext.py 1.3\n"
952 '''
953 
954 #
955 # messages.po, used for bug 17898
956 #
957 
958 b'''
959 # test file for http://bugs.python.org/issue17898
960 msgid ""
961 msgstr ""
962 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
963 "#-#-#-#-#  messages.po (EdX Studio)  #-#-#-#-#\n"
964 "Content-Type: text/plain; charset=UTF-8\n"
965 '''
966