コード例 #1
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_header_entry(self):
        buf = StringIO(r'''\
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2007 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version:  3.15\n"
"Report-Msgid-Bugs-To: Fliegender Zirkus <*****@*****.**>\n"
"POT-Creation-Date: 2007-09-27 11:19+0700\n"
"PO-Revision-Date: 2007-09-27 21:42-0700\n"
"Last-Translator: John <*****@*****.**>\n"
"Language-Team: German Lang <*****@*****.**>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 1.0dev-r313\n"
''')
        catalog = pofile.read_po(buf)
        self.assertEqual(1, len(list(catalog)))
        self.assertEqual(u'3.15', catalog.version)
        self.assertEqual(u'Fliegender Zirkus <*****@*****.**>',
                         catalog.msgid_bugs_address)
        self.assertEqual(datetime(2007, 9, 27, 11, 19,
                                  tzinfo=FixedOffsetTimezone(7 * 60)),
                         catalog.creation_date)
        self.assertEqual(u'John <*****@*****.**>', catalog.last_translator)
        self.assertEqual(u'German Lang <*****@*****.**>', catalog.language_team)
        self.assertEqual(u'iso-8859-2', catalog.charset)
        self.assertEqual(True, list(catalog)[0].fuzzy)
コード例 #2
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_with_context(self):
        buf = BytesIO(b'''# Some string in the menu
#: main.py:1
msgctxt "Menu"
msgid "foo"
msgstr "Voh"

# Another string in the menu
#: main.py:2
msgctxt "Menu"
msgid "bar"
msgstr "Bahr"
''')
        catalog = pofile.read_po(buf, ignore_obsolete=True)
        self.assertEqual(2, len(catalog))
        message = catalog.get('foo', context='Menu')
        self.assertEqual('Menu', message.context)
        message = catalog.get('bar', context='Menu')
        self.assertEqual('Menu', message.context)

        # And verify it pass through write_po
        out_buf = BytesIO()
        pofile.write_po(out_buf, catalog, omit_header=True)
        assert out_buf.getvalue().strip() == buf.getvalue().strip(), \
                                                            out_buf.getvalue()
コード例 #3
0
ファイル: frontend.py プロジェクト: ghosthoughts/py3babel
    def run(self):
        po_files = []
        mo_files = []

        if not self.input_file:
            if self.locale:
                po_files.append(
                    (self.locale, os.path.join(self.directory, self.locale, "LC_MESSAGES", self.domain + ".po"))
                )
                mo_files.append(os.path.join(self.directory, self.locale, "LC_MESSAGES", self.domain + ".mo"))
            else:
                for locale in os.listdir(self.directory):
                    po_file = os.path.join(self.directory, locale, "LC_MESSAGES", self.domain + ".po")
                    if os.path.exists(po_file):
                        po_files.append((locale, po_file))
                        mo_files.append(os.path.join(self.directory, locale, "LC_MESSAGES", self.domain + ".mo"))
        else:
            po_files.append((self.locale, self.input_file))
            if self.output_file:
                mo_files.append(self.output_file)
            else:
                mo_files.append(os.path.join(self.directory, self.locale, "LC_MESSAGES", self.domain + ".mo"))

        if not po_files:
            raise DistutilsOptionError("no message catalogs found")

        for idx, (locale, po_file) in enumerate(po_files):
            mo_file = mo_files[idx]
            infile = open(po_file, "rb")
            try:
                catalog = read_po(infile, locale)
            finally:
                infile.close()

            if self.statistics:
                translated = 0
                for message in list(catalog)[1:]:
                    if message.string:
                        translated += 1
                percentage = 0
                if len(catalog):
                    percentage = translated * 100 // len(catalog)
                log.info("%d of %d messages (%d%%) translated in %r", translated, len(catalog), percentage, po_file)

            if catalog.fuzzy and not self.use_fuzzy:
                log.warn("catalog %r is marked as fuzzy, skipping", po_file)
                continue

            for message, errors in catalog.check():
                for error in errors:
                    log.error("error: %s:%d: %s", po_file, message.lineno, error)

            log.info("compiling catalog %r to %r", po_file, mo_file)

            outfile = open(mo_file, "wb")
            try:
                write_mo(outfile, catalog, use_fuzzy=self.use_fuzzy)
            finally:
                outfile.close()
コード例 #4
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_single_plural_form(self):
        buf = StringIO(r'''msgid "foo"
msgid_plural "foos"
msgstr[0] "Voh"''')
        catalog = pofile.read_po(buf, locale='ja_JP')
        self.assertEqual(1, len(catalog))
        self.assertEqual(1, catalog.num_plurals)
        message = catalog['foo']
        self.assertEqual(1, len(message.string))
コード例 #5
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_plural_with_square_brackets(self):
        buf = StringIO(r'''msgid "foo"
msgid_plural "foos"
msgstr[0] "Voh [text]"
msgstr[1] "Vohs [text]"''')
        catalog = pofile.read_po(buf, locale='nb_NO')
        self.assertEqual(1, len(catalog))
        self.assertEqual(2, catalog.num_plurals)
        message = catalog['foo']
        self.assertEqual(2, len(message.string))
コード例 #6
0
    def test_1_num_plurals_checkers(self):
        for _locale in [p for p in PLURALS if PLURALS[p][0] == 1]:
            try:
                locale = Locale.parse(_locale)
            except UnknownLocaleError:
                # Just an alias? Not what we're testing here, let's continue
                continue
            po_file = (u"""\
# %(english_name)s translations for TestProject.
# Copyright (C) 2007 FooBar, Inc.
# This file is distributed under the same license as the TestProject
# project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
#
msgid ""
msgstr ""
"Project-Id-Version: TestProject 0.1\\n"
"Report-Msgid-Bugs-To: [email protected]\\n"
"POT-Creation-Date: 2007-04-01 15:30+0200\\n"
"PO-Revision-Date: %(date)s\\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
"Language-Team: %(locale)s <*****@*****.**>\n"
"Plural-Forms: nplurals=%(num_plurals)s; plural=%(plural_expr)s\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=utf-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Generated-By: Babel %(version)s\\n"

#. This will be a translator comment,
#. that will include several lines
#: project/file1.py:8
msgid "bar"
msgstr ""

#: project/file2.py:9
msgid "foobar"
msgid_plural "foobars"
msgstr[0] ""

""" % dict(locale       = _locale,
           english_name = locale.english_name,
           version      = VERSION,
           year         = time.strftime('%Y'),
           date         = format_datetime(datetime.now(LOCALTZ),
                                          'yyyy-MM-dd HH:mmZ',
                                          tzinfo=LOCALTZ, locale=_locale),
           num_plurals  = PLURALS[_locale][0],
           plural_expr  = PLURALS[_locale][0])).encode('utf-8')

            # This test will fail for revisions <= 406 because so far
            # catalog.num_plurals was neglected
            catalog = read_po(BytesIO(po_file), _locale)
            message = catalog['foobar']
            checkers.num_plurals(catalog, message)
コード例 #7
0
    def test_input_dirs_is_treated_as_list(self):
        self.cmd.input_dirs = self.datadir
        self.cmd.output_file = self._pot_file()
        self.cmd.finalize_options()
        self.cmd.run()

        with open(self._pot_file(), 'U') as f:
            catalog = read_po(f)
        msg = catalog.get('bar')
        self.assertEqual(1, len(msg.locations))
        self.assertTrue('file1.py' in msg.locations[0][0])
コード例 #8
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_more_than_two_plural_forms(self):
        buf = StringIO(r'''msgid "foo"
msgid_plural "foos"
msgstr[0] "Voh"
msgstr[1] "Vohs"
msgstr[2] "Vohss"''')
        catalog = pofile.read_po(buf, locale='lv_LV')
        self.assertEqual(1, len(catalog))
        self.assertEqual(3, catalog.num_plurals)
        message = catalog['foo']
        self.assertEqual(3, len(message.string))
        self.assertEqual(u'Vohss', message.string[2])
コード例 #9
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_not_fuzzy_header(self):
        buf = StringIO(r'''\
# Translations template for AReallyReallyLongNameForAProject.
# Copyright (C) 2007 ORGANIZATION
# This file is distributed under the same license as the
# AReallyReallyLongNameForAProject project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
#
''')
        catalog = pofile.read_po(buf)
        self.assertEqual(1, len(list(catalog)))
        self.assertEqual(False, list(catalog)[0].fuzzy)
コード例 #10
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_silent_location_fallback(self):
        buf = BytesIO(b'''\
#: broken_file.py
msgid "missing line number"
msgstr ""

#: broken_file.py:broken_line_number
msgid "broken line number"
msgstr ""''')
        catalog = pofile.read_po(buf)
        self.assertEqual(catalog['missing line number'].locations, [])
        self.assertEqual(catalog['broken line number'].locations, [])
コード例 #11
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_read_multiline(self):
        buf = StringIO(r'''msgid ""
"Here's some text that\n"
"includesareallylongwordthatmightbutshouldnt"
" throw us into an infinite "
"loop\n"
msgstr ""''')
        catalog = pofile.read_po(buf)
        self.assertEqual(1, len(catalog))
        message = list(catalog)[1]
        self.assertEqual("Here's some text that\nincludesareallylongwordthat"
                         "mightbutshouldnt throw us into an infinite loop\n",
                         message.id)
コード例 #12
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_obsolete_message_ignored(self):
        buf = StringIO(r'''# This is an obsolete message
#~ msgid "foo"
#~ msgstr "Voh"

# This message is not obsolete
#: main.py:1
msgid "bar"
msgstr "Bahr"
''')
        catalog = pofile.read_po(buf, ignore_obsolete=True)
        self.assertEqual(1, len(catalog))
        self.assertEqual(0, len(catalog.obsolete))
コード例 #13
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_obsolete_message(self):
        buf = StringIO(r'''# This is an obsolete message
#~ msgid "foo"
#~ msgstr "Voh"

# This message is not obsolete
#: main.py:1
msgid "bar"
msgstr "Bahr"
''')
        catalog = pofile.read_po(buf)
        self.assertEqual(1, len(catalog))
        self.assertEqual(1, len(catalog.obsolete))
        message = catalog.obsolete[u'foo']
        self.assertEqual(u'foo', message.id)
        self.assertEqual(u'Voh', message.string)
        self.assertEqual(['This is an obsolete message'], message.user_comments)
コード例 #14
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_applies_specified_encoding_during_read(self):
        buf = BytesIO(u'''
msgid ""
msgstr ""
"Project-Id-Version:  3.15\\n"
"Report-Msgid-Bugs-To: Fliegender Zirkus <*****@*****.**>\\n"
"POT-Creation-Date: 2007-09-27 11:19+0700\\n"
"PO-Revision-Date: 2007-09-27 21:42-0700\\n"
"Last-Translator: John <*****@*****.**>\\n"
"Language-Team: German Lang <*****@*****.**>\\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=iso-8859-1\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Generated-By: Babel 1.0dev-r313\\n"

msgid "foo"
msgstr "bär"'''.encode('iso-8859-1'))
        catalog = pofile.read_po(buf, locale='de_DE')
        self.assertEqual(u'bär', catalog.get('foo').string)
コード例 #15
0
ファイル: frontend.py プロジェクト: ghosthoughts/py3babel
    def run(self):
        log.info("creating catalog %r based on %r", self.output_file, self.input_file)

        infile = open(self.input_file, "rb")
        try:
            # Although reading from the catalog template, read_po must be fed
            # the locale in order to correctly calculate plurals
            catalog = read_po(infile, locale=self.locale)
        finally:
            infile.close()

        catalog.locale = self._locale
        catalog.revision_date = datetime.now(LOCALTZ)
        catalog.fuzzy = False

        outfile = open(self.output_file, "wb")
        try:
            write_po(outfile, catalog, width=self.width)
        finally:
            outfile.close()
コード例 #16
0
ファイル: frontend.py プロジェクト: ghosthoughts/py3babel
    def update(self, argv):
        """Subcommand for updating existing message catalogs from a template.

        :param argv: the command arguments
        :since: version 0.9
        """
        parser = OptionParser(usage=self.usage % ("update", ""), description=self.commands["update"])
        parser.add_option("--domain", "-D", dest="domain", help="domain of PO file (default '%default')")
        parser.add_option("--input-file", "-i", dest="input_file", metavar="FILE", help="name of the input file")
        parser.add_option("--output-dir", "-d", dest="output_dir", metavar="DIR", help="path to output directory")
        parser.add_option(
            "--output-file",
            "-o",
            dest="output_file",
            metavar="FILE",
            help="name of the output file (default " "'<output_dir>/<locale>/LC_MESSAGES/" "<domain>.po')",
        )
        parser.add_option("--locale", "-l", dest="locale", metavar="LOCALE", help="locale of the translations catalog")
        parser.add_option("-w", "--width", dest="width", type="int", help="set output line width (default 76)")
        parser.add_option(
            "--no-wrap",
            dest="no_wrap",
            action="store_true",
            help="do not break long message lines, longer than " "the output line width, into several lines",
        )
        parser.add_option(
            "--ignore-obsolete",
            dest="ignore_obsolete",
            action="store_true",
            help="do not include obsolete messages in the output " "(default %default)",
        )
        parser.add_option(
            "--no-fuzzy-matching",
            "-N",
            dest="no_fuzzy_matching",
            action="store_true",
            help="do not use fuzzy matching (default %default)",
        )
        parser.add_option(
            "--previous",
            dest="previous",
            action="store_true",
            help="keep previous msgids of translated messages " "(default %default)",
        )

        parser.set_defaults(domain="messages", ignore_obsolete=False, no_fuzzy_matching=False, previous=False)
        options, args = parser.parse_args(argv)

        if not options.input_file:
            parser.error("you must specify the input file")
        if not options.output_file and not options.output_dir:
            parser.error("you must specify the output file or directory")
        if options.output_file and not options.locale:
            parser.error("you must specify the locale")
        if options.no_fuzzy_matching and options.previous:
            options.previous = False

        po_files = []
        if not options.output_file:
            if options.locale:
                po_files.append(
                    (
                        options.locale,
                        os.path.join(options.output_dir, options.locale, "LC_MESSAGES", options.domain + ".po"),
                    )
                )
            else:
                for locale in os.listdir(options.output_dir):
                    po_file = os.path.join(options.output_dir, locale, "LC_MESSAGES", options.domain + ".po")
                    if os.path.exists(po_file):
                        po_files.append((locale, po_file))
        else:
            po_files.append((options.locale, options.output_file))

        domain = options.domain
        if not domain:
            domain = os.path.splitext(os.path.basename(options.input_file))[0]

        infile = open(options.input_file, "U")
        try:
            template = read_po(infile)
        finally:
            infile.close()

        if not po_files:
            parser.error("no message catalogs found")

        if options.width and options.no_wrap:
            parser.error("'--no-wrap' and '--width' are mutually exclusive.")
        elif not options.width and not options.no_wrap:
            options.width = 76
        for locale, filename in po_files:
            self.log.info("updating catalog %r based on %r", filename, options.input_file)
            infile = open(filename, "rb")
            try:
                catalog = read_po(infile, locale=locale, domain=domain)
            finally:
                infile.close()

            catalog.update(template, options.no_fuzzy_matching)

            tmpname = os.path.join(os.path.dirname(filename), tempfile.gettempprefix() + os.path.basename(filename))
            tmpfile = open(tmpname, "wb")
            try:
                try:
                    write_po(
                        tmpfile,
                        catalog,
                        ignore_obsolete=options.ignore_obsolete,
                        include_previous=options.previous,
                        width=options.width,
                    )
                finally:
                    tmpfile.close()
            except:
                os.remove(tmpname)
                raise

            try:
                os.rename(tmpname, filename)
            except OSError:
                # We're probably on Windows, which doesn't support atomic
                # renames, at least not through Python
                # If the error is in fact due to a permissions problem, that
                # same error is going to be raised from one of the following
                # operations
                os.remove(filename)
                shutil.copy(tmpname, filename)
                os.remove(tmpname)
コード例 #17
0
ファイル: frontend.py プロジェクト: ghosthoughts/py3babel
    def run(self):
        po_files = []
        if not self.output_file:
            if self.locale:
                po_files.append(
                    (self.locale, os.path.join(self.output_dir, self.locale, "LC_MESSAGES", self.domain + ".po"))
                )
            else:
                for locale in os.listdir(self.output_dir):
                    po_file = os.path.join(self.output_dir, locale, "LC_MESSAGES", self.domain + ".po")
                    if os.path.exists(po_file):
                        po_files.append((locale, po_file))
        else:
            po_files.append((self.locale, self.output_file))

        domain = self.domain
        if not domain:
            domain = os.path.splitext(os.path.basename(self.input_file))[0]

        infile = open(self.input_file, "rb")
        try:
            template = read_po(infile)
        finally:
            infile.close()

        if not po_files:
            raise DistutilsOptionError("no message catalogs found")

        for locale, filename in po_files:
            log.info("updating catalog %r based on %r", filename, self.input_file)
            infile = open(filename, "rb")
            try:
                catalog = read_po(infile, locale=locale, domain=domain)
            finally:
                infile.close()

            catalog.update(template, self.no_fuzzy_matching)

            tmpname = os.path.join(os.path.dirname(filename), tempfile.gettempprefix() + os.path.basename(filename))
            tmpfile = open(tmpname, "wb")
            try:
                try:
                    write_po(
                        tmpfile,
                        catalog,
                        ignore_obsolete=self.ignore_obsolete,
                        include_previous=self.previous,
                        width=self.width,
                    )
                finally:
                    tmpfile.close()
            except:
                os.remove(tmpname)
                raise

            try:
                os.rename(tmpname, filename)
            except OSError:
                # We're probably on Windows, which doesn't support atomic
                # renames, at least not through Python
                # If the error is in fact due to a permissions problem, that
                # same error is going to be raised from one of the following
                # operations
                os.remove(filename)
                shutil.copy(tmpname, filename)
                os.remove(tmpname)
コード例 #18
0
ファイル: frontend.py プロジェクト: ghosthoughts/py3babel
    def compile(self, argv):
        """Subcommand for compiling a message catalog to a MO file.

        :param argv: the command arguments
        :since: version 0.9
        """
        parser = OptionParser(usage=self.usage % ("compile", ""), description=self.commands["compile"])
        parser.add_option("--domain", "-D", dest="domain", help="domain of MO and PO files (default '%default')")
        parser.add_option("--directory", "-d", dest="directory", metavar="DIR", help="base directory of catalog files")
        parser.add_option("--locale", "-l", dest="locale", metavar="LOCALE", help="locale of the catalog")
        parser.add_option("--input-file", "-i", dest="input_file", metavar="FILE", help="name of the input file")
        parser.add_option(
            "--output-file",
            "-o",
            dest="output_file",
            metavar="FILE",
            help="name of the output file (default " "'<output_dir>/<locale>/LC_MESSAGES/" "<domain>.mo')",
        )
        parser.add_option(
            "--use-fuzzy",
            "-f",
            dest="use_fuzzy",
            action="store_true",
            help="also include fuzzy translations (default " "%default)",
        )
        parser.add_option(
            "--statistics", dest="statistics", action="store_true", help="print statistics about translations"
        )

        parser.set_defaults(domain="messages", use_fuzzy=False, compile_all=False, statistics=False)
        options, args = parser.parse_args(argv)

        po_files = []
        mo_files = []
        if not options.input_file:
            if not options.directory:
                parser.error("you must specify either the input file or the " "base directory")
            if options.locale:
                po_files.append(
                    (
                        options.locale,
                        os.path.join(options.directory, options.locale, "LC_MESSAGES", options.domain + ".po"),
                    )
                )
                mo_files.append(os.path.join(options.directory, options.locale, "LC_MESSAGES", options.domain + ".mo"))
            else:
                for locale in os.listdir(options.directory):
                    po_file = os.path.join(options.directory, locale, "LC_MESSAGES", options.domain + ".po")
                    if os.path.exists(po_file):
                        po_files.append((locale, po_file))
                        mo_files.append(os.path.join(options.directory, locale, "LC_MESSAGES", options.domain + ".mo"))
        else:
            po_files.append((options.locale, options.input_file))
            if options.output_file:
                mo_files.append(options.output_file)
            else:
                if not options.directory:
                    parser.error("you must specify either the output file or " "the base directory")
                mo_files.append(os.path.join(options.directory, options.locale, "LC_MESSAGES", options.domain + ".mo"))
        if not po_files:
            parser.error("no message catalogs found")

        for idx, (locale, po_file) in enumerate(po_files):
            mo_file = mo_files[idx]
            infile = open(po_file, "rb")
            try:
                catalog = read_po(infile, locale)
            finally:
                infile.close()

            if options.statistics:
                translated = 0
                for message in list(catalog)[1:]:
                    if message.string:
                        translated += 1
                percentage = 0
                if len(catalog):
                    percentage = translated * 100 // len(catalog)
                self.log.info(
                    "%d of %d messages (%d%%) translated in %r", translated, len(catalog), percentage, po_file
                )

            if catalog.fuzzy and not options.use_fuzzy:
                self.log.warning("catalog %r is marked as fuzzy, skipping", po_file)
                continue

            for message, errors in catalog.check():
                for error in errors:
                    self.log.error("error: %s:%d: %s", po_file, message.lineno, error)

            self.log.info("compiling catalog %r to %r", po_file, mo_file)

            outfile = open(mo_file, "wb")
            try:
                write_mo(outfile, catalog, use_fuzzy=options.use_fuzzy)
            finally:
                outfile.close()
コード例 #19
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_preserve_domain(self):
        buf = StringIO(r'''msgid "foo"
msgstr "Voh"''')
        catalog = pofile.read_po(buf, domain='mydomain')
        self.assertEqual('mydomain', catalog.domain)
コード例 #20
0
ファイル: test_pofile.py プロジェクト: ghosthoughts/py3babel
    def test_preserve_locale(self):
        buf = StringIO(r'''msgid "foo"
msgstr "Voh"''')
        catalog = pofile.read_po(buf, locale='en_US')
        self.assertEqual(Locale('en', 'US'), catalog.locale)
コード例 #21
0
ファイル: frontend.py プロジェクト: ghosthoughts/py3babel
    def init(self, argv):
        """Subcommand for creating new message catalogs from a template.

        :param argv: the command arguments
        """
        parser = OptionParser(usage=self.usage % ("init", ""), description=self.commands["init"])
        parser.add_option("--domain", "-D", dest="domain", help="domain of PO file (default '%default')")
        parser.add_option("--input-file", "-i", dest="input_file", metavar="FILE", help="name of the input file")
        parser.add_option("--output-dir", "-d", dest="output_dir", metavar="DIR", help="path to output directory")
        parser.add_option(
            "--output-file",
            "-o",
            dest="output_file",
            metavar="FILE",
            help="name of the output file (default " "'<output_dir>/<locale>/LC_MESSAGES/" "<domain>.po')",
        )
        parser.add_option(
            "--locale", "-l", dest="locale", metavar="LOCALE", help="locale for the new localized catalog"
        )
        parser.add_option("-w", "--width", dest="width", type="int", help="set output line width (default 76)")
        parser.add_option(
            "--no-wrap",
            dest="no_wrap",
            action="store_true",
            help="do not break long message lines, longer than " "the output line width, into several lines",
        )

        parser.set_defaults(domain="messages")
        options, args = parser.parse_args(argv)

        if not options.locale:
            parser.error("you must provide a locale for the new catalog")
        try:
            locale = Locale.parse(options.locale)
        except UnknownLocaleError as e:
            parser.error(e)

        if not options.input_file:
            parser.error("you must specify the input file")

        if not options.output_file and not options.output_dir:
            parser.error("you must specify the output file or directory")

        if not options.output_file:
            options.output_file = os.path.join(
                options.output_dir, options.locale, "LC_MESSAGES", options.domain + ".po"
            )
        if not os.path.exists(os.path.dirname(options.output_file)):
            os.makedirs(os.path.dirname(options.output_file))
        if options.width and options.no_wrap:
            parser.error("'--no-wrap' and '--width' are mutually exclusive.")
        elif not options.width and not options.no_wrap:
            options.width = 76

        infile = open(options.input_file, "r")
        try:
            # Although reading from the catalog template, read_po must be fed
            # the locale in order to correctly calculate plurals
            catalog = read_po(infile, locale=options.locale)
        finally:
            infile.close()

        catalog.locale = locale
        catalog.revision_date = datetime.now(LOCALTZ)

        self.log.info("creating catalog %r based on %r", options.output_file, options.input_file)

        outfile = open(options.output_file, "wb")
        try:
            write_po(outfile, catalog, width=options.width)
        finally:
            outfile.close()