changeset 106:2a00e352c986

Merged `write_pot` and `write_po` functions by moving more functionality to the `Catalog` class. This is certainly not perfect yet, but moves us in the right direction.
author cmlenz
date Wed, 13 Jun 2007 23:02:24 +0000
parents abd3a594dab4
children 4b42e23644e5
files babel/messages/catalog.py babel/messages/frontend.py babel/messages/pofile.py babel/messages/tests/pofile.py
diffstat 4 files changed, 176 insertions(+), 319 deletions(-) [+]
line wrap: on
line diff
--- a/babel/messages/catalog.py
+++ b/babel/messages/catalog.py
@@ -103,11 +103,18 @@
         :type:  `bool`
         """)
 
+DEFAULT_HEADER = u"""\
+# Translations template for PROJECT.
+# Copyright (C) YEAR COPYRIGHT HOLDER
+# This file is distributed under the same license as the PROJECT project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#"""
 
 class Catalog(object):
     """Representation of a message catalog."""
 
-    def __init__(self, locale=None, domain=None, project=None, version=None,
+    def __init__(self, locale=None, domain=None, header_comment=DEFAULT_HEADER,
+                 project=None, version=None, copyright_holder=None,
                  msgid_bugs_address=None, creation_date=None,
                  revision_date=None, last_translator=None, charset='utf-8'):
         """Initialize the catalog object.
@@ -116,21 +123,28 @@
                        if the catalog is not bound to a locale (which basically
                        means it's a template)
         :param domain: the message domain
+        :param header_comment: the header comment as string, or `None` for the
+                               default header
         :param project: the project's name
         :param version: the project's version
-        :param msgid_bugs_address: the address to report bugs about the catalog
+        :param copyright_holder: the copyright holder of the catalog
+        :param msgid_bugs_address: the email address or URL to submit bug
+                                   reports to
         :param creation_date: the date the catalog was created
         :param revision_date: the date the catalog was revised
         :param last_translator: the name and email of the last translator
+        :param charset: the encoding to use in the output
         """
         self.domain = domain #: the message domain
         if locale:
             locale = Locale.parse(locale)
         self.locale = locale #: the locale or `None`
+        self._header_comment = header_comment
         self._messages = odict()
 
         self.project = project or 'PROJECT' #: the project name
         self.version = version or 'VERSION' #: the project version
+        self.copyright_holder = copyright_holder or 'ORGANIZATION'
         self.msgid_bugs_address = msgid_bugs_address or 'EMAIL@ADDRESS'
         self.last_translator = last_translator #: last translator name + email
         self.charset = charset or 'utf-8'
@@ -146,7 +160,34 @@
             revision_date = revision_date.replace(tzinfo=LOCALTZ)
         self.revision_date = revision_date #: last revision date of the catalog
 
-    def headers(self):
+    def get_header_comment(self):
+        comment = self._header_comment
+        comment = comment.replace('PROJECT', self.project) \
+                         .replace('VERSION', self.version) \
+                         .replace('YEAR', self.revision_date.strftime('%Y')) \
+                         .replace('COPYRIGHT HOLDER', self.copyright_holder)
+        if self.locale:
+            comment = comment.replace('Translations template',
+                                      '%s translations' % self.locale.english_name)
+        return comment
+    def set_header_comment(self, string):
+        self._header_comment = string
+    header_comment = property(get_header_comment, set_header_comment, doc="""\
+    The header comment for the catalog.
+    
+    >>> catalog = Catalog(project='Foobar', version='1.0',
+    ...                   copyright_holder='Foo Company')
+    >>> print catalog.header_comment
+    # Translations template for Foobar.
+    # Copyright (C) 2007 Foo Company
+    # This file is distributed under the same license as the Foobar project.
+    # FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
+    #
+
+    :type: `unicode`
+    """)
+
+    def mime_headers(self):
         headers = []
         headers.append(('Project-Id-Version',
                         '%s %s' % (self.project, self.version)))
@@ -169,7 +210,7 @@
         headers.append(('Content-Transfer-Encoding', '8bit'))
         headers.append(('Generated-By', 'Babel %s' % VERSION))
         return headers
-    headers = property(headers, doc="""\
+    mime_headers = property(mime_headers, doc="""\
     The MIME headers of the catalog, used for the special ``msgid ""`` entry.
     
     The behavior of this property changes slightly depending on whether a locale
@@ -181,7 +222,7 @@
     >>> created = datetime(1990, 4, 1, 15, 30, tzinfo=UTC)
     >>> catalog = Catalog(project='Foobar', version='1.0',
     ...                   creation_date=created)
-    >>> for name, value in catalog.headers:
+    >>> for name, value in catalog.mime_headers:
     ...     print '%s: %s' % (name, value)
     Project-Id-Version: Foobar 1.0
     Report-Msgid-Bugs-To: EMAIL@ADDRESS
@@ -200,7 +241,7 @@
     >>> catalog = Catalog(locale='de_DE', project='Foobar', version='1.0',
     ...                   creation_date=created, revision_date=revised,
     ...                   last_translator='John Doe <jd@example.com>')
-    >>> for name, value in catalog.headers:
+    >>> for name, value in catalog.mime_headers:
     ...     print '%s: %s' % (name, value)
     Project-Id-Version: Foobar 1.0
     Report-Msgid-Bugs-To: EMAIL@ADDRESS
@@ -273,7 +314,7 @@
         :rtype: ``iterator``
         """
         buf = []
-        for name, value in self.headers:
+        for name, value in self.mime_headers:
             buf.append('%s: %s' % (name, value))
         yield Message('', '\n'.join(buf), flags=set(['fuzzy']))
         for key in self._messages:
--- a/babel/messages/frontend.py
+++ b/babel/messages/frontend.py
@@ -15,6 +15,7 @@
 """Frontends for the message extraction functionality."""
 
 from ConfigParser import RawConfigParser
+from datetime import datetime
 from distutils import log
 from distutils.cmd import Command
 from distutils.errors import DistutilsOptionError, DistutilsSetupError
@@ -30,9 +31,9 @@
 from babel.messages.catalog import Catalog
 from babel.messages.extract import extract_from_dir, DEFAULT_KEYWORDS, \
                                    DEFAULT_MAPPING
-from babel.messages.pofile import write_po, write_pot
+from babel.messages.pofile import read_po, write_po
 from babel.messages.plurals import PLURALS
-from babel.util import odict
+from babel.util import odict, LOCALTZ
 
 __all__ = ['CommandLineInterface', 'extract_messages',
            'check_message_extractors', 'main']
@@ -177,12 +178,12 @@
                                 comments=comments)
 
             log.info('writing PO template file to %s' % self.output_file)
-            write_pot(outfile, catalog, width=self.width,
-                      no_location=self.no_location,
-                      omit_header=self.omit_header,
-                      sort_output=self.sort_output,
-                      sort_by_file=self.sort_by_file,
-                      copyright_holder=self.copyright_holder)
+            write_po(outfile, catalog, width=self.width,
+                     no_location=self.no_location,
+                     omit_header=self.omit_header,
+                     sort_output=self.sort_output,
+                     sort_by_file=self.sort_by_file,
+                     copyright_holder=self.copyright_holder)
         finally:
             outfile.close()
 
@@ -255,7 +256,7 @@
     description = 'create new catalogs based on a catalog template'
     user_options = [
         ('domain=', 'D',
-         "domain of PO file (defaults to lower-cased project name)"),
+         "domain of PO file (default 'messages')"),
         ('input-file=', 'i',
          'name of the input file'),
         ('output-dir=', 'd',
@@ -265,10 +266,6 @@
          "'<output_dir>/<locale>/LC_MESSAGES/<domain>.po')"),
         ('locale=', 'l',
          'locale for the new localized catalog'),
-        ('first-author=', None,
-         'name of first author'),
-        ('first-author-email=', None,
-         'email of first author')
     ]
 
     def initialize_options(self):
@@ -276,69 +273,47 @@
         self.output_file = None
         self.input_file = None
         self.locale = None
-        self.domain = None
-        self.first_author = None
-        self.first_author_email = None
+        self.domain = 'messages'
 
     def finalize_options(self):
         if not self.input_file:
             raise DistutilsOptionError('you must specify the input file')
 
-        if not self.domain:
-            self.domain = self.distribution.get_name().lower()
-
         if not self.locale:
             raise DistutilsOptionError('you must provide a locale for the '
                                        'new catalog')
-        else:
-            try:
-                self._locale = Locale.parse(self.locale)
-            except UnknownLocaleError, error:
-                log.error(error)
-                sys.exit(1)
-
-        if self._locale.territory == self._locale.language.upper():
-            # Remove country part if equal to language
-            # XXX: This might not be the best behaviour, investigate
-            self.locale = self._locale.language
+        try:
+            self._locale = Locale.parse(self.locale)
+        except UnknownLocaleError, e:
+            raise DistutilsOptionError(e)
 
         if not self.output_file and not self.output_dir:
             raise DistutilsOptionError('you must specify the output directory')
-
-        if not self.output_file and self.output_dir:
-            self.output_file = os.path.join(self.output_dir,
-                                            self.locale,
-                                            'LC_MESSAGES',
-                                            self.domain + '.po')
+        if not self.output_file:
+            self.output_file = os.path.join(self.output_dir, self.locale,
+                                            'LC_MESSAGES', self.domain + '.po')
 
         if not os.path.exists(os.path.dirname(self.output_file)):
             os.makedirs(os.path.dirname(self.output_file))
 
     def run(self):
-        outfile = open(self.output_file, 'w')
-        infile = open(self.input_file, 'r')
-
-        if PLURALS.has_key(str(self._locale)):
-            # Try <language>_<COUNTRY> if passed by user
-            plurals = PLURALS[str(self._locale)]
-        elif PLURALS.has_key(self._locale.language):
-            # Try <language>
-            plurals = PLURALS[self._locale.language]
-        else:
-            plurals = ('INTEGER', 'EXPRESSION')
-
         log.info('creating catalog %r based on %r', self.output_file,
                  self.input_file)
 
-        write_po(outfile, infile, self._locale,
-                 project=self.distribution.get_name(),
-                 version=self.distribution.get_version(),
-                 plurals=plurals,
-                 first_author=self.first_author,
-                 first_author_email=self.first_author_email)
+        infile = open(self.input_file, 'r')
+        try:
+            catalog = read_po(infile)
+        finally:
+            infile.close()
 
-        infile.close()
-        outfile.close()
+        catalog.locale = self._locale
+        catalog.revision_date = datetime.now()
+
+        outfile = open(self.output_file, 'w')
+        try:
+            write_po(outfile, catalog)
+        finally:
+            outfile.close()
 
 
 class CommandLineInterface(object):
@@ -492,12 +467,12 @@
                     catalog.add(message, None, [(filepath, lineno)], 
                                 comments=comments)
 
-            write_pot(outfile, catalog, width=options.width,
-                      no_location=options.no_location,
-                      omit_header=options.omit_header,
-                      sort_output=options.sort_output,
-                      sort_by_file=options.sort_by_file,
-                      copyright_holder=options.copyright_holder)
+            write_po(outfile, catalog, width=options.width,
+                     no_location=options.no_location,
+                     omit_header=options.omit_header,
+                     sort_output=options.sort_output,
+                     sort_by_file=options.sort_by_file,
+                     copyright_holder=options.copyright_holder)
         finally:
             if options.output:
                 outfile.close()
@@ -510,90 +485,59 @@
         parser = OptionParser(usage=self.usage % ('init',''),
                               description=self.command_descriptions['init'])
         parser.add_option('--domain', '-D', dest='domain',
-                          help="domain of PO file (defaults to lower-cased "
-                               "project name)")
+                          help="domain of PO file (default '%default')")
         parser.add_option('--input-file', '-i', dest='input_file',
-                          help='name of the input file')
+                          metavar='FILE', help='name of the input file')
         parser.add_option('--output-dir', '-d', dest='output_dir',
-                          help='path to output directory')
+                          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',
+        parser.add_option('--locale', '-l', dest='locale', metavar='LOCALE',
                           help='locale for the new localized catalog')
-        parser.add_option('--first-author', dest='first_author',
-                          metavar='FIRST_AUTHOR_NAME',
-                          help='name of first author')
-        parser.add_option('--first-author-email', dest='first_author_email',
-                          help='email of first author')
-        parser.add_option('--project-name', dest='project_name', metavar='NAME',
-                          default='PROJECT', help='the project name')
-        parser.add_option('--project-version', dest='project_version',
-                          metavar='VERSION', help='the project version')
 
+        parser.set_defaults(domain='messages')
         options, args = parser.parse_args(argv)
 
-        if not options.project_name:
-            parser.error('please provide the project name')
-
-        if not options.project_version:
-            parser.error('please provide the project version')
+        if not options.locale:
+            parser.error('you must provide a locale for the new catalog')
+        try:
+            locale = Locale.parse(options.locale)
+        except UnknownLocaleError, e:
+            parser.error(e)
 
         if not options.input_file:
             parser.error('you must specify the input file')
 
-        if not options.domain:
-            options.domain = options.project_name.lower()
-
-        if not options.locale:
-            parser.error('you must provide a locale for the new catalog')
-        else:
-            try:
-                locale = Locale.parse(options.locale)
-            except UnknownLocaleError, error:
-                parser.error(error)
+        if not options.output_file and not options.output_dir:
+            parser.error('you must specify the output file or directory')
 
-        if locale.language.upper() == locale.territory:
-            # Remove country part if equal to language
-            # XXX: This might not be the best behaviour, investigate
-            options.locale = locale.language
-
-        if not options.output_file and not options.output_dir:
-            parser.error('you must specify the output directory')
-
-        if not options.output_file and options.output_dir:
+        if not options.output_file:
             options.output_file = os.path.join(options.output_dir,
-                                               options.locale,
-                                               'LC_MESSAGES',
+                                               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))
 
-        outfile = open(options.output_file, 'w')
         infile = open(options.input_file, 'r')
+        try:
+            catalog = read_po(infile)
+        finally:
+            infile.close()
 
-        if PLURALS.has_key(str(locale)):
-            # Try <language>_<COUNTRY> if passed by user
-            plurals = PLURALS[str(locale)]
-        elif PLURALS.has_key(locale.language):
-            # Try <language>
-            plurals = PLURALS[locale.language]
-        else:
-            plurals = ('INTEGER', 'EXPRESSION')
+        catalog.locale = locale
+        catalog.revision_date = datetime.now()
 
         print 'creating catalog %r based on %r' % (options.output_file,
                                                    options.input_file)
 
-        write_po(outfile, infile, locale,
-                 project=options.project_name,
-                 version=options.project_version,
-                 plurals=plurals,
-                 first_author=options.first_author,
-                 first_author_email=options.first_author_email)
-
-        infile.close()
-        outfile.close()
+        outfile = open(options.output_file, 'w')
+        try:
+            write_po(outfile, catalog)
+        finally:
+            outfile.close()
 
 def main():
     CommandLineInterface().run(sys.argv)
--- a/babel/messages/pofile.py
+++ b/babel/messages/pofile.py
@@ -30,14 +30,19 @@
 from babel.messages.catalog import Catalog
 from babel.util import LOCALTZ
 
-__all__ = ['escape', 'normalize', 'read_po', 'write_po', 'write_pot']
+__all__ = ['escape', 'normalize', 'read_po', 'write_po']
 
 def read_po(fileobj):
     """Read messages from a ``gettext`` PO (portable object) file from the given
     file-like object and return a `Catalog`.
     
     >>> from StringIO import StringIO
-    >>> buf = StringIO('''
+    >>> buf = StringIO('''# Translations template for PROJECT.
+    ... # Copyright (C) YEAR COPYRIGHT HOLDER
+    ... # This file is distributed under the same license as the PROJECT project.
+    ... # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+    ... #
+    ... 
     ... #: main.py:1
     ... #, fuzzy, python-format
     ... msgid "foo %(name)s"
@@ -52,6 +57,14 @@
     ... msgstr[1] ""
     ... ''')
     >>> catalog = read_po(buf)
+    >>> catalog.revision_date = datetime(2007, 04, 01)
+    
+    >>> print catalog.header_comment
+    # Translations template for PROJECT.
+    # Copyright (C) 2007 ORGANIZATION
+    # This file is distributed under the same license as the PROJECT project.
+    # FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
+    
     >>> for message in catalog:
     ...     if message.id:
     ...         print (message.id, message.string)
@@ -73,6 +86,8 @@
     flags = []
     comments = []
     in_msgid = in_msgstr = False
+    in_header = True
+    header_lines = []
 
     def _add_message():
         translations.sort()
@@ -91,29 +106,33 @@
     for line in fileobj.readlines():
         line = line.strip()
         if line.startswith('#'):
-            in_msgid = in_msgstr = False
-            if messages:
-                _add_message()
-            if line[1:].startswith(':'):
-                for location in line[2:].lstrip().split():
-                    filename, lineno = location.split(':', 1)
-                    locations.append((filename, int(lineno)))
-            elif line[1:].startswith(','):
-                for flag in line[2:].lstrip().split(','):
-                    flags.append(flag.strip())
-            elif line[1:].startswith('.'):
-                # These are called auto-comments
-                comment = line[2:].strip()
-                if comment:
-                    # Just check that we're not adding empty comments
-                    comments.append(comment)
-            elif line[1:].startswith(' '):
-                # These are called user comments
-                comment = line[1:].strip()
-                if comment:
-                    # Just check that we're not adding empty comments
-                    comments.append(comment)
-        elif line:
+            if in_header and line[1:].startswith(' '):
+                header_lines.append(line)
+            else:
+                in_header = in_msgid = in_msgstr = False
+                if messages:
+                    _add_message()
+                if line[1:].startswith(':'):
+                    for location in line[2:].lstrip().split():
+                        filename, lineno = location.split(':', 1)
+                        locations.append((filename, int(lineno)))
+                elif line[1:].startswith(','):
+                    for flag in line[2:].lstrip().split(','):
+                        flags.append(flag.strip())
+                elif line[1:].startswith('.'):
+                    # These are called auto-comments
+                    comment = line[2:].strip()
+                    if comment:
+                        # Just check that we're not adding empty comments
+                        comments.append(comment)
+                elif line[1:].startswith(' '):
+                    # These are called user comments
+                    comment = line[1:].strip()
+                    if comment:
+                        # Just check that we're not adding empty comments
+                        comments.append(comment)
+        else:
+            in_header = False
             if line.startswith('msgid_plural'):
                 in_msgid = True
                 msg = line[12:].lstrip()
@@ -139,18 +158,11 @@
                 elif in_msgstr:
                     translations[-1][1] += line.rstrip()[1:-1]
 
+    catalog.header_comment = '\n'.join(header_lines)
     if messages:
         _add_message()
     return catalog
 
-POT_HEADER = u"""\
-# Translations template for %(project)s.
-# Copyright (C) %(year)s %(copyright_holder)s
-# This file is distributed under the same license as the %(project)s project.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-""" 
-
 WORD_SEP = re.compile('('
     r'\s+|'                                 # any whitespace
     r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words
@@ -236,8 +248,8 @@
         lines[-1] += '\n'
     return u'""\n' + u'\n'.join([escape(l) for l in lines])
 
-def write_pot(fileobj, catalog, width=76, no_location=False, omit_header=False,
-              sort_output=False, sort_by_file=False, copyright_holder=None):
+def write_po(fileobj, catalog, width=76, no_location=False, omit_header=False,
+             sort_output=False, sort_by_file=False):
     r"""Write a ``gettext`` PO (portable object) template file for a given
     message catalog to the provided file-like object.
     
@@ -247,7 +259,7 @@
     >>> catalog.add((u'bar', u'baz'), locations=[('main.py', 3)])
     >>> from StringIO import StringIO
     >>> buf = StringIO()
-    >>> write_pot(buf, catalog, omit_header=True)
+    >>> write_po(buf, catalog, omit_header=True)
     >>> print buf.getvalue()
     #: main.py:1
     #, fuzzy, python-format
@@ -269,7 +281,6 @@
     :param no_location: do not emit a location comment for every message
     :param omit_header: do not include the ``msgid ""`` entry at the top of the
                         output
-    :param copyright_holder: sets the copyright holder in the output
     """
     def _normalize(key):
         return normalize(key, width=width).encode(catalog.charset,
@@ -280,33 +291,24 @@
             text = text.encode(catalog.charset)
         fileobj.write(text)
 
+    messages = list(catalog)
     if sort_output:
-        messages = list(catalog)
         messages.sort(lambda x,y: cmp(x.id, y.id))
     elif sort_by_file:
-        messages = list(catalog)
         messages.sort(lambda x,y: cmp(x.locations, y.locations))
-    else:
-        messages = catalog
-
-    _copyright_holder = copyright_holder or 'ORGANIZATION'
 
     for message in messages:
         if not message.id: # This is the header "message"
             if omit_header:
                 continue
-            pot_header = POT_HEADER % {
-                'year': date.today().strftime('%Y'),
-                'project': catalog.project,
-                'copyright_holder': _copyright_holder,
-            }
+            comment_header = catalog.header_comment
             if width and width > 0:
                 lines = []
-                for line in pot_header.splitlines():
+                for line in comment_header.splitlines():
                     lines += wrap(line, width=width, subsequent_indent='# ',
                                   break_long_words=False)
-                pot_header = u'\n'.join(lines) + u'\n'
-            _write(pot_header)
+                comment_header = u'\n'.join(lines) + u'\n'
+            _write(comment_header)
 
         if message.comments:
             for comment in message.comments:
@@ -331,135 +333,3 @@
             _write('msgid %s\n' % _normalize(message.id))
             _write('msgstr %s\n' % _normalize(message.string or ''))
         _write('\n')
-
-
-# TODO: this should really be a combination of read_po() and write_pot(), the
-#       latter then being renamed back to write_po(). The problem at this time
-#       is that the Catalog class doesn't know anything about the header
-#       comment header
-
-def write_po(fileobj, input_fileobj, locale_obj, project='PROJECT',
-             version='VERSION', first_author=None, first_author_email=None,
-             plurals=('INTEGER', 'EXPRESSION')):
-    r"""Write a ``gettext`` PO (portable object) file to the given file-like 
-    object, from the given input PO template file.
-    
-    >>> from StringIO import StringIO
-    >>> from babel import Locale
-    >>> locale_obj = Locale.parse('pt_PT')
-    >>> inbuf = StringIO(r'''# Translations template for FooBar.
-    ... # Copyright (C) 2007 ORGANIZATION
-    ... # This file is distributed under the same license as the
-    ... # FooBar project.
-    ... # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-    ... #
-    ... #, fuzzy
-    ... msgid ""
-    ... msgstr ""
-    ... "Project-Id-Version: FooBar 0.1\n"
-    ... "POT-Creation-Date: 2007-06-07 22:54+0100\n"
-    ... "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-    ... "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-    ... "Language-Team: LANGUAGE <LL@li.org>\n"
-    ... "MIME-Version: 1.0\n"
-    ... "Content-Type: text/plain; charset=utf-8\n"
-    ... "Content-Transfer-Encoding: 8bit\n"
-    ... "Generated-By: Babel 0.1dev-r50\n"
-    ...
-    ... #: base.py:83 templates/index.html:9
-    ... #: templates/index2.html:9
-    ... msgid "Home"
-    ... msgstr ""
-    ...
-    ... #: base.py:84 templates/index.html:9
-    ... msgid "Accounts"
-    ... msgstr ""
-    ... ''')
-    >>> outbuf = StringIO()
-    >>> write_po(outbuf, inbuf, locale_obj, project='FooBar',
-    ...          version='0.1', first_author='A Name', 
-    ...          first_author_email='user@domain.tld',
-    ...          plurals=(2, '(n != 1)'))
-    >>> print outbuf.getvalue() # doctest: +ELLIPSIS
-    # Portuguese (Portugal) translations for FooBar
-    # Copyright (C) 2007 ORGANIZATION
-    # This file is distributed under the same license as the
-    # FooBar project.
-    # A Name <user@domain.tld>, ...
-    #
-    #, fuzzy
-    msgid ""
-    msgstr ""
-    "Project-Id-Version: FooBar 0.1\n"
-    "POT-Creation-Date: 2007-06-07 22:54+0100\n"
-    "PO-Revision-Date: ...\n"
-    "Last-Translator: A Name <user@domain.tld>\n"
-    "Language-Team: LANGUAGE <LL@li.org>\n"
-    "MIME-Version: 1.0\n"
-    "Content-Type: text/plain; charset=utf-8\n"
-    "Content-Transfer-Encoding: 8bit\n"
-    "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-    "Generated-By: Babel ...\n"
-    <BLANKLINE>
-    #: base.py:83 templates/index.html:9
-    #: templates/index2.html:9
-    msgid "Home"
-    msgstr ""
-    <BLANKLINE>
-    #: base.py:84 templates/index.html:9
-    msgid "Accounts"
-    msgstr ""
-    <BLANKLINE>
-    >>>
-    """
-    
-    _first_author = ''
-    if first_author:
-        _first_author += first_author
-    if first_author_email:
-        _first_author += ' <%s>' % first_author_email
-
-    inlines = input_fileobj.readlines()
-    outlines = []
-    in_header = True
-    _date = datetime.now(LOCALTZ)
-    for index in range(len(inlines)):
-        if in_header:
-            if '# Translations template' in inlines[index]:
-                outlines.append('# %s translations for %s\n' % \
-                                (locale_obj.english_name, project))
-            elif '# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.' in inlines[index]:
-                if _first_author:
-                    outlines.append(
-                        '# %s, %s\n' % (_first_author, _date.strftime('%Y'))
-                    )
-                else:
-                    outlines.append(inlines[index])
-            elif '"PO-Revision-Date:' in inlines[index]:
-                outlines.append(
-                    '"PO-Revision-Date: %s\\n"\n' % \
-                    _date.strftime('%Y-%m-%d %H:%M%z')
-                )
-            elif '"Last-Translator:' in inlines[index]:
-                if _first_author:
-                    outlines.append(
-                        '"Last-Translator: %s\\n"\n' % _first_author
-                    )
-                else:
-                    outlines.append(inlines[index])
-            elif '"Content-Transfer-Encoding:' in inlines[index]:
-                outlines.append(inlines[index])
-                if '"Plural-Forms:' not in inlines[index+1]:
-                    outlines.append(
-                        '"Plural-Forms: nplurals=%s; plural=%s;\\n"\n' % plurals
-                    )
-            elif inlines[index].endswith('\\n"\n') and \
-                 inlines[index+1] == '\n':
-                in_header = False
-                outlines.append(inlines[index])
-            else:
-                outlines.append(inlines[index])
-        else:
-            outlines.extend(inlines[index:])
-            break
-    fileobj.writelines(outlines)
--- a/babel/messages/tests/pofile.py
+++ b/babel/messages/tests/pofile.py
@@ -11,6 +11,7 @@
 # individuals. For the exact contribution history, see the revision
 # history and logs, available at http://babel.edgewall.org/log/.
 
+from datetime import datetime
 import doctest
 from StringIO import StringIO
 import unittest
@@ -19,14 +20,14 @@
 from babel.messages import pofile
 
 
-class WritePotTestCase(unittest.TestCase):
+class WritePoTestCase(unittest.TestCase):
 
     def test_join_locations(self):
         catalog = Catalog()
         catalog.add(u'foo', locations=[('main.py', 1)])
         catalog.add(u'foo', locations=[('utils.py', 3)])
         buf = StringIO()
-        pofile.write_pot(buf, catalog, omit_header=True)
+        pofile.write_po(buf, catalog, omit_header=True)
         self.assertEqual('''#: main.py:1 utils.py:3
 msgid "foo"
 msgstr ""''', buf.getvalue().strip())
@@ -41,7 +42,7 @@
         catalog = Catalog()
         catalog.add(text, locations=[('main.py', 1)])
         buf = StringIO()
-        pofile.write_pot(buf, catalog, no_location=True, omit_header=True,
+        pofile.write_po(buf, catalog, no_location=True, omit_header=True,
                          width=42)
         self.assertEqual(r'''msgid ""
 "Here's some text where       \n"
@@ -59,7 +60,7 @@
         catalog = Catalog()
         catalog.add(text, locations=[('main.py', 1)])
         buf = StringIO()
-        pofile.write_pot(buf, catalog, no_location=True, omit_header=True,
+        pofile.write_po(buf, catalog, no_location=True, omit_header=True,
                          width=32)
         self.assertEqual(r'''msgid ""
 "Here's some text that\n"
@@ -72,15 +73,16 @@
         """
         Verify that long lines in the header comment are wrapped correctly.
         """
-        catalog = Catalog(project='AReallyReallyLongNameForAProject')
+        catalog = Catalog(project='AReallyReallyLongNameForAProject',
+                          revision_date=datetime(2007, 4, 1))
         buf = StringIO()
-        pofile.write_pot(buf, catalog)
+        pofile.write_po(buf, catalog)
         self.assertEqual('''\
 # Translations template for AReallyReallyLongNameForAProject.
 # Copyright (C) 2007 ORGANIZATION
 # This file is distributed under the same license as the
 # AReallyReallyLongNameForAProject project.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
 #
 #, fuzzy''', '\n'.join(buf.getvalue().splitlines()[:7]))
 
@@ -92,7 +94,7 @@
                     comments=['Comment About `bar` with',
                               'multiple lines.'])
         buf = StringIO()
-        pofile.write_pot(buf, catalog, omit_header=True)
+        pofile.write_po(buf, catalog, omit_header=True)
         self.assertEqual('''#. Comment About `foo`
 #: main.py:1
 msgid "foo"
@@ -108,7 +110,7 @@
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(doctest.DocTestSuite(pofile))
-    suite.addTest(unittest.makeSuite(WritePotTestCase))
+    suite.addTest(unittest.makeSuite(WritePoTestCase))
     return suite
 
 if __name__ == '__main__':
Copyright (C) 2012-2017 Edgewall Software