1
# -*- coding: utf-8 -*-
3
# Copyright (C) 2007-2011 Edgewall Software
6
# This software is licensed as described in the file COPYING, which
7
# you should have received as part of this distribution. The terms
8
# are also available at http://babel.edgewall.org/wiki/License.
10
# This software consists of voluntary contributions made by many
11
# individuals. For the exact contribution history, see the revision
12
# history and logs, available at http://babel.edgewall.org/log/.
18
from babel.messages import extract
19
from babel._compat import BytesIO, StringIO
22
class ExtractPythonTestCase(unittest.TestCase):
24
def test_nested_calls(self):
26
msg1 = _(i18n_arg.replace(r'\"', '"'))
27
msg2 = ungettext(i18n_arg.replace(r'\"', '"'), multi_arg.replace(r'\"', '"'), 2)
28
msg3 = ungettext("Babel", multi_arg.replace(r'\"', '"'), 2)
29
msg4 = ungettext(i18n_arg.replace(r'\"', '"'), "Babels", 2)
30
msg5 = ungettext('bunny', 'bunnies', random.randint(1, 2))
31
msg6 = ungettext(arg0, 'bunnies', random.randint(1, 2))
33
msg8 = gettext('Rabbit')
34
msg9 = dgettext('wiki', model.addPage())
35
msg10 = dngettext(getDomain(), 'Page', 'Pages', 3)
37
messages = list(extract.extract_python(buf,
38
extract.DEFAULT_KEYWORDS.keys(),
42
(2, 'ungettext', (None, None, None), []),
43
(3, 'ungettext', (u'Babel', None, None), []),
44
(4, 'ungettext', (None, u'Babels', None), []),
45
(5, 'ungettext', (u'bunny', u'bunnies', None), []),
46
(6, 'ungettext', (None, u'bunnies', None), []),
48
(8, 'gettext', u'Rabbit', []),
49
(9, 'dgettext', (u'wiki', None), []),
50
(10, 'dngettext', (None, u'Page', u'Pages', None), [])],
53
def test_nested_comments(self):
55
msg = ngettext('pylon', # TRANSLATORS: shouldn't be
56
'pylons', # TRANSLATORS: seeing this
59
messages = list(extract.extract_python(buf, ('ngettext',),
60
['TRANSLATORS:'], {}))
61
self.assertEqual([(1, 'ngettext', (u'pylon', u'pylons', None), [])],
64
def test_comments_with_calls_that_spawn_multiple_lines(self):
66
# NOTE: This Comment SHOULD Be Extracted
67
add_notice(req, ngettext("Catalog deleted.",
68
"Catalogs deleted.", len(selected)))
70
# NOTE: This Comment SHOULD Be Extracted
71
add_notice(req, _("Locale deleted."))
74
# NOTE: This Comment SHOULD Be Extracted
75
add_notice(req, ngettext("Foo deleted.", "Foos deleted.", len(selected)))
77
# NOTE: This Comment SHOULD Be Extracted
78
# NOTE: And This One Too
79
add_notice(req, ngettext("Bar deleted.",
80
"Bars deleted.", len(selected)))
82
messages = list(extract.extract_python(buf, ('ngettext','_'), ['NOTE:'],
84
{'strip_comment_tags':False}))
85
self.assertEqual((6, '_', 'Locale deleted.',
86
[u'NOTE: This Comment SHOULD Be Extracted']),
88
self.assertEqual((10, 'ngettext', (u'Foo deleted.', u'Foos deleted.',
90
[u'NOTE: This Comment SHOULD Be Extracted']),
92
self.assertEqual((3, 'ngettext',
94
u'Catalogs deleted.', None),
95
[u'NOTE: This Comment SHOULD Be Extracted']),
97
self.assertEqual((15, 'ngettext', (u'Bar deleted.', u'Bars deleted.',
99
[u'NOTE: This Comment SHOULD Be Extracted',
100
u'NOTE: And This One Too']),
103
def test_declarations(self):
105
class gettext(object):
107
def render_body(context,x,y=_('Page arg 1'),z=_('Page arg 2'),**pageargs):
109
def ngettext(y='arg 1',z='arg 2',**pageargs):
112
verbose_name = _('log entry')
114
messages = list(extract.extract_python(buf,
115
extract.DEFAULT_KEYWORDS.keys(),
117
self.assertEqual([(3, '_', u'Page arg 1', []),
118
(3, '_', u'Page arg 2', []),
119
(8, '_', u'log entry', [])],
122
def test_multiline(self):
124
msg1 = ngettext('pylon',
126
msg2 = ngettext('elvis',
130
messages = list(extract.extract_python(buf, ('ngettext',), [], {}))
131
self.assertEqual([(1, 'ngettext', (u'pylon', u'pylons', None), []),
132
(3, 'ngettext', (u'elvis', u'elvises', None), [])],
135
def test_triple_quoted_strings(self):
137
msg1 = _('''pylons''')
138
msg2 = ngettext(r'''elvis''', \"\"\"elvises\"\"\", count)
139
msg2 = ngettext(\"\"\"elvis\"\"\", 'elvises', count)
141
messages = list(extract.extract_python(buf,
142
extract.DEFAULT_KEYWORDS.keys(),
144
self.assertEqual([(1, '_', (u'pylons'), []),
145
(2, 'ngettext', (u'elvis', u'elvises', None), []),
146
(3, 'ngettext', (u'elvis', u'elvises', None), [])],
149
def test_multiline_strings(self):
151
_('''This module provides internationalization and localization
152
support for your Python programs by providing an interface to the GNU
153
gettext message catalog library.''')
155
messages = list(extract.extract_python(buf,
156
extract.DEFAULT_KEYWORDS.keys(),
160
u'This module provides internationalization and localization\n'
161
'support for your Python programs by providing an interface to '
162
'the GNU\ngettext message catalog library.', [])],
165
def test_concatenated_strings(self):
167
foobar = _('foo' 'bar')
169
messages = list(extract.extract_python(buf,
170
extract.DEFAULT_KEYWORDS.keys(),
172
self.assertEqual(u'foobar', messages[0][2])
174
def test_unicode_string_arg(self):
175
buf = BytesIO(b"msg = _(u'Foo Bar')")
176
messages = list(extract.extract_python(buf, ('_',), [], {}))
177
self.assertEqual(u'Foo Bar', messages[0][2])
179
def test_comment_tag(self):
181
# NOTE: A translation comment
184
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
185
self.assertEqual(u'Foo Bar', messages[0][2])
186
self.assertEqual([u'NOTE: A translation comment'], messages[0][3])
188
def test_comment_tag_multiline(self):
190
# NOTE: A translation comment
194
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
195
self.assertEqual(u'Foo Bar', messages[0][2])
196
self.assertEqual([u'NOTE: A translation comment', u'with a second line'],
199
def test_translator_comments_with_previous_non_translator_comments(self):
201
# This shouldn't be in the output
202
# because it didn't start with a comment tag
203
# NOTE: A translation comment
207
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
208
self.assertEqual(u'Foo Bar', messages[0][2])
209
self.assertEqual([u'NOTE: A translation comment', u'with a second line'],
212
def test_comment_tags_not_on_start_of_comment(self):
214
# This shouldn't be in the output
215
# because it didn't start with a comment tag
216
# do NOTE: this will not be a translation comment
217
# NOTE: This one will be
220
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
221
self.assertEqual(u'Foo Bar', messages[0][2])
222
self.assertEqual([u'NOTE: This one will be'], messages[0][3])
224
def test_multiple_comment_tags(self):
226
# NOTE1: A translation comment for tag1
230
# NOTE2: A translation comment for tag2
233
messages = list(extract.extract_python(buf, ('_',),
234
['NOTE1:', 'NOTE2:'], {}))
235
self.assertEqual(u'Foo Bar1', messages[0][2])
236
self.assertEqual([u'NOTE1: A translation comment for tag1',
237
u'with a second line'], messages[0][3])
238
self.assertEqual(u'Foo Bar2', messages[1][2])
239
self.assertEqual([u'NOTE2: A translation comment for tag2'], messages[1][3])
241
def test_two_succeeding_comments(self):
247
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
248
self.assertEqual(u'Foo Bar', messages[0][2])
249
self.assertEqual([u'NOTE: one', u'NOTE: two'], messages[0][3])
251
def test_invalid_translator_comments(self):
253
# NOTE: this shouldn't apply to any messages
258
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
259
self.assertEqual(u'Foo Bar', messages[0][2])
260
self.assertEqual([], messages[0][3])
262
def test_invalid_translator_comments2(self):
265
hithere = _('Hi there!')
267
# NOTE: you should not be seeing this in the .po
268
rows = [[v for v in range(0,10)] for row in range(0,10)]
270
# this (NOTE:) should not show up either
273
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
274
self.assertEqual(u'Hi there!', messages[0][2])
275
self.assertEqual([u'NOTE: Hi!'], messages[0][3])
276
self.assertEqual(u'Hello', messages[1][2])
277
self.assertEqual([], messages[1][3])
279
def test_invalid_translator_comments3(self):
284
hithere = _('Hi there!')
286
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
287
self.assertEqual(u'Hi there!', messages[0][2])
288
self.assertEqual([], messages[0][3])
290
def test_comment_tag_with_leading_space(self):
292
#: A translation comment
293
#: with leading spaces
296
messages = list(extract.extract_python(buf, ('_',), [':'], {}))
297
self.assertEqual(u'Foo Bar', messages[0][2])
298
self.assertEqual([u': A translation comment', u': with leading spaces'],
301
def test_different_signatures(self):
303
foo = _('foo', 'bar')
304
n = ngettext('hello', 'there', n=3)
305
n = ngettext(n=3, 'hello', 'there')
306
n = ngettext(n=3, *messages)
310
messages = list(extract.extract_python(buf, ('_', 'ngettext'), [], {}))
311
self.assertEqual((u'foo', u'bar'), messages[0][2])
312
self.assertEqual((u'hello', u'there', None), messages[1][2])
313
self.assertEqual((None, u'hello', u'there'), messages[2][2])
314
self.assertEqual((None, None), messages[3][2])
315
self.assertEqual(None, messages[4][2])
316
self.assertEqual(('foo'), messages[5][2])
318
def test_utf8_message(self):
321
msg = _('Bonjour à tous')
323
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'],
324
{'encoding': 'utf-8'}))
325
self.assertEqual(u'Bonjour à tous', messages[0][2])
326
self.assertEqual([u'NOTE: hello'], messages[0][3])
328
def test_utf8_message_with_magic_comment(self):
329
buf = BytesIO(u"""# -*- coding: utf-8 -*-
331
msg = _('Bonjour à tous')
333
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
334
self.assertEqual(u'Bonjour à tous', messages[0][2])
335
self.assertEqual([u'NOTE: hello'], messages[0][3])
337
def test_utf8_message_with_utf8_bom(self):
338
buf = BytesIO(codecs.BOM_UTF8 + u"""
340
msg = _('Bonjour à tous')
342
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
343
self.assertEqual(u'Bonjour à tous', messages[0][2])
344
self.assertEqual([u'NOTE: hello'], messages[0][3])
346
def test_utf8_raw_strings_match_unicode_strings(self):
347
buf = BytesIO(codecs.BOM_UTF8 + u"""
348
msg = _('Bonjour à tous')
349
msgu = _(u'Bonjour à tous')
351
messages = list(extract.extract_python(buf, ('_',), ['NOTE:'], {}))
352
self.assertEqual(u'Bonjour à tous', messages[0][2])
353
self.assertEqual(messages[0][2], messages[1][2])
355
def test_extract_strip_comment_tags(self):
357
#: This is a comment with a very simple
361
# NOTE: This is a multiline comment with
364
messages = list(extract.extract('python', buf, comment_tags=['NOTE:', ':'],
365
strip_comment_tags=True))
366
self.assertEqual(u'Servus', messages[0][1])
367
self.assertEqual([u'This is a comment with a very simple',
368
u'prefix specified'], messages[0][2])
369
self.assertEqual(u'Babatschi', messages[1][1])
370
self.assertEqual([u'This is a multiline comment with',
371
u'a prefix too'], messages[1][2])
374
class ExtractJavaScriptTestCase(unittest.TestCase):
376
def test_simple_extract(self):
379
msg2 = gettext('simple')
380
msg3 = ngettext('s', 'p', 42)
383
list(extract.extract('javascript', buf, extract.DEFAULT_KEYWORDS,
386
self.assertEqual([(1, 'simple', [], None),
387
(2, 'simple', [], None),
388
(3, ('s', 'p'), [], None)], messages)
390
def test_various_calls(self):
392
msg1 = _(i18n_arg.replace(/"/, '"'))
393
msg2 = ungettext(i18n_arg.replace(/"/, '"'), multi_arg.replace(/"/, '"'), 2)
394
msg3 = ungettext("Babel", multi_arg.replace(/"/, '"'), 2)
395
msg4 = ungettext(i18n_arg.replace(/"/, '"'), "Babels", 2)
396
msg5 = ungettext('bunny', 'bunnies', parseInt(Math.random() * 2 + 1))
397
msg6 = ungettext(arg0, 'bunnies', rparseInt(Math.random() * 2 + 1))
398
msg7 = _(hello.there)
399
msg8 = gettext('Rabbit')
400
msg9 = dgettext('wiki', model.addPage())
401
msg10 = dngettext(domain, 'Page', 'Pages', 3)
404
list(extract.extract('javascript', buf, extract.DEFAULT_KEYWORDS, [],
406
self.assertEqual([(5, (u'bunny', u'bunnies'), [], None),
407
(8, u'Rabbit', [], None),
408
(10, (u'Page', u'Pages'), [], None)], messages)
410
def test_message_with_line_comment(self):
413
msg = _('Bonjour à tous')
415
messages = list(extract.extract_javascript(buf, ('_',), ['NOTE:'], {}))
416
self.assertEqual(u'Bonjour à tous', messages[0][2])
417
self.assertEqual([u'NOTE: hello'], messages[0][3])
419
def test_message_with_multiline_comment(self):
424
msg = _('Bonjour à tous')
426
messages = list(extract.extract_javascript(buf, ('_',), ['NOTE:'], {}))
427
self.assertEqual(u'Bonjour à tous', messages[0][2])
428
self.assertEqual([u'NOTE: hello', 'and bonjour', ' and servus'], messages[0][3])
430
def test_ignore_function_definitions(self):
432
function gettext(value) {
433
return translations[language][value] || value;
436
messages = list(extract.extract_javascript(buf, ('gettext',), [], {}))
437
self.assertEqual(messages, [])
439
def test_misplaced_comments(self):
441
/* NOTE: this won't show up */
444
/* NOTE: this will */
447
// NOTE: this will show up
449
msg = _('Something else')
451
// NOTE: but this won't
456
messages = list(extract.extract_javascript(buf, ('_',), ['NOTE:'], {}))
457
self.assertEqual(u'Something', messages[0][2])
458
self.assertEqual([u'NOTE: this will'], messages[0][3])
459
self.assertEqual(u'Something else', messages[1][2])
460
self.assertEqual([u'NOTE: this will show up', 'too.'], messages[1][3])
461
self.assertEqual(u'no comment here', messages[2][2])
462
self.assertEqual([], messages[2][3])
465
class ExtractTestCase(unittest.TestCase):
467
def test_invalid_filter(self):
469
msg1 = _(i18n_arg.replace(r'\"', '"'))
470
msg2 = ungettext(i18n_arg.replace(r'\"', '"'), multi_arg.replace(r'\"', '"'), 2)
471
msg3 = ungettext("Babel", multi_arg.replace(r'\"', '"'), 2)
472
msg4 = ungettext(i18n_arg.replace(r'\"', '"'), "Babels", 2)
473
msg5 = ungettext('bunny', 'bunnies', random.randint(1, 2))
474
msg6 = ungettext(arg0, 'bunnies', random.randint(1, 2))
475
msg7 = _(hello.there)
476
msg8 = gettext('Rabbit')
477
msg9 = dgettext('wiki', model.addPage())
478
msg10 = dngettext(domain, 'Page', 'Pages', 3)
481
list(extract.extract('python', buf, extract.DEFAULT_KEYWORDS, [],
483
self.assertEqual([(5, (u'bunny', u'bunnies'), [], None),
484
(8, u'Rabbit', [], None),
485
(10, (u'Page', u'Pages'), [], None)], messages)
487
def test_invalid_extract_method(self):
489
self.assertRaises(ValueError, list, extract.extract('spam', buf))
491
def test_different_signatures(self):
493
foo = _('foo', 'bar')
494
n = ngettext('hello', 'there', n=3)
495
n = ngettext(n=3, 'hello', 'there')
496
n = ngettext(n=3, *messages)
501
list(extract.extract('python', buf, extract.DEFAULT_KEYWORDS, [],
503
self.assertEqual(len(messages), 2)
504
self.assertEqual(u'foo', messages[0][1])
505
self.assertEqual((u'hello', u'there'), messages[1][1])
507
def test_empty_string_msgid(self):
512
sys.stderr = StringIO()
515
list(extract.extract('python', buf, extract.DEFAULT_KEYWORDS,
517
self.assertEqual([], messages)
518
assert 'warning: Empty msgid.' in sys.stderr.getvalue()
522
def test_warn_if_empty_string_msgid_found_in_context_aware_extraction_method(self):
523
buf = BytesIO(b"\nmsg = pgettext('ctxt', '')\n")
525
sys.stderr = StringIO()
527
messages = extract.extract('python', buf)
528
self.assertEqual([], list(messages))
529
assert 'warning: Empty msgid.' in sys.stderr.getvalue()