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