1import os 2import base64 3import contextlib 4import gettext 5import unittest 6 7from 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 16GNU_MO_DATA = b'''\ 173hIElQAAAAAJAAAAHAAAAGQAAAAAAAAArAAAAAAAAACsAAAAFQAAAK0AAAAjAAAAwwAAAKEAAADn 18AAAAMAAAAIkBAAAHAAAAugEAABYAAADCAQAAHAAAANkBAAALAAAA9gEAAEIBAAACAgAAFgAAAEUD 19AAAeAAAAXAMAAKEAAAB7AwAAMgAAAB0EAAAFAAAAUAQAABsAAABWBAAAIQAAAHIEAAAJAAAAlAQA 20AABSYXltb25kIEx1eHVyeSBZYWNoLXQAVGhlcmUgaXMgJXMgZmlsZQBUaGVyZSBhcmUgJXMgZmls 21ZXMAVGhpcyBtb2R1bGUgcHJvdmlkZXMgaW50ZXJuYXRpb25hbGl6YXRpb24gYW5kIGxvY2FsaXph 22dGlvbgpzdXBwb3J0IGZvciB5b3VyIFB5dGhvbiBwcm9ncmFtcyBieSBwcm92aWRpbmcgYW4gaW50 23ZXJmYWNlIHRvIHRoZSBHTlUKZ2V0dGV4dCBtZXNzYWdlIGNhdGFsb2cgbGlicmFyeS4AV2l0aCBj 24b250ZXh0BFRoZXJlIGlzICVzIGZpbGUAVGhlcmUgYXJlICVzIGZpbGVzAG11bGx1c2sAbXkgY29u 25dGV4dARudWRnZSBudWRnZQBteSBvdGhlciBjb250ZXh0BG51ZGdlIG51ZGdlAG51ZGdlIG51ZGdl 26AFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDMtMDQtMTEgMTQ6 27MzItMDQwMApMYXN0LVRyYW5zbGF0b3I6IEouIERhdmlkIEliYW5leiA8ai1kYXZpZEBub29zLmZy 28PgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpNSU1FLVZlcnNpb246 29IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4NTktMQpDb250ZW50 30LVRyYW5zZmVyLUVuY29kaW5nOiA4Yml0CkdlbmVyYXRlZC1CeTogcHlnZXR0ZXh0LnB5IDEuMQpQ 31bHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0d29iYmxlciBNYW5n 32cm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFoeXIgY2ViaXZxcmYg 33dmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVnIHNiZSBsYmhlIENs 34Z3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1ciBUQUgKdHJnZ3Jr 35ZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4ASGF5ICVzIGZpY2hlcm8gKGNvbnRleHQpAEhheSAl 36cyBmaWNoZXJvcyAoY29udGV4dCkAYmFjb24Ad2luayB3aW5rIChpbiAibXkgY29udGV4dCIpAHdp 37bmsgd2luayAoaW4gIm15IG90aGVyIGNvbnRleHQiKQB3aW5rIHdpbmsA 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 44GNU_MO_DATA_BAD_MAJOR_VERSION = b'''\ 453hIElQAABQAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj 46AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD 47AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh 48eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU 49aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u 50CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh 51Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51 52ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt 53MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k 54YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN 55SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4 56NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0 57ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0 58d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo 59eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn 60IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1 61ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA== 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 68GNU_MO_DATA_BAD_MINOR_VERSION = b'''\ 693hIElQcAAAAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj 70AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD 71AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh 72eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU 73aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u 74CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh 75Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51 76ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt 77MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k 78YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN 79SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4 80NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0 81ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0 82d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo 83eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn 84IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1 85ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA== 86''' 87 88 89UMO_DATA = b'''\ 903hIElQAAAAADAAAAHAAAADQAAAAAAAAAAAAAAAAAAABMAAAABAAAAE0AAAAQAAAAUgAAAA8BAABj 91AAAABAAAAHMBAAAWAAAAeAEAAABhYsOeAG15Y29udGV4dMOeBGFiw54AUHJvamVjdC1JZC1WZXJz 92aW9uOiAyLjAKUE8tUmV2aXNpb24tRGF0ZTogMjAwMy0wNC0xMSAxMjo0Mi0wNDAwCkxhc3QtVHJh 93bnNsYXRvcjogQmFycnkgQS4gV0Fyc2F3IDxiYXJyeUBweXRob24ub3JnPgpMYW5ndWFnZS1UZWFt 94OiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpNSU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5 95cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzog 96N2JpdApHZW5lcmF0ZWQtQnk6IG1hbnVhbGx5CgDCpHl6AMKkeXogKGNvbnRleHQgdmVyc2lvbikA 97''' 98 99MMO_DATA = b'''\ 1003hIElQAAAAABAAAAHAAAACQAAAADAAAALAAAAAAAAAA4AAAAeAEAADkAAAABAAAAAAAAAAAAAAAA 101UHJvamVjdC1JZC1WZXJzaW9uOiBObyBQcm9qZWN0IDAuMApQT1QtQ3JlYXRpb24tRGF0ZTogV2Vk 102IERlYyAxMSAwNzo0NDoxNSAyMDAyClBPLVJldmlzaW9uLURhdGU6IDIwMDItMDgtMTQgMDE6MTg6 103NTgrMDA6MDAKTGFzdC1UcmFuc2xhdG9yOiBKb2huIERvZSA8amRvZUBleGFtcGxlLmNvbT4KSmFu 104ZSBGb29iYXIgPGpmb29iYXJAZXhhbXBsZS5jb20+Ckxhbmd1YWdlLVRlYW06IHh4IDx4eEBleGFt 105cGxlLmNvbT4KTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFy 106c2V0PWlzby04ODU5LTE1CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFi 107bGUKR2VuZXJhdGVkLUJ5OiBweWdldHRleHQucHkgMS4zCgA= 108''' 109 110LOCALEDIR = os.path.join('xx', 'LC_MESSAGES') 111MOFILE = os.path.join(LOCALEDIR, 'gettext.mo') 112MOFILE_BAD_MAJOR_VERSION = os.path.join(LOCALEDIR, 'gettext_bad_major_version.mo') 113MOFILE_BAD_MINOR_VERSION = os.path.join(LOCALEDIR, 'gettext_bad_minor_version.mo') 114UMOFILE = os.path.join(LOCALEDIR, 'ugettext.mo') 115MMOFILE = os.path.join(LOCALEDIR, 'metadata.mo') 116 117 118class 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 141GNU_MO_DATA_ISSUE_17898 = b'''\ 1423hIElQAAAAABAAAAHAAAACQAAAAAAAAAAAAAAAAAAAAsAAAAggAAAC0AAAAAUGx1cmFsLUZvcm1z 143OiBucGx1cmFscz0yOyBwbHVyYWw9KG4gIT0gMSk7CiMtIy0jLSMtIyAgbWVzc2FnZXMucG8gKEVk 144WCBTdHVkaW8pICAjLSMtIy0jLSMKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PVVU 145Ri04CgA= 146''' 147 148class 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 198support for your Python programs by providing an interface to the GNU 199gettext message catalog library.'''), 200 '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba 201fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH 202trggrkg 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 225class 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 306support for your Python programs by providing an interface to the GNU 307gettext message catalog library.'''), 308 '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba 309fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH 310trggrkg zrffntr pngnybt yvoenel.''') 311 312 313class 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 504class 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 678class 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 700class 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 720class 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 762class 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 779class DummyGNUTranslations(gettext.GNUTranslations): 780 def foo(self): 781 return 'foo' 782 783 784class 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 820class MiscTestCase(unittest.TestCase): 821 def test__all__(self): 822 blacklist = {'c2py', 'ENOENT'} 823 support.check__all__(self, gettext, blacklist=blacklist) 824 825 826if __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 835b''' 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# 840msgid "" 841msgstr "" 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 855msgid "nudge nudge" 856msgstr "wink wink" 857 858msgctxt "my context" 859msgid "nudge nudge" 860msgstr "wink wink (in \"my context\")" 861 862msgctxt "my other context" 863msgid "nudge nudge" 864msgstr "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 868msgid "albatross" 869msgstr "" 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 873msgid "Raymond Luxury Yach-t" 874msgstr "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 879msgid "mullusk" 880msgstr "bacon" 881 882#: test_gettext.py:40 test_gettext.py:101 883msgid "" 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." 887msgstr "" 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. 894msgid "There is %s file" 895msgid_plural "There are %s files" 896msgstr[0] "Hay %s fichero" 897msgstr[1] "Hay %s ficheros" 898 899# Manually added, as neither pygettext nor xgettext support plural forms 900# and context in Python. 901msgctxt "With context" 902msgid "There is %s file" 903msgid_plural "There are %s files" 904msgstr[0] "Hay %s fichero (context)" 905msgstr[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 911b''' 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# 916msgid "" 917msgstr "" 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 928msgid "ab\xc3\x9e" 929msgstr "\xc2\xa4yz" 930 931#: nofile:1 932msgctxt "mycontext\xc3\x9e" 933msgid "ab\xc3\x9e" 934msgstr "\xc2\xa4yz (context version)" 935''' 936 937# Here's the third example po file, used to generate MMO_DATA 938 939b''' 940msgid "" 941msgstr "" 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 958b''' 959# test file for http://bugs.python.org/issue17898 960msgid "" 961msgstr "" 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