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