1 import os 2 import base64 3 import shutil 4 import gettext 5 import unittest 6 7 from test import test_support 8 9 10 # TODO: 11 # - Add new tests, for example for "dgettext" 12 # - Remove dummy tests, for example testing for single and double quotes 13 # has no sense, it would have if we were testing a parser (i.e. pygettext) 14 # - Tests should have only one assert. 15 16 GNU_MO_DATA = '''\ 17 3hIElQAAAAAGAAAAHAAAAEwAAAALAAAAfAAAAAAAAACoAAAAFQAAAKkAAAAjAAAAvwAAAKEAAADj 18 AAAABwAAAIUBAAALAAAAjQEAAEUBAACZAQAAFgAAAN8CAAAeAAAA9gIAAKEAAAAVAwAABQAAALcD 19 AAAJAAAAvQMAAAEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABQAAAAYAAAACAAAAAFJh 20 eW1vbmQgTHV4dXJ5IFlhY2gtdABUaGVyZSBpcyAlcyBmaWxlAFRoZXJlIGFyZSAlcyBmaWxlcwBU 21 aGlzIG1vZHVsZSBwcm92aWRlcyBpbnRlcm5hdGlvbmFsaXphdGlvbiBhbmQgbG9jYWxpemF0aW9u 22 CnN1cHBvcnQgZm9yIHlvdXIgUHl0aG9uIHByb2dyYW1zIGJ5IHByb3ZpZGluZyBhbiBpbnRlcmZh 23 Y2UgdG8gdGhlIEdOVQpnZXR0ZXh0IG1lc3NhZ2UgY2F0YWxvZyBsaWJyYXJ5LgBtdWxsdXNrAG51 24 ZGdlIG51ZGdlAFByb2plY3QtSWQtVmVyc2lvbjogMi4wClBPLVJldmlzaW9uLURhdGU6IDIwMDAt 25 MDgtMjkgMTI6MTktMDQ6MDAKTGFzdC1UcmFuc2xhdG9yOiBKLiBEYXZpZCBJYsOhw7FleiA8ai1k 26 YXZpZEBub29zLmZyPgpMYW5ndWFnZS1UZWFtOiBYWCA8cHl0aG9uLWRldkBweXRob24ub3JnPgpN 27 SU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9aXNvLTg4 28 NTktMQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBub25lCkdlbmVyYXRlZC1CeTogcHlnZXR0 29 ZXh0LnB5IDEuMQpQbHVyYWwtRm9ybXM6IG5wbHVyYWxzPTI7IHBsdXJhbD1uIT0xOwoAVGhyb2F0 30 d29iYmxlciBNYW5ncm92ZQBIYXkgJXMgZmljaGVybwBIYXkgJXMgZmljaGVyb3MAR3V2ZiB6YnFo 31 eXIgY2ViaXZxcmYgdmFncmVhbmd2YmFueXZtbmd2YmEgbmFxIHlicG55dm1uZ3ZiYQpmaGNjYmVn 32 IHNiZSBsYmhlIENsZ3ViYSBjZWJ0ZW56ZiBvbCBjZWJpdnF2YXQgbmEgdmFncmVzbnByIGdiIGd1 33 ciBUQUgKdHJnZ3JrZyB6cmZmbnRyIHBuZ255YnQgeXZvZW5lbC4AYmFjb24Ad2luayB3aW5rAA== 34 ''' 35 36 UMO_DATA = '''\ 37 3hIElQAAAAACAAAAHAAAACwAAAAFAAAAPAAAAAAAAABQAAAABAAAAFEAAAAPAQAAVgAAAAQAAABm 38 AQAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAYWLDngBQcm9qZWN0LUlkLVZlcnNpb246IDIuMApQTy1S 39 ZXZpc2lvbi1EYXRlOiAyMDAzLTA0LTExIDEyOjQyLTA0MDAKTGFzdC1UcmFuc2xhdG9yOiBCYXJy 40 eSBBLiBXQXJzYXcgPGJhcnJ5QHB5dGhvbi5vcmc+Ckxhbmd1YWdlLVRlYW06IFhYIDxweXRob24t 41 ZGV2QHB5dGhvbi5vcmc+Ck1JTUUtVmVyc2lvbjogMS4wCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFp 42 bjsgY2hhcnNldD11dGYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA3Yml0CkdlbmVyYXRl 43 ZC1CeTogbWFudWFsbHkKAMKkeXoA 44 ''' 45 46 MMO_DATA = '''\ 47 3hIElQAAAAABAAAAHAAAACQAAAADAAAALAAAAAAAAAA4AAAAeAEAADkAAAABAAAAAAAAAAAAAAAA 48 UHJvamVjdC1JZC1WZXJzaW9uOiBObyBQcm9qZWN0IDAuMApQT1QtQ3JlYXRpb24tRGF0ZTogV2Vk 49 IERlYyAxMSAwNzo0NDoxNSAyMDAyClBPLVJldmlzaW9uLURhdGU6IDIwMDItMDgtMTQgMDE6MTg6 50 NTgrMDA6MDAKTGFzdC1UcmFuc2xhdG9yOiBKb2huIERvZSA8amRvZUBleGFtcGxlLmNvbT4KSmFu 51 ZSBGb29iYXIgPGpmb29iYXJAZXhhbXBsZS5jb20+Ckxhbmd1YWdlLVRlYW06IHh4IDx4eEBleGFt 52 cGxlLmNvbT4KTUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFy 53 c2V0PWlzby04ODU5LTE1CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFi 54 bGUKR2VuZXJhdGVkLUJ5OiBweWdldHRleHQucHkgMS4zCgA= 55 ''' 56 57 LOCALEDIR = os.path.join('xx', 'LC_MESSAGES') 58 MOFILE = os.path.join(LOCALEDIR, 'gettext.mo') 59 UMOFILE = os.path.join(LOCALEDIR, 'ugettext.mo') 60 MMOFILE = os.path.join(LOCALEDIR, 'metadata.mo') 61 62 63 class GettextBaseTest(unittest.TestCase): 64 def setUp(self): 65 if not os.path.isdir(LOCALEDIR): 66 os.makedirs(LOCALEDIR) 67 with open(MOFILE, 'wb') as fp: 68 fp.write(base64.decodestring(GNU_MO_DATA)) 69 with open(UMOFILE, 'wb') as fp: 70 fp.write(base64.decodestring(UMO_DATA)) 71 with open(MMOFILE, 'wb') as fp: 72 fp.write(base64.decodestring(MMO_DATA)) 73 74 self.env = test_support.EnvironmentVarGuard() 75 self.env['LANGUAGE'] = 'xx' 76 gettext._translations.clear() 77 78 def tearDown(self): 79 self.env.__exit__() 80 del self.env 81 shutil.rmtree(os.path.split(LOCALEDIR)[0]) 82 83 84 class GettextTestCase1(GettextBaseTest): 85 def setUp(self): 86 GettextBaseTest.setUp(self) 87 self.localedir = os.curdir 88 self.mofile = MOFILE 89 gettext.install('gettext', self.localedir) 90 91 def test_some_translations(self): 92 eq = self.assertEqual 93 # test some translations 94 eq(_('albatross'), 'albatross') 95 eq(_(u'mullusk'), 'bacon') 96 eq(_(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove') 97 eq(_(ur'nudge nudge'), 'wink wink') 98 99 def test_double_quotes(self): 100 eq = self.assertEqual 101 # double quotes 102 eq(_("albatross"), 'albatross') 103 eq(_(u"mullusk"), 'bacon') 104 eq(_(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove') 105 eq(_(ur"nudge nudge"), 'wink wink') 106 107 def test_triple_single_quotes(self): 108 eq = self.assertEqual 109 # triple single quotes 110 eq(_('''albatross'''), 'albatross') 111 eq(_(u'''mullusk'''), 'bacon') 112 eq(_(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove') 113 eq(_(ur'''nudge nudge'''), 'wink wink') 114 115 def test_triple_double_quotes(self): 116 eq = self.assertEqual 117 # triple double quotes 118 eq(_("""albatross"""), 'albatross') 119 eq(_(u"""mullusk"""), 'bacon') 120 eq(_(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove') 121 eq(_(ur"""nudge nudge"""), 'wink wink') 122 123 def test_multiline_strings(self): 124 eq = self.assertEqual 125 # multiline strings 126 eq(_('''This module provides internationalization and localization 127 support for your Python programs by providing an interface to the GNU 128 gettext message catalog library.'''), 129 '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba 130 fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH 131 trggrkg zrffntr pngnybt yvoenel.''') 132 133 def test_the_alternative_interface(self): 134 eq = self.assertEqual 135 # test the alternative interface 136 with open(self.mofile, 'rb') as fp: 137 t = gettext.GNUTranslations(fp) 138 # Install the translation object 139 t.install() 140 eq(_('nudge nudge'), 'wink wink') 141 # Try unicode return type 142 t.install(unicode=True) 143 eq(_('mullusk'), 'bacon') 144 # Test installation of other methods 145 import __builtin__ 146 t.install(unicode=True, names=["gettext", "lgettext"]) 147 eq(_, t.ugettext) 148 eq(__builtin__.gettext, t.ugettext) 149 eq(lgettext, t.lgettext) 150 del __builtin__.gettext 151 del __builtin__.lgettext 152 153 154 class GettextTestCase2(GettextBaseTest): 155 def setUp(self): 156 GettextBaseTest.setUp(self) 157 self.localedir = os.curdir 158 # Set up the bindings 159 gettext.bindtextdomain('gettext', self.localedir) 160 gettext.textdomain('gettext') 161 # For convenience 162 self._ = gettext.gettext 163 164 def test_bindtextdomain(self): 165 self.assertEqual(gettext.bindtextdomain('gettext'), self.localedir) 166 167 def test_textdomain(self): 168 self.assertEqual(gettext.textdomain(), 'gettext') 169 170 def test_some_translations(self): 171 eq = self.assertEqual 172 # test some translations 173 eq(self._('albatross'), 'albatross') 174 eq(self._(u'mullusk'), 'bacon') 175 eq(self._(r'Raymond Luxury Yach-t'), 'Throatwobbler Mangrove') 176 eq(self._(ur'nudge nudge'), 'wink wink') 177 178 def test_double_quotes(self): 179 eq = self.assertEqual 180 # double quotes 181 eq(self._("albatross"), 'albatross') 182 eq(self._(u"mullusk"), 'bacon') 183 eq(self._(r"Raymond Luxury Yach-t"), 'Throatwobbler Mangrove') 184 eq(self._(ur"nudge nudge"), 'wink wink') 185 186 def test_triple_single_quotes(self): 187 eq = self.assertEqual 188 # triple single quotes 189 eq(self._('''albatross'''), 'albatross') 190 eq(self._(u'''mullusk'''), 'bacon') 191 eq(self._(r'''Raymond Luxury Yach-t'''), 'Throatwobbler Mangrove') 192 eq(self._(ur'''nudge nudge'''), 'wink wink') 193 194 def test_triple_double_quotes(self): 195 eq = self.assertEqual 196 # triple double quotes 197 eq(self._("""albatross"""), 'albatross') 198 eq(self._(u"""mullusk"""), 'bacon') 199 eq(self._(r"""Raymond Luxury Yach-t"""), 'Throatwobbler Mangrove') 200 eq(self._(ur"""nudge nudge"""), 'wink wink') 201 202 def test_multiline_strings(self): 203 eq = self.assertEqual 204 # multiline strings 205 eq(self._('''This module provides internationalization and localization 206 support for your Python programs by providing an interface to the GNU 207 gettext message catalog library.'''), 208 '''Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba 209 fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH 210 trggrkg zrffntr pngnybt yvoenel.''') 211 212 213 class PluralFormsTestCase(GettextBaseTest): 214 def setUp(self): 215 GettextBaseTest.setUp(self) 216 self.mofile = MOFILE 217 218 def test_plural_forms1(self): 219 eq = self.assertEqual 220 x = gettext.ngettext('There is %s file', 'There are %s files', 1) 221 eq(x, 'Hay %s fichero') 222 x = gettext.ngettext('There is %s file', 'There are %s files', 2) 223 eq(x, 'Hay %s ficheros') 224 225 def test_plural_forms2(self): 226 eq = self.assertEqual 227 with open(self.mofile, 'rb') as fp: 228 t = gettext.GNUTranslations(fp) 229 x = t.ngettext('There is %s file', 'There are %s files', 1) 230 eq(x, 'Hay %s fichero') 231 x = t.ngettext('There is %s file', 'There are %s files', 2) 232 eq(x, 'Hay %s ficheros') 233 234 def test_hu(self): 235 eq = self.assertEqual 236 f = gettext.c2py('0') 237 s = ''.join([ str(f(x)) for x in range(200) ]) 238 eq(s, "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") 239 240 def test_de(self): 241 eq = self.assertEqual 242 f = gettext.c2py('n != 1') 243 s = ''.join([ str(f(x)) for x in range(200) ]) 244 eq(s, "10111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") 245 246 def test_fr(self): 247 eq = self.assertEqual 248 f = gettext.c2py('n>1') 249 s = ''.join([ str(f(x)) for x in range(200) ]) 250 eq(s, "00111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") 251 252 def test_gd(self): 253 eq = self.assertEqual 254 f = gettext.c2py('n==1 ? 0 : n==2 ? 1 : 2') 255 s = ''.join([ str(f(x)) for x in range(200) ]) 256 eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222") 257 258 def test_gd2(self): 259 eq = self.assertEqual 260 # Tests the combination of parentheses and "?:" 261 f = gettext.c2py('n==1 ? 0 : (n==2 ? 1 : 2)') 262 s = ''.join([ str(f(x)) for x in range(200) ]) 263 eq(s, "20122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222") 264 265 def test_lt(self): 266 eq = self.assertEqual 267 f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2') 268 s = ''.join([ str(f(x)) for x in range(200) ]) 269 eq(s, "20111111112222222222201111111120111111112011111111201111111120111111112011111111201111111120111111112011111111222222222220111111112011111111201111111120111111112011111111201111111120111111112011111111") 270 271 def test_ru(self): 272 eq = self.assertEqual 273 f = gettext.c2py('n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2') 274 s = ''.join([ str(f(x)) for x in range(200) ]) 275 eq(s, "20111222222222222222201112222220111222222011122222201112222220111222222011122222201112222220111222222011122222222222222220111222222011122222201112222220111222222011122222201112222220111222222011122222") 276 277 def test_pl(self): 278 eq = self.assertEqual 279 f = gettext.c2py('n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2') 280 s = ''.join([ str(f(x)) for x in range(200) ]) 281 eq(s, "20111222222222222222221112222222111222222211122222221112222222111222222211122222221112222222111222222211122222222222222222111222222211122222221112222222111222222211122222221112222222111222222211122222") 282 283 def test_sl(self): 284 eq = self.assertEqual 285 f = gettext.c2py('n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3') 286 s = ''.join([ str(f(x)) for x in range(200) ]) 287 eq(s, "30122333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333012233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333") 288 289 def test_security(self): 290 raises = self.assertRaises 291 # Test for a dangerous expression 292 raises(ValueError, gettext.c2py, "os.chmod('/etc/passwd',0777)") 293 294 295 class UnicodeTranslationsTest(GettextBaseTest): 296 def setUp(self): 297 GettextBaseTest.setUp(self) 298 with open(UMOFILE, 'rb') as fp: 299 self.t = gettext.GNUTranslations(fp) 300 self._ = self.t.ugettext 301 302 def test_unicode_msgid(self): 303 unless = self.assertTrue 304 unless(isinstance(self._(''), unicode)) 305 unless(isinstance(self._(u''), unicode)) 306 307 def test_unicode_msgstr(self): 308 eq = self.assertEqual 309 eq(self._(u'ab\xde'), u'\xa4yz') 310 311 312 class WeirdMetadataTest(GettextBaseTest): 313 def setUp(self): 314 GettextBaseTest.setUp(self) 315 with open(MMOFILE, 'rb') as fp: 316 try: 317 self.t = gettext.GNUTranslations(fp) 318 except: 319 self.tearDown() 320 raise 321 322 def test_weird_metadata(self): 323 info = self.t.info() 324 self.assertEqual(info['last-translator'], 325 'John Doe <jdoe (at] example.com>\nJane Foobar <jfoobar (at] example.com>') 326 327 328 class DummyGNUTranslations(gettext.GNUTranslations): 329 def foo(self): 330 return 'foo' 331 332 333 class GettextCacheTestCase(GettextBaseTest): 334 def test_cache(self): 335 self.localedir = os.curdir 336 self.mofile = MOFILE 337 338 self.assertEqual(len(gettext._translations), 0) 339 340 t = gettext.translation('gettext', self.localedir) 341 342 self.assertEqual(len(gettext._translations), 1) 343 344 t = gettext.translation('gettext', self.localedir, 345 class_=DummyGNUTranslations) 346 347 self.assertEqual(len(gettext._translations), 2) 348 self.assertEqual(t.__class__, DummyGNUTranslations) 349 350 # Calling it again doesn't add to the cache 351 352 t = gettext.translation('gettext', self.localedir, 353 class_=DummyGNUTranslations) 354 355 self.assertEqual(len(gettext._translations), 2) 356 self.assertEqual(t.__class__, DummyGNUTranslations) 357 358 359 def test_main(): 360 test_support.run_unittest(__name__) 361 362 if __name__ == '__main__': 363 test_main() 364 365 366 # For reference, here's the .po file used to created the GNU_MO_DATA above. 367 # 368 # The original version was automatically generated from the sources with 369 # pygettext. Later it was manually modified to add plural forms support. 370 371 ''' 372 # Dummy translation for the Python test_gettext.py module. 373 # Copyright (C) 2001 Python Software Foundation 374 # Barry Warsaw <barry (at] python.org>, 2000. 375 # 376 msgid "" 377 msgstr "" 378 "Project-Id-Version: 2.0\n" 379 "PO-Revision-Date: 2003-04-11 14:32-0400\n" 380 "Last-Translator: J. David Ibanez <j-david (at] noos.fr>\n" 381 "Language-Team: XX <python-dev (at] python.org>\n" 382 "MIME-Version: 1.0\n" 383 "Content-Type: text/plain; charset=iso-8859-1\n" 384 "Content-Transfer-Encoding: 8bit\n" 385 "Generated-By: pygettext.py 1.1\n" 386 "Plural-Forms: nplurals=2; plural=n!=1;\n" 387 388 #: test_gettext.py:19 test_gettext.py:25 test_gettext.py:31 test_gettext.py:37 389 #: test_gettext.py:51 test_gettext.py:80 test_gettext.py:86 test_gettext.py:92 390 #: test_gettext.py:98 391 msgid "nudge nudge" 392 msgstr "wink wink" 393 394 #: test_gettext.py:16 test_gettext.py:22 test_gettext.py:28 test_gettext.py:34 395 #: test_gettext.py:77 test_gettext.py:83 test_gettext.py:89 test_gettext.py:95 396 msgid "albatross" 397 msgstr "" 398 399 #: test_gettext.py:18 test_gettext.py:24 test_gettext.py:30 test_gettext.py:36 400 #: test_gettext.py:79 test_gettext.py:85 test_gettext.py:91 test_gettext.py:97 401 msgid "Raymond Luxury Yach-t" 402 msgstr "Throatwobbler Mangrove" 403 404 #: test_gettext.py:17 test_gettext.py:23 test_gettext.py:29 test_gettext.py:35 405 #: test_gettext.py:56 test_gettext.py:78 test_gettext.py:84 test_gettext.py:90 406 #: test_gettext.py:96 407 msgid "mullusk" 408 msgstr "bacon" 409 410 #: test_gettext.py:40 test_gettext.py:101 411 msgid "" 412 "This module provides internationalization and localization\n" 413 "support for your Python programs by providing an interface to the GNU\n" 414 "gettext message catalog library." 415 msgstr "" 416 "Guvf zbqhyr cebivqrf vagreangvbanyvmngvba naq ybpnyvmngvba\n" 417 "fhccbeg sbe lbhe Clguba cebtenzf ol cebivqvat na vagresnpr gb gur TAH\n" 418 "trggrkg zrffntr pngnybt yvoenel." 419 420 # Manually added, as neither pygettext nor xgettext support plural forms 421 # in Python. 422 msgid "There is %s file" 423 msgid_plural "There are %s files" 424 msgstr[0] "Hay %s fichero" 425 msgstr[1] "Hay %s ficheros" 426 ''' 427 428 # Here's the second example po file example, used to generate the UMO_DATA 429 # containing utf-8 encoded Unicode strings 430 431 ''' 432 # Dummy translation for the Python test_gettext.py module. 433 # Copyright (C) 2001 Python Software Foundation 434 # Barry Warsaw <barry (at] python.org>, 2000. 435 # 436 msgid "" 437 msgstr "" 438 "Project-Id-Version: 2.0\n" 439 "PO-Revision-Date: 2003-04-11 12:42-0400\n" 440 "Last-Translator: Barry A. WArsaw <barry (at] python.org>\n" 441 "Language-Team: XX <python-dev (at] python.org>\n" 442 "MIME-Version: 1.0\n" 443 "Content-Type: text/plain; charset=utf-8\n" 444 "Content-Transfer-Encoding: 7bit\n" 445 "Generated-By: manually\n" 446 447 #: nofile:0 448 msgid "ab\xc3\x9e" 449 msgstr "\xc2\xa4yz" 450 ''' 451 452 # Here's the third example po file, used to generate MMO_DATA 453 454 ''' 455 msgid "" 456 msgstr "" 457 "Project-Id-Version: No Project 0.0\n" 458 "POT-Creation-Date: Wed Dec 11 07:44:15 2002\n" 459 "PO-Revision-Date: 2002-08-14 01:18:58+00:00\n" 460 "Last-Translator: John Doe <jdoe (at] example.com>\n" 461 "Jane Foobar <jfoobar (at] example.com>\n" 462 "Language-Team: xx <xx (at] example.com>\n" 463 "MIME-Version: 1.0\n" 464 "Content-Type: text/plain; charset=iso-8859-15\n" 465 "Content-Transfer-Encoding: quoted-printable\n" 466 "Generated-By: pygettext.py 1.3\n" 467 ''' 468