cmlenz@263: # -*- coding: utf-8 -*- cmlenz@263: # cmlenz@263: # Copyright (C) 2007 Edgewall Software cmlenz@263: # All rights reserved. cmlenz@263: # cmlenz@263: # This software is licensed as described in the file COPYING, which cmlenz@263: # you should have received as part of this distribution. The terms cmlenz@263: # are also available at http://babel.edgewall.org/wiki/License. cmlenz@263: # cmlenz@263: # This software consists of voluntary contributions made by many cmlenz@263: # individuals. For the exact contribution history, see the revision cmlenz@263: # history and logs, available at http://babel.edgewall.org/log/. cmlenz@263: cmlenz@263: from datetime import datetime cmlenz@263: from distutils.dist import Distribution cmlenz@381: from distutils.errors import DistutilsOptionError cmlenz@263: from distutils.log import _global_log cmlenz@263: import doctest fschwarz@526: import logging cmlenz@263: import os cmlenz@263: import shutil cmlenz@263: from StringIO import StringIO cmlenz@263: import sys cmlenz@263: import time cmlenz@263: import unittest cmlenz@263: cmlenz@263: from babel import __version__ as VERSION cmlenz@263: from babel.dates import format_datetime cmlenz@263: from babel.messages import frontend cmlenz@263: from babel.util import LOCALTZ cmlenz@263: cmlenz@263: cmlenz@263: class CompileCatalogTestCase(unittest.TestCase): cmlenz@263: cmlenz@263: def setUp(self): cmlenz@263: self.olddir = os.getcwd() cmlenz@263: self.datadir = os.path.join(os.path.dirname(__file__), 'data') cmlenz@263: os.chdir(self.datadir) cmlenz@263: _global_log.threshold = 5 # shut up distutils logging cmlenz@263: cmlenz@263: self.dist = Distribution(dict( cmlenz@263: name='TestProject', cmlenz@263: version='0.1', cmlenz@263: packages=['project'] cmlenz@263: )) cmlenz@263: self.cmd = frontend.compile_catalog(self.dist) cmlenz@263: self.cmd.initialize_options() cmlenz@263: cmlenz@263: def tearDown(self): cmlenz@263: os.chdir(self.olddir) cmlenz@263: cmlenz@263: def test_no_directory_or_output_file_specified(self): cmlenz@263: self.cmd.locale = 'en_US' cmlenz@263: self.cmd.input_file = 'dummy' cmlenz@263: self.assertRaises(DistutilsOptionError, self.cmd.finalize_options) cmlenz@263: cmlenz@263: def test_no_directory_or_input_file_specified(self): cmlenz@263: self.cmd.locale = 'en_US' cmlenz@263: self.cmd.output_file = 'dummy' cmlenz@263: self.assertRaises(DistutilsOptionError, self.cmd.finalize_options) cmlenz@263: cmlenz@263: cmlenz@263: class ExtractMessagesTestCase(unittest.TestCase): cmlenz@263: cmlenz@263: def setUp(self): cmlenz@263: self.olddir = os.getcwd() cmlenz@263: self.datadir = os.path.join(os.path.dirname(__file__), 'data') cmlenz@263: os.chdir(self.datadir) cmlenz@263: _global_log.threshold = 5 # shut up distutils logging cmlenz@263: cmlenz@263: self.dist = Distribution(dict( cmlenz@263: name='TestProject', cmlenz@263: version='0.1', cmlenz@263: packages=['project'] cmlenz@263: )) cmlenz@263: self.cmd = frontend.extract_messages(self.dist) cmlenz@263: self.cmd.initialize_options() cmlenz@263: cmlenz@263: def tearDown(self): cmlenz@263: pot_file = os.path.join(self.datadir, 'project', 'i18n', 'temp.pot') cmlenz@263: if os.path.isfile(pot_file): cmlenz@263: os.unlink(pot_file) cmlenz@263: cmlenz@263: os.chdir(self.olddir) cmlenz@263: cmlenz@263: def test_neither_default_nor_custom_keywords(self): cmlenz@263: self.cmd.output_file = 'dummy' cmlenz@263: self.cmd.no_default_keywords = True cmlenz@263: self.assertRaises(DistutilsOptionError, self.cmd.finalize_options) cmlenz@263: cmlenz@263: def test_no_output_file_specified(self): cmlenz@263: self.assertRaises(DistutilsOptionError, self.cmd.finalize_options) cmlenz@263: cmlenz@263: def test_both_sort_output_and_sort_by_file(self): cmlenz@263: self.cmd.output_file = 'dummy' cmlenz@263: self.cmd.sort_output = True cmlenz@263: self.cmd.sort_by_file = True cmlenz@263: self.assertRaises(DistutilsOptionError, self.cmd.finalize_options) cmlenz@263: cmlenz@263: def test_extraction_with_default_mapping(self): cmlenz@263: self.cmd.copyright_holder = 'FooBar, Inc.' cmlenz@263: self.cmd.msgid_bugs_address = 'bugs.address@email.tld' cmlenz@263: self.cmd.output_file = 'project/i18n/temp.pot' cmlenz@263: self.cmd.add_comments = 'TRANSLATOR:,TRANSLATORS:' cmlenz@263: cmlenz@263: self.cmd.finalize_options() cmlenz@263: self.cmd.run() cmlenz@263: cmlenz@263: pot_file = os.path.join(self.datadir, 'project', 'i18n', 'temp.pot') cmlenz@263: assert os.path.isfile(pot_file) cmlenz@263: cmlenz@263: self.assertEqual( cmlenz@263: r"""# Translations template for TestProject. cmlenz@263: # Copyright (C) %(year)s FooBar, Inc. cmlenz@263: # This file is distributed under the same license as the TestProject cmlenz@263: # project. cmlenz@263: # FIRST AUTHOR , %(year)s. cmlenz@263: # cmlenz@263: #, fuzzy cmlenz@263: msgid "" cmlenz@263: msgstr "" cmlenz@263: "Project-Id-Version: TestProject 0.1\n" cmlenz@263: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@263: "POT-Creation-Date: %(date)s\n" cmlenz@263: "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" cmlenz@263: "Last-Translator: FULL NAME \n" cmlenz@263: "Language-Team: LANGUAGE \n" cmlenz@263: "MIME-Version: 1.0\n" cmlenz@263: "Content-Type: text/plain; charset=utf-8\n" cmlenz@263: "Content-Transfer-Encoding: 8bit\n" cmlenz@263: "Generated-By: Babel %(version)s\n" cmlenz@263: cmlenz@348: #. TRANSLATOR: This will be a translator coment, cmlenz@263: #. that will include several lines cmlenz@263: #: project/file1.py:8 cmlenz@263: msgid "bar" cmlenz@263: msgstr "" cmlenz@263: cmlenz@263: #: project/file2.py:9 cmlenz@263: msgid "foobar" cmlenz@263: msgid_plural "foobars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@461: #: project/ignored/this_wont_normally_be_here.py:11 cmlenz@263: msgid "FooBar" cmlenz@263: msgid_plural "FooBars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@263: """ % {'version': VERSION, cmlenz@263: 'year': time.strftime('%Y'), cmlenz@263: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@263: tzinfo=LOCALTZ, locale='en')}, cmlenz@263: open(pot_file, 'U').read()) cmlenz@263: cmlenz@263: def test_extraction_with_mapping_file(self): cmlenz@263: self.cmd.copyright_holder = 'FooBar, Inc.' cmlenz@263: self.cmd.msgid_bugs_address = 'bugs.address@email.tld' cmlenz@263: self.cmd.mapping_file = 'mapping.cfg' cmlenz@263: self.cmd.output_file = 'project/i18n/temp.pot' cmlenz@263: self.cmd.add_comments = 'TRANSLATOR:,TRANSLATORS:' cmlenz@263: cmlenz@263: self.cmd.finalize_options() cmlenz@263: self.cmd.run() cmlenz@263: cmlenz@263: pot_file = os.path.join(self.datadir, 'project', 'i18n', 'temp.pot') cmlenz@263: assert os.path.isfile(pot_file) cmlenz@263: cmlenz@263: self.assertEqual( cmlenz@263: r"""# Translations template for TestProject. cmlenz@263: # Copyright (C) %(year)s FooBar, Inc. cmlenz@263: # This file is distributed under the same license as the TestProject cmlenz@263: # project. cmlenz@263: # FIRST AUTHOR , %(year)s. cmlenz@263: # cmlenz@263: #, fuzzy cmlenz@263: msgid "" cmlenz@263: msgstr "" cmlenz@263: "Project-Id-Version: TestProject 0.1\n" cmlenz@263: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@263: "POT-Creation-Date: %(date)s\n" cmlenz@263: "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" cmlenz@263: "Last-Translator: FULL NAME \n" cmlenz@263: "Language-Team: LANGUAGE \n" cmlenz@263: "MIME-Version: 1.0\n" cmlenz@263: "Content-Type: text/plain; charset=utf-8\n" cmlenz@263: "Content-Transfer-Encoding: 8bit\n" cmlenz@263: "Generated-By: Babel %(version)s\n" cmlenz@263: cmlenz@348: #. TRANSLATOR: This will be a translator coment, cmlenz@263: #. that will include several lines cmlenz@263: #: project/file1.py:8 cmlenz@263: msgid "bar" cmlenz@263: msgstr "" cmlenz@263: cmlenz@263: #: project/file2.py:9 cmlenz@263: msgid "foobar" cmlenz@263: msgid_plural "foobars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@263: """ % {'version': VERSION, cmlenz@263: 'year': time.strftime('%Y'), cmlenz@263: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@263: tzinfo=LOCALTZ, locale='en')}, cmlenz@263: open(pot_file, 'U').read()) cmlenz@263: cmlenz@263: def test_extraction_with_mapping_dict(self): cmlenz@263: self.dist.message_extractors = { cmlenz@263: 'project': [ cmlenz@461: ('**/ignored/**.*', 'ignore', None), cmlenz@461: ('**.py', 'python', None), cmlenz@263: ] cmlenz@263: } cmlenz@263: self.cmd.copyright_holder = 'FooBar, Inc.' cmlenz@263: self.cmd.msgid_bugs_address = 'bugs.address@email.tld' cmlenz@263: self.cmd.output_file = 'project/i18n/temp.pot' cmlenz@263: self.cmd.add_comments = 'TRANSLATOR:,TRANSLATORS:' cmlenz@263: cmlenz@263: self.cmd.finalize_options() cmlenz@263: self.cmd.run() cmlenz@263: cmlenz@263: pot_file = os.path.join(self.datadir, 'project', 'i18n', 'temp.pot') cmlenz@263: assert os.path.isfile(pot_file) cmlenz@263: cmlenz@263: self.assertEqual( cmlenz@263: r"""# Translations template for TestProject. cmlenz@263: # Copyright (C) %(year)s FooBar, Inc. cmlenz@263: # This file is distributed under the same license as the TestProject cmlenz@263: # project. cmlenz@263: # FIRST AUTHOR , %(year)s. cmlenz@263: # cmlenz@263: #, fuzzy cmlenz@263: msgid "" cmlenz@263: msgstr "" cmlenz@263: "Project-Id-Version: TestProject 0.1\n" cmlenz@263: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@263: "POT-Creation-Date: %(date)s\n" cmlenz@263: "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" cmlenz@263: "Last-Translator: FULL NAME \n" cmlenz@263: "Language-Team: LANGUAGE \n" cmlenz@263: "MIME-Version: 1.0\n" cmlenz@263: "Content-Type: text/plain; charset=utf-8\n" cmlenz@263: "Content-Transfer-Encoding: 8bit\n" cmlenz@263: "Generated-By: Babel %(version)s\n" cmlenz@263: cmlenz@348: #. TRANSLATOR: This will be a translator coment, cmlenz@263: #. that will include several lines cmlenz@263: #: project/file1.py:8 cmlenz@263: msgid "bar" cmlenz@263: msgstr "" cmlenz@263: cmlenz@263: #: project/file2.py:9 cmlenz@263: msgid "foobar" cmlenz@263: msgid_plural "foobars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@263: """ % {'version': VERSION, cmlenz@263: 'year': time.strftime('%Y'), cmlenz@263: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@263: tzinfo=LOCALTZ, locale='en')}, cmlenz@263: open(pot_file, 'U').read()) cmlenz@263: cmlenz@263: cmlenz@263: class InitCatalogTestCase(unittest.TestCase): cmlenz@263: cmlenz@263: def setUp(self): cmlenz@263: self.olddir = os.getcwd() cmlenz@263: self.datadir = os.path.join(os.path.dirname(__file__), 'data') cmlenz@263: os.chdir(self.datadir) cmlenz@263: _global_log.threshold = 5 # shut up distutils logging cmlenz@263: cmlenz@263: self.dist = Distribution(dict( cmlenz@263: name='TestProject', cmlenz@263: version='0.1', cmlenz@263: packages=['project'] cmlenz@263: )) cmlenz@263: self.cmd = frontend.init_catalog(self.dist) cmlenz@263: self.cmd.initialize_options() cmlenz@263: cmlenz@263: def tearDown(self): cmlenz@381: for dirname in ['en_US', 'ja_JP', 'lv_LV']: cmlenz@381: locale_dir = os.path.join(self.datadir, 'project', 'i18n', dirname) cmlenz@381: if os.path.isdir(locale_dir): cmlenz@381: shutil.rmtree(locale_dir) cmlenz@263: cmlenz@263: os.chdir(self.olddir) cmlenz@263: cmlenz@263: def test_no_input_file(self): cmlenz@263: self.cmd.locale = 'en_US' cmlenz@263: self.cmd.output_file = 'dummy' cmlenz@263: self.assertRaises(DistutilsOptionError, self.cmd.finalize_options) cmlenz@263: cmlenz@263: def test_no_locale(self): cmlenz@263: self.cmd.input_file = 'dummy' cmlenz@263: self.cmd.output_file = 'dummy' cmlenz@263: self.assertRaises(DistutilsOptionError, self.cmd.finalize_options) cmlenz@263: cmlenz@263: def test_with_output_dir(self): cmlenz@263: self.cmd.input_file = 'project/i18n/messages.pot' cmlenz@263: self.cmd.locale = 'en_US' cmlenz@263: self.cmd.output_dir = 'project/i18n' cmlenz@263: cmlenz@263: self.cmd.finalize_options() cmlenz@263: self.cmd.run() cmlenz@263: cmlenz@263: po_file = os.path.join(self.datadir, 'project', 'i18n', 'en_US', cmlenz@263: 'LC_MESSAGES', 'messages.po') cmlenz@263: assert os.path.isfile(po_file) cmlenz@263: cmlenz@263: self.assertEqual( cmlenz@263: r"""# English (United States) translations for TestProject. cmlenz@263: # Copyright (C) 2007 FooBar, Inc. cmlenz@263: # This file is distributed under the same license as the TestProject cmlenz@263: # project. cmlenz@263: # FIRST AUTHOR , 2007. cmlenz@263: # cmlenz@263: msgid "" cmlenz@263: msgstr "" cmlenz@263: "Project-Id-Version: TestProject 0.1\n" cmlenz@263: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@263: "POT-Creation-Date: 2007-04-01 15:30+0200\n" cmlenz@263: "PO-Revision-Date: %(date)s\n" cmlenz@263: "Last-Translator: FULL NAME \n" cmlenz@263: "Language-Team: en_US \n" cmlenz@263: "Plural-Forms: nplurals=2; plural=(n != 1)\n" cmlenz@263: "MIME-Version: 1.0\n" cmlenz@263: "Content-Type: text/plain; charset=utf-8\n" cmlenz@263: "Content-Transfer-Encoding: 8bit\n" cmlenz@263: "Generated-By: Babel %(version)s\n" cmlenz@263: cmlenz@263: #. This will be a translator coment, cmlenz@263: #. that will include several lines cmlenz@263: #: project/file1.py:8 cmlenz@263: msgid "bar" cmlenz@263: msgstr "" cmlenz@263: cmlenz@263: #: project/file2.py:9 cmlenz@263: msgid "foobar" cmlenz@263: msgid_plural "foobars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@263: """ % {'version': VERSION, cmlenz@263: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@263: tzinfo=LOCALTZ, locale='en')}, cmlenz@263: open(po_file, 'U').read()) cmlenz@263: cmlenz@381: def test_keeps_catalog_non_fuzzy(self): cmlenz@263: self.cmd.input_file = 'project/i18n/messages_non_fuzzy.pot' cmlenz@263: self.cmd.locale = 'en_US' cmlenz@263: self.cmd.output_dir = 'project/i18n' cmlenz@263: cmlenz@263: self.cmd.finalize_options() cmlenz@263: self.cmd.run() cmlenz@263: cmlenz@263: po_file = os.path.join(self.datadir, 'project', 'i18n', 'en_US', cmlenz@263: 'LC_MESSAGES', 'messages.po') cmlenz@263: assert os.path.isfile(po_file) cmlenz@263: cmlenz@263: self.assertEqual( cmlenz@263: r"""# English (United States) translations for TestProject. cmlenz@263: # Copyright (C) 2007 FooBar, Inc. cmlenz@263: # This file is distributed under the same license as the TestProject cmlenz@263: # project. cmlenz@263: # FIRST AUTHOR , 2007. cmlenz@263: # cmlenz@263: msgid "" cmlenz@263: msgstr "" cmlenz@263: "Project-Id-Version: TestProject 0.1\n" cmlenz@263: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@263: "POT-Creation-Date: 2007-04-01 15:30+0200\n" cmlenz@263: "PO-Revision-Date: %(date)s\n" cmlenz@263: "Last-Translator: FULL NAME \n" cmlenz@263: "Language-Team: en_US \n" cmlenz@263: "Plural-Forms: nplurals=2; plural=(n != 1)\n" cmlenz@263: "MIME-Version: 1.0\n" cmlenz@263: "Content-Type: text/plain; charset=utf-8\n" cmlenz@263: "Content-Transfer-Encoding: 8bit\n" cmlenz@263: "Generated-By: Babel %(version)s\n" cmlenz@263: cmlenz@263: #. This will be a translator coment, cmlenz@263: #. that will include several lines cmlenz@263: #: project/file1.py:8 cmlenz@263: msgid "bar" cmlenz@263: msgstr "" cmlenz@263: cmlenz@263: #: project/file2.py:9 cmlenz@263: msgid "foobar" cmlenz@263: msgid_plural "foobars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@263: """ % {'version': VERSION, cmlenz@263: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@263: tzinfo=LOCALTZ, locale='en')}, cmlenz@263: open(po_file, 'U').read()) cmlenz@263: cmlenz@381: def test_correct_init_more_than_2_plurals(self): cmlenz@381: self.cmd.input_file = 'project/i18n/messages.pot' cmlenz@381: self.cmd.locale = 'lv_LV' cmlenz@381: self.cmd.output_dir = 'project/i18n' cmlenz@381: cmlenz@381: self.cmd.finalize_options() cmlenz@381: self.cmd.run() cmlenz@381: cmlenz@381: po_file = os.path.join(self.datadir, 'project', 'i18n', 'lv_LV', cmlenz@381: 'LC_MESSAGES', 'messages.po') cmlenz@381: assert os.path.isfile(po_file) cmlenz@381: cmlenz@381: self.assertEqual( cmlenz@381: r"""# Latvian (Latvia) translations for TestProject. cmlenz@381: # Copyright (C) 2007 FooBar, Inc. cmlenz@381: # This file is distributed under the same license as the TestProject cmlenz@381: # project. cmlenz@381: # FIRST AUTHOR , 2007. cmlenz@381: # cmlenz@381: msgid "" cmlenz@381: msgstr "" cmlenz@381: "Project-Id-Version: TestProject 0.1\n" cmlenz@381: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@381: "POT-Creation-Date: 2007-04-01 15:30+0200\n" cmlenz@381: "PO-Revision-Date: %(date)s\n" cmlenz@381: "Last-Translator: FULL NAME \n" cmlenz@381: "Language-Team: lv_LV \n" cmlenz@381: "Plural-Forms: nplurals=3; plural=(n%%10==1 && n%%100!=11 ? 0 : n != 0 ? 1 :" cmlenz@381: " 2)\n" cmlenz@381: "MIME-Version: 1.0\n" cmlenz@381: "Content-Type: text/plain; charset=utf-8\n" cmlenz@381: "Content-Transfer-Encoding: 8bit\n" cmlenz@381: "Generated-By: Babel %(version)s\n" cmlenz@381: cmlenz@381: #. This will be a translator coment, cmlenz@381: #. that will include several lines cmlenz@381: #: project/file1.py:8 cmlenz@381: msgid "bar" cmlenz@381: msgstr "" cmlenz@381: cmlenz@381: #: project/file2.py:9 cmlenz@381: msgid "foobar" cmlenz@381: msgid_plural "foobars" cmlenz@381: msgstr[0] "" cmlenz@381: msgstr[1] "" cmlenz@381: msgstr[2] "" cmlenz@381: cmlenz@381: """ % {'version': VERSION, cmlenz@381: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@381: tzinfo=LOCALTZ, locale='en')}, cmlenz@381: open(po_file, 'U').read()) cmlenz@381: cmlenz@381: def test_correct_init_singular_plural_forms(self): cmlenz@381: self.cmd.input_file = 'project/i18n/messages.pot' cmlenz@381: self.cmd.locale = 'ja_JP' cmlenz@381: self.cmd.output_dir = 'project/i18n' cmlenz@381: cmlenz@381: self.cmd.finalize_options() cmlenz@381: self.cmd.run() cmlenz@381: cmlenz@381: po_file = os.path.join(self.datadir, 'project', 'i18n', 'ja_JP', cmlenz@381: 'LC_MESSAGES', 'messages.po') cmlenz@381: assert os.path.isfile(po_file) cmlenz@381: cmlenz@381: self.assertEqual( cmlenz@381: r"""# Japanese (Japan) translations for TestProject. cmlenz@381: # Copyright (C) 2007 FooBar, Inc. cmlenz@381: # This file is distributed under the same license as the TestProject cmlenz@381: # project. cmlenz@381: # FIRST AUTHOR , 2007. cmlenz@381: # cmlenz@381: msgid "" cmlenz@381: msgstr "" cmlenz@381: "Project-Id-Version: TestProject 0.1\n" cmlenz@381: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@381: "POT-Creation-Date: 2007-04-01 15:30+0200\n" cmlenz@381: "PO-Revision-Date: %(date)s\n" cmlenz@381: "Last-Translator: FULL NAME \n" cmlenz@381: "Language-Team: ja_JP \n" cmlenz@381: "Plural-Forms: nplurals=1; plural=0\n" cmlenz@381: "MIME-Version: 1.0\n" cmlenz@381: "Content-Type: text/plain; charset=utf-8\n" cmlenz@381: "Content-Transfer-Encoding: 8bit\n" cmlenz@381: "Generated-By: Babel %(version)s\n" cmlenz@381: cmlenz@381: #. This will be a translator coment, cmlenz@381: #. that will include several lines cmlenz@381: #: project/file1.py:8 cmlenz@381: msgid "bar" cmlenz@381: msgstr "" cmlenz@381: cmlenz@381: #: project/file2.py:9 cmlenz@381: msgid "foobar" cmlenz@381: msgid_plural "foobars" cmlenz@381: msgstr[0] "" cmlenz@381: cmlenz@381: """ % {'version': VERSION, cmlenz@381: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@381: tzinfo=LOCALTZ, locale='ja_JP')}, cmlenz@381: open(po_file, 'U').read()) cmlenz@381: cmlenz@263: cmlenz@263: class CommandLineInterfaceTestCase(unittest.TestCase): cmlenz@263: cmlenz@263: def setUp(self): cmlenz@263: self.datadir = os.path.join(os.path.dirname(__file__), 'data') fschwarz@544: self.orig_working_dir = os.getcwd() cmlenz@263: self.orig_argv = sys.argv cmlenz@263: self.orig_stdout = sys.stdout cmlenz@263: self.orig_stderr = sys.stderr cmlenz@263: sys.argv = ['pybabel'] cmlenz@263: sys.stdout = StringIO() cmlenz@263: sys.stderr = StringIO() fschwarz@544: os.chdir(self.datadir) fschwarz@526: fschwarz@526: # Logging handlers will be reused if possible (#227). This breaks the fschwarz@526: # implicit assumption that our newly created StringIO for sys.stderr fschwarz@526: # contains the console output. Removing the old handler ensures that a fschwarz@526: # new handler with our new StringIO instance will be used. fschwarz@526: log = logging.getLogger('babel') fschwarz@526: for handler in log.handlers: fschwarz@526: log.removeHandler(handler) cmlenz@263: self.cli = frontend.CommandLineInterface() cmlenz@263: cmlenz@263: def tearDown(self): fschwarz@544: os.chdir(self.orig_working_dir) cmlenz@263: sys.argv = self.orig_argv cmlenz@263: sys.stdout = self.orig_stdout cmlenz@263: sys.stderr = self.orig_stderr cmlenz@381: for dirname in ['lv_LV', 'ja_JP']: cmlenz@381: locale_dir = os.path.join(self.datadir, 'project', 'i18n', dirname) cmlenz@381: if os.path.isdir(locale_dir): cmlenz@381: shutil.rmtree(locale_dir) cmlenz@263: cmlenz@263: def test_usage(self): cmlenz@263: try: cmlenz@263: self.cli.run(sys.argv) cmlenz@263: self.fail('Expected SystemExit') cmlenz@263: except SystemExit, e: fschwarz@510: stderr = sys.stderr.getvalue() fschwarz@510: if isinstance(e.code, int): fschwarz@510: self.assertEqual(2, e.code) fschwarz@510: else: fschwarz@510: # OptionParser in Python 2.3 does not set the exit code. fschwarz@510: # Instead the 'code' contains the custom error message from the fschwarz@510: # frontend fschwarz@510: stderr = stderr + e.code + '\n' cmlenz@263: self.assertEqual("""\ cmlenz@263: usage: pybabel command [options] [args] cmlenz@263: jruigrok@476: pybabel: error: no valid command or option passed. try the -h/--help option for more information. fschwarz@510: """, stderr.lower()) cmlenz@263: fschwarz@542: def _run_init_catalog(self): fschwarz@542: i18n_dir = os.path.join(self.datadir, 'project', 'i18n') fschwarz@542: pot_path = os.path.join(self.datadir, 'project', 'i18n', 'messages.pot') fschwarz@542: init_argv = sys.argv + ['init', '--locale', 'en_US', '-d', i18n_dir, fschwarz@542: '-i', pot_path] fschwarz@542: self.cli.run(init_argv) fschwarz@542: fschwarz@542: def test_no_duplicated_output_for_multiple_runs(self): fschwarz@542: self._run_init_catalog() fschwarz@542: first_output = sys.stderr.getvalue() fschwarz@542: self._run_init_catalog() fschwarz@542: second_output = sys.stderr.getvalue()[len(first_output):] fschwarz@542: fschwarz@542: # in case the log message is not duplicated we should get the same fschwarz@542: # output as before fschwarz@542: self.assertEqual(first_output, second_output) fschwarz@542: fschwarz@542: def test_frontend_can_log_to_predefined_handler(self): fschwarz@542: custom_stream = StringIO() fschwarz@542: log = logging.getLogger('babel') fschwarz@542: log.addHandler(logging.StreamHandler(custom_stream)) fschwarz@542: fschwarz@542: self._run_init_catalog() fschwarz@542: self.assertNotEqual(id(sys.stderr), id(custom_stream)) fschwarz@542: self.assertEqual('', sys.stderr.getvalue()) fschwarz@542: assert len(custom_stream.getvalue()) > 0 fschwarz@542: cmlenz@263: def test_help(self): cmlenz@263: try: cmlenz@263: self.cli.run(sys.argv + ['--help']) cmlenz@263: self.fail('Expected SystemExit') cmlenz@263: except SystemExit, e: cmlenz@263: self.assertEqual(0, e.code) cmlenz@263: self.assertEqual("""\ cmlenz@263: usage: pybabel command [options] [args] cmlenz@263: cmlenz@263: options: cmlenz@263: --version show program's version number and exit cmlenz@263: -h, --help show this help message and exit cmlenz@263: --list-locales print all known locales and exit cmlenz@263: -v, --verbose print as much as possible cmlenz@263: -q, --quiet print as little as possible cmlenz@263: cmlenz@263: commands: cmlenz@263: compile compile message catalogs to mo files cmlenz@263: extract extract messages from source files and generate a pot file cmlenz@263: init create new message catalogs from a pot file cmlenz@263: update update existing message catalogs from a pot file cmlenz@263: """, sys.stdout.getvalue().lower()) cmlenz@263: cmlenz@263: def test_extract_with_default_mapping(self): cmlenz@263: pot_file = os.path.join(self.datadir, 'project', 'i18n', 'temp.pot') fschwarz@544: self.cli.run(sys.argv + ['extract', fschwarz@544: '--copyright-holder', 'FooBar, Inc.', fschwarz@544: '--project', 'TestProject', '--version', '0.1', fschwarz@544: '--msgid-bugs-address', 'bugs.address@email.tld', fschwarz@544: '-c', 'TRANSLATOR', '-c', 'TRANSLATORS:', fschwarz@544: '-o', pot_file, 'project']) fschwarz@544: assert os.path.isfile(pot_file) fschwarz@544: self.assertEqual( cmlenz@263: r"""# Translations template for TestProject. cmlenz@263: # Copyright (C) %(year)s FooBar, Inc. cmlenz@263: # This file is distributed under the same license as the TestProject cmlenz@263: # project. cmlenz@263: # FIRST AUTHOR , %(year)s. cmlenz@263: # cmlenz@263: #, fuzzy cmlenz@263: msgid "" cmlenz@263: msgstr "" cmlenz@263: "Project-Id-Version: TestProject 0.1\n" cmlenz@263: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@263: "POT-Creation-Date: %(date)s\n" cmlenz@263: "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" cmlenz@263: "Last-Translator: FULL NAME \n" cmlenz@263: "Language-Team: LANGUAGE \n" cmlenz@263: "MIME-Version: 1.0\n" cmlenz@263: "Content-Type: text/plain; charset=utf-8\n" cmlenz@263: "Content-Transfer-Encoding: 8bit\n" cmlenz@263: "Generated-By: Babel %(version)s\n" cmlenz@263: fschwarz@544: #. TRANSLATOR: This will be a translator coment, cmlenz@263: #. that will include several lines cmlenz@263: #: project/file1.py:8 cmlenz@263: msgid "bar" cmlenz@263: msgstr "" cmlenz@263: cmlenz@263: #: project/file2.py:9 cmlenz@263: msgid "foobar" cmlenz@263: msgid_plural "foobars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@461: #: project/ignored/this_wont_normally_be_here.py:11 cmlenz@263: msgid "FooBar" cmlenz@263: msgid_plural "FooBars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@263: """ % {'version': VERSION, cmlenz@263: 'year': time.strftime('%Y'), cmlenz@263: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@263: tzinfo=LOCALTZ, locale='en')}, cmlenz@263: open(pot_file, 'U').read()) cmlenz@263: cmlenz@263: def test_extract_with_mapping_file(self): cmlenz@263: pot_file = os.path.join(self.datadir, 'project', 'i18n', 'temp.pot') fschwarz@544: self.cli.run(sys.argv + ['extract', fschwarz@544: '--copyright-holder', 'FooBar, Inc.', fschwarz@544: '--project', 'TestProject', '--version', '0.1', fschwarz@544: '--msgid-bugs-address', 'bugs.address@email.tld', fschwarz@544: '--mapping', os.path.join(self.datadir, 'mapping.cfg'), fschwarz@544: '-c', 'TRANSLATOR', '-c', 'TRANSLATORS:', fschwarz@544: '-o', pot_file, 'project']) fschwarz@544: assert os.path.isfile(pot_file) fschwarz@544: self.assertEqual( cmlenz@263: r"""# Translations template for TestProject. cmlenz@263: # Copyright (C) %(year)s FooBar, Inc. cmlenz@263: # This file is distributed under the same license as the TestProject cmlenz@263: # project. cmlenz@263: # FIRST AUTHOR , %(year)s. cmlenz@263: # cmlenz@263: #, fuzzy cmlenz@263: msgid "" cmlenz@263: msgstr "" cmlenz@263: "Project-Id-Version: TestProject 0.1\n" cmlenz@263: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@263: "POT-Creation-Date: %(date)s\n" cmlenz@263: "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" cmlenz@263: "Last-Translator: FULL NAME \n" cmlenz@263: "Language-Team: LANGUAGE \n" cmlenz@263: "MIME-Version: 1.0\n" cmlenz@263: "Content-Type: text/plain; charset=utf-8\n" cmlenz@263: "Content-Transfer-Encoding: 8bit\n" cmlenz@263: "Generated-By: Babel %(version)s\n" cmlenz@263: fschwarz@544: #. TRANSLATOR: This will be a translator coment, cmlenz@263: #. that will include several lines cmlenz@263: #: project/file1.py:8 cmlenz@263: msgid "bar" cmlenz@263: msgstr "" cmlenz@263: cmlenz@263: #: project/file2.py:9 cmlenz@263: msgid "foobar" cmlenz@263: msgid_plural "foobars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@263: """ % {'version': VERSION, cmlenz@263: 'year': time.strftime('%Y'), cmlenz@263: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@263: tzinfo=LOCALTZ, locale='en')}, cmlenz@263: open(pot_file, 'U').read()) cmlenz@263: cmlenz@263: def test_init_with_output_dir(self): cmlenz@263: po_file = os.path.join(self.datadir, 'project', 'i18n', 'en_US', cmlenz@263: 'LC_MESSAGES', 'messages.po') fschwarz@544: self.cli.run(sys.argv + ['init', fschwarz@544: '--locale', 'en_US', fschwarz@544: '-d', os.path.join(self.datadir, 'project', 'i18n'), fschwarz@544: '-i', os.path.join(self.datadir, 'project', 'i18n', 'messages.pot')]) fschwarz@544: assert os.path.isfile(po_file) fschwarz@544: self.assertEqual( cmlenz@263: r"""# English (United States) translations for TestProject. cmlenz@263: # Copyright (C) 2007 FooBar, Inc. cmlenz@263: # This file is distributed under the same license as the TestProject cmlenz@263: # project. cmlenz@263: # FIRST AUTHOR , 2007. cmlenz@263: # cmlenz@263: #, fuzzy cmlenz@263: msgid "" cmlenz@263: msgstr "" cmlenz@263: "Project-Id-Version: TestProject 0.1\n" cmlenz@263: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@263: "POT-Creation-Date: 2007-04-01 15:30+0200\n" cmlenz@263: "PO-Revision-Date: %(date)s\n" cmlenz@263: "Last-Translator: FULL NAME \n" cmlenz@263: "Language-Team: en_US \n" cmlenz@263: "Plural-Forms: nplurals=2; plural=(n != 1)\n" cmlenz@263: "MIME-Version: 1.0\n" cmlenz@263: "Content-Type: text/plain; charset=utf-8\n" cmlenz@263: "Content-Transfer-Encoding: 8bit\n" cmlenz@263: "Generated-By: Babel %(version)s\n" cmlenz@263: cmlenz@263: #. This will be a translator coment, cmlenz@263: #. that will include several lines cmlenz@263: #: project/file1.py:8 cmlenz@263: msgid "bar" cmlenz@263: msgstr "" cmlenz@263: cmlenz@263: #: project/file2.py:9 cmlenz@263: msgid "foobar" cmlenz@263: msgid_plural "foobars" cmlenz@263: msgstr[0] "" cmlenz@263: msgstr[1] "" cmlenz@263: cmlenz@263: """ % {'version': VERSION, cmlenz@263: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@263: tzinfo=LOCALTZ, locale='en')}, cmlenz@263: open(po_file, 'U').read()) cmlenz@381: cmlenz@381: def test_init_singular_plural_forms(self): cmlenz@381: po_file = os.path.join(self.datadir, 'project', 'i18n', 'ja_JP', cmlenz@381: 'LC_MESSAGES', 'messages.po') fschwarz@544: self.cli.run(sys.argv + ['init', fschwarz@544: '--locale', 'ja_JP', fschwarz@544: '-d', os.path.join(self.datadir, 'project', 'i18n'), fschwarz@544: '-i', os.path.join(self.datadir, 'project', 'i18n', fschwarz@544: 'messages.pot')]) cmlenz@381: assert os.path.isfile(po_file) cmlenz@381: self.assertEqual( cmlenz@381: r"""# Japanese (Japan) translations for TestProject. cmlenz@381: # Copyright (C) 2007 FooBar, Inc. cmlenz@381: # This file is distributed under the same license as the TestProject cmlenz@381: # project. cmlenz@381: # FIRST AUTHOR , 2007. cmlenz@381: # cmlenz@381: #, fuzzy cmlenz@381: msgid "" cmlenz@381: msgstr "" cmlenz@381: "Project-Id-Version: TestProject 0.1\n" cmlenz@381: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@381: "POT-Creation-Date: 2007-04-01 15:30+0200\n" cmlenz@381: "PO-Revision-Date: %(date)s\n" cmlenz@381: "Last-Translator: FULL NAME \n" cmlenz@381: "Language-Team: ja_JP \n" cmlenz@381: "Plural-Forms: nplurals=1; plural=0\n" cmlenz@381: "MIME-Version: 1.0\n" cmlenz@381: "Content-Type: text/plain; charset=utf-8\n" cmlenz@381: "Content-Transfer-Encoding: 8bit\n" cmlenz@381: "Generated-By: Babel %(version)s\n" cmlenz@381: cmlenz@381: #. This will be a translator coment, cmlenz@381: #. that will include several lines cmlenz@381: #: project/file1.py:8 cmlenz@381: msgid "bar" cmlenz@381: msgstr "" cmlenz@381: cmlenz@381: #: project/file2.py:9 cmlenz@381: msgid "foobar" cmlenz@381: msgid_plural "foobars" cmlenz@381: msgstr[0] "" cmlenz@381: cmlenz@381: """ % {'version': VERSION, cmlenz@381: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@381: tzinfo=LOCALTZ, locale='en')}, cmlenz@381: open(po_file, 'U').read()) cmlenz@381: cmlenz@381: def test_init_more_than_2_plural_forms(self): cmlenz@381: po_file = os.path.join(self.datadir, 'project', 'i18n', 'lv_LV', cmlenz@381: 'LC_MESSAGES', 'messages.po') fschwarz@544: self.cli.run(sys.argv + ['init', fschwarz@544: '--locale', 'lv_LV', fschwarz@544: '-d', os.path.join(self.datadir, 'project', 'i18n'), fschwarz@544: '-i', os.path.join(self.datadir, 'project', 'i18n', fschwarz@544: 'messages.pot')]) cmlenz@381: assert os.path.isfile(po_file) cmlenz@381: self.assertEqual( cmlenz@381: r"""# Latvian (Latvia) translations for TestProject. cmlenz@381: # Copyright (C) 2007 FooBar, Inc. cmlenz@381: # This file is distributed under the same license as the TestProject cmlenz@381: # project. cmlenz@381: # FIRST AUTHOR , 2007. cmlenz@381: # cmlenz@381: #, fuzzy cmlenz@381: msgid "" cmlenz@381: msgstr "" cmlenz@381: "Project-Id-Version: TestProject 0.1\n" cmlenz@381: "Report-Msgid-Bugs-To: bugs.address@email.tld\n" cmlenz@381: "POT-Creation-Date: 2007-04-01 15:30+0200\n" cmlenz@381: "PO-Revision-Date: %(date)s\n" cmlenz@381: "Last-Translator: FULL NAME \n" cmlenz@381: "Language-Team: lv_LV \n" cmlenz@381: "Plural-Forms: nplurals=3; plural=(n%%10==1 && n%%100!=11 ? 0 : n != 0 ? 1 :" cmlenz@381: " 2)\n" cmlenz@381: "MIME-Version: 1.0\n" cmlenz@381: "Content-Type: text/plain; charset=utf-8\n" cmlenz@381: "Content-Transfer-Encoding: 8bit\n" cmlenz@381: "Generated-By: Babel %(version)s\n" cmlenz@381: cmlenz@381: #. This will be a translator coment, cmlenz@381: #. that will include several lines cmlenz@381: #: project/file1.py:8 cmlenz@381: msgid "bar" cmlenz@381: msgstr "" cmlenz@381: cmlenz@381: #: project/file2.py:9 cmlenz@381: msgid "foobar" cmlenz@381: msgid_plural "foobars" cmlenz@381: msgstr[0] "" cmlenz@381: msgstr[1] "" cmlenz@381: msgstr[2] "" cmlenz@381: cmlenz@381: """ % {'version': VERSION, cmlenz@381: 'date': format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', cmlenz@381: tzinfo=LOCALTZ, locale='en')}, cmlenz@381: open(po_file, 'U').read()) cmlenz@263: cmlenz@263: def test_compile_catalog(self): cmlenz@263: po_file = os.path.join(self.datadir, 'project', 'i18n', 'de_DE', cmlenz@263: 'LC_MESSAGES', 'messages.po') cmlenz@263: mo_file = po_file.replace('.po', '.mo') cmlenz@263: self.cli.run(sys.argv + ['compile', cmlenz@263: '--locale', 'de_DE', cmlenz@263: '-d', os.path.join(self.datadir, 'project', 'i18n')]) cmlenz@263: assert not os.path.isfile(mo_file), 'Expected no file at %r' % mo_file cmlenz@263: self.assertEqual("""\ cmlenz@263: catalog %r is marked as fuzzy, skipping cmlenz@263: """ % (po_file), sys.stderr.getvalue()) cmlenz@263: cmlenz@263: def test_compile_fuzzy_catalog(self): cmlenz@263: po_file = os.path.join(self.datadir, 'project', 'i18n', 'de_DE', cmlenz@263: 'LC_MESSAGES', 'messages.po') cmlenz@263: mo_file = po_file.replace('.po', '.mo') cmlenz@263: try: cmlenz@263: self.cli.run(sys.argv + ['compile', cmlenz@263: '--locale', 'de_DE', '--use-fuzzy', cmlenz@263: '-d', os.path.join(self.datadir, 'project', 'i18n')]) cmlenz@263: assert os.path.isfile(mo_file) cmlenz@263: self.assertEqual("""\ cmlenz@263: compiling catalog %r to %r cmlenz@263: """ % (po_file, mo_file), sys.stderr.getvalue()) cmlenz@263: finally: cmlenz@263: if os.path.isfile(mo_file): cmlenz@263: os.unlink(mo_file) cmlenz@263: cmlenz@348: def test_compile_catalog_with_more_than_2_plural_forms(self): cmlenz@348: po_file = os.path.join(self.datadir, 'project', 'i18n', 'ru_RU', cmlenz@348: 'LC_MESSAGES', 'messages.po') cmlenz@348: mo_file = po_file.replace('.po', '.mo') cmlenz@348: try: cmlenz@348: self.cli.run(sys.argv + ['compile', cmlenz@348: '--locale', 'ru_RU', '--use-fuzzy', cmlenz@348: '-d', os.path.join(self.datadir, 'project', 'i18n')]) cmlenz@348: assert os.path.isfile(mo_file) cmlenz@348: self.assertEqual("""\ cmlenz@348: compiling catalog %r to %r cmlenz@348: """ % (po_file, mo_file), sys.stderr.getvalue()) cmlenz@348: finally: cmlenz@348: if os.path.isfile(mo_file): cmlenz@348: os.unlink(mo_file) cmlenz@348: cmlenz@263: cmlenz@263: def suite(): cmlenz@263: suite = unittest.TestSuite() cmlenz@263: suite.addTest(doctest.DocTestSuite(frontend)) cmlenz@263: suite.addTest(unittest.makeSuite(CompileCatalogTestCase)) cmlenz@263: suite.addTest(unittest.makeSuite(ExtractMessagesTestCase)) cmlenz@263: suite.addTest(unittest.makeSuite(InitCatalogTestCase)) cmlenz@263: suite.addTest(unittest.makeSuite(CommandLineInterfaceTestCase)) cmlenz@263: return suite cmlenz@263: cmlenz@263: if __name__ == '__main__': cmlenz@263: unittest.main(defaultTest='suite')