Commit 7c6e265a authored by Ramiro Morales's avatar Ramiro Morales
Browse files

Refactored the internals of makemessages management command for better readability.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17261 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 64066a59
Loading
Loading
Loading
Loading
+165 −143
Original line number Diff line number Diff line
@@ -112,84 +112,50 @@ def copy_plural_forms(msgs, locale, domain, verbosity):
                break
    return msgs


def make_messages(locale=None, domain='django', verbosity='1', all=False,
        extensions=None, symlinks=False, ignore_patterns=[], no_wrap=False,
        no_location=False,
        no_obsolete=False):
def write_pot_file(potfile, msgs, file, work_file, is_templatized):
    """
    Uses the locale directory from the Django SVN tree or an application/
    project to process all
    Write the :param potfile: POT file with the :param msgs: contents,
    previously making sure its format is valid.
    """
    # Need to ensure that the i18n framework is enabled
    from django.conf import settings
    if settings.configured:
        settings.USE_I18N = True
    else:
        settings.configure(USE_I18N = True)

    from django.utils.translation import templatize

    invoked_for_django = False
    if os.path.isdir(os.path.join('conf', 'locale')):
        localedir = os.path.abspath(os.path.join('conf', 'locale'))
        invoked_for_django = True
        # Ignoring all contrib apps
        ignore_patterns += ['contrib/*']
    elif os.path.isdir('locale'):
        localedir = os.path.abspath('locale')
    if is_templatized:
        old = '#: ' + work_file[2:]
        new = '#: ' + file[2:]
        msgs = msgs.replace(old, new)
    if os.path.exists(potfile):
        # Strip the header
        msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
    else:
        raise CommandError("This script should be run from the Django SVN tree or your project or app tree. If you did indeed run it from the SVN checkout or your project or application, maybe you are just missing the conf/locale (in the django tree) or locale (for project and application) directory? It is not created automatically, you have to create it by hand if you want to enable i18n for your project or application.")

    if domain not in ('django', 'djangojs'):
        raise CommandError("currently makemessages only supports domains 'django' and 'djangojs'")

    if (locale is None and not all) or domain is None:
        message = "Type '%s help %s' for usage information." % (os.path.basename(sys.argv[0]), sys.argv[1])
        raise CommandError(message)

    # We require gettext version 0.15 or newer.
    output = _popen('xgettext --version')[0]
    match = re.search(r'(?P<major>\d+)\.(?P<minor>\d+)', output)
    if match:
        xversion = (int(match.group('major')), int(match.group('minor')))
        if xversion < (0, 15):
            raise CommandError("Django internationalization requires GNU gettext 0.15 or newer. You are using version %s, please upgrade your gettext toolset." % match.group())

    languages = []
    if locale is not None:
        languages.append(locale)
    elif all:
        locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % localedir))
        languages = [os.path.basename(l) for l in locale_dirs]

    wrap = no_wrap and '--no-wrap' or ''
    location = no_location and '--no-location' or ''
        msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
    f = open(potfile, 'ab')
    try:
        f.write(msgs)
    finally:
        f.close()

    for locale in languages:
        if verbosity > 0:
            print "processing language", locale
        basedir = os.path.join(localedir, locale, 'LC_MESSAGES')
        if not os.path.isdir(basedir):
            os.makedirs(basedir)
def process_file(file, dirpath, potfile, domain, verbosity, extensions, wrap,
        location):
    """
    Extract translatable literals from :param file: for :param domain:
    creating or updating the :param potfile: POT file.

        pofile = os.path.join(basedir, '%s.po' % domain)
        potfile = os.path.join(basedir, '%s.pot' % domain)
    Uses the xgettext GNU gettext utility.
    """

        if os.path.exists(potfile):
            os.unlink(potfile)
    from django.utils.translation import templatize

        for dirpath, file in find_files(".", ignore_patterns, verbosity, symlinks=symlinks):
            file_base, file_ext = os.path.splitext(file)
            if domain == 'djangojs' and file_ext in extensions:
    if verbosity > 1:
        sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
                src = open(os.path.join(dirpath, file), "rU").read()
                src = prepare_js_for_gettext(src)
    _, file_ext = os.path.splitext(file)
    if domain == 'djangojs' and file_ext in extensions:
        is_templatized = True
        orig_file = os.path.join(dirpath, file)
        src_data = open(orig_file).read()
        src_data = prepare_js_for_gettext(src_data)
        thefile = '%s.c' % file
                f = open(os.path.join(dirpath, thefile), "w")
        work_file = os.path.join(dirpath, thefile)
        f = open(work_file, "w")
        try:
                    f.write(src)
            f.write(src_data)
        finally:
            f.close()
        cmd = (
@@ -197,46 +163,23 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
            '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 '
            '--keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 '
            '--from-code UTF-8 --add-comments=Translators -o - "%s"' % (
                        domain, wrap, location, os.path.join(dirpath, thefile)
                domain, wrap, location, work_file
            )
        )
                msgs, errors = _popen(cmd)
                if errors:
                    os.unlink(os.path.join(dirpath, thefile))
                    if os.path.exists(potfile):
                        os.unlink(potfile)
                    raise CommandError(
                        "errors happened while running xgettext on %s\n%s" %
                        (file, errors))
                if msgs:
                    old = '#: ' + os.path.join(dirpath, thefile)[2:]
                    new = '#: ' + os.path.join(dirpath, file)[2:]
                    msgs = msgs.replace(old, new)
                    if os.path.exists(potfile):
                        # Strip the header
                        msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
                    else:
                        msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
                    f = open(potfile, 'ab')
                    try:
                        f.write(msgs)
                    finally:
                        f.close()
                os.unlink(os.path.join(dirpath, thefile))
    elif domain == 'django' and (file_ext == '.py' or file_ext in extensions):
        thefile = file
        orig_file = os.path.join(dirpath, file)
                if file_ext in extensions:
                    src = open(orig_file, "rU").read()
        is_templatized = file_ext in extensions
        if is_templatized:
            src_data = open(orig_file, "rU").read()
            thefile = '%s.py' % file
                    content = templatize(src, orig_file[2:])
            content = templatize(src_data, orig_file[2:])
            f = open(os.path.join(dirpath, thefile), "w")
            try:
                f.write(content)
            finally:
                f.close()
                if verbosity > 1:
                    sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
        work_file = os.path.join(dirpath, thefile)
        cmd = (
            'xgettext -d %s -L Python %s %s --keyword=gettext_noop '
            '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 '
@@ -245,42 +188,37 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
            '--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 '
            '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 '
            '--add-comments=Translators -o - "%s"' % (
                        domain, wrap, location, os.path.join(dirpath, thefile))
                domain, wrap, location, work_file)
        )
    else:
        return
    msgs, errors = _popen(cmd)
    if errors:
                    if thefile != file:
                        os.unlink(os.path.join(dirpath, thefile))
        if is_templatized:
            os.unlink(work_file)
        if os.path.exists(potfile):
            os.unlink(potfile)
        raise CommandError(
            "errors happened while running xgettext on %s\n%s" %
            (file, errors))
    if msgs:
                    if thefile != file:
                        old = '#: ' + os.path.join(dirpath, thefile)[2:]
                        new = '#: ' + orig_file[2:]
                        msgs = msgs.replace(old, new)
                    if os.path.exists(potfile):
                        # Strip the header
                        msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
                    else:
                        msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
                    f = open(potfile, 'ab')
                    try:
                        f.write(msgs)
                    finally:
                        f.close()
                if thefile != file:
                    os.unlink(os.path.join(dirpath, thefile))
        write_pot_file(potfile, msgs, orig_file, work_file, is_templatized)
    if is_templatized:
        os.unlink(work_file)

        if os.path.exists(potfile):
def write_po_file(pofile, potfile, domain, locale, verbosity,
        copy_pforms, wrap, location, no_obsolete):
    """
    Creates of updates the :param pofile: PO file for :param domain: and :param
    locale:.  Uses contents of the existing :param potfile:.

    Uses mguniq, msgmerge, and msgattrib GNU gettext utilities.
    """
    msgs, errors = _popen('msguniq %s %s --to-code=utf-8 "%s"' %
                            (wrap, location, potfile))
    if errors:
        os.unlink(potfile)
                raise CommandError(
                    "errors happened while running msguniq\n%s" % errors)
        raise CommandError("errors happened while running msguniq\n%s" % errors)
    if os.path.exists(pofile):
        f = open(potfile, 'w')
        try:
@@ -293,7 +231,7 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
            os.unlink(potfile)
            raise CommandError(
                "errors happened while running msgmerge\n%s" % errors)
            elif not invoked_for_django:
    elif copy_pforms:
        msgs = copy_plural_forms(msgs, locale, domain, verbosity)
    msgs = msgs.replace(
        "#. #-#-#-#-#  %s.pot (PACKAGE VERSION)  #-#-#-#-#\n" % domain, "")
@@ -310,6 +248,90 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False,
            raise CommandError(
                "errors happened while running msgattrib\n%s" % errors)

def make_messages(locale=None, domain='django', verbosity=1, all=False,
        extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False,
        no_location=False, no_obsolete=False):
    """
    Uses the ``locale/`` directory from the Django SVN tree or an
    application/project to process all files with translatable literals for
    the :param domain: domain and :param locale: locale.
    """
    # Need to ensure that the i18n framework is enabled
    from django.conf import settings
    if settings.configured:
        settings.USE_I18N = True
    else:
        settings.configure(USE_I18N = True)

    if ignore_patterns is None:
        ignore_patterns = []

    invoked_for_django = False
    if os.path.isdir(os.path.join('conf', 'locale')):
        localedir = os.path.abspath(os.path.join('conf', 'locale'))
        invoked_for_django = True
        # Ignoring all contrib apps
        ignore_patterns += ['contrib/*']
    elif os.path.isdir('locale'):
        localedir = os.path.abspath('locale')
    else:
        raise CommandError("This script should be run from the Django SVN "
                "tree or your project or app tree. If you did indeed run it "
                "from the SVN checkout or your project or application, "
                "maybe you are just missing the conf/locale (in the django "
                "tree) or locale (for project and application) directory? It "
                "is not created automatically, you have to create it by hand "
                "if you want to enable i18n for your project or application.")

    if domain not in ('django', 'djangojs'):
        raise CommandError("currently makemessages only supports domains 'django' and 'djangojs'")

    if (locale is None and not all) or domain is None:
        message = "Type '%s help %s' for usage information." % (os.path.basename(sys.argv[0]), sys.argv[1])
        raise CommandError(message)

    # We require gettext version 0.15 or newer.
    output = _popen('xgettext --version')[0]
    match = re.search(r'(?P<major>\d+)\.(?P<minor>\d+)', output)
    if match:
        xversion = (int(match.group('major')), int(match.group('minor')))
        if xversion < (0, 15):
            raise CommandError("Django internationalization requires GNU "
                    "gettext 0.15 or newer. You are using version %s, please "
                    "upgrade your gettext toolset." % match.group())

    locales = []
    if locale is not None:
        locales.append(locale)
    elif all:
        locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % localedir))
        locales = [os.path.basename(l) for l in locale_dirs]

    wrap = '--no-wrap' if no_wrap else ''
    location = '--no-location' if no_location else ''

    for locale in locales:
        if verbosity > 0:
            print "processing language", locale
        basedir = os.path.join(localedir, locale, 'LC_MESSAGES')
        if not os.path.isdir(basedir):
            os.makedirs(basedir)

        pofile = os.path.join(basedir, '%s.po' % domain)
        potfile = os.path.join(basedir, '%s.pot' % domain)

        if os.path.exists(potfile):
            os.unlink(potfile)

        for dirpath, file in find_files(".", ignore_patterns, verbosity,
                symlinks=symlinks):
            process_file(file, dirpath, potfile, domain, verbosity, extensions,
                    wrap, location)

        if os.path.exists(potfile):
            write_po_file(pofile, potfile, domain, locale, verbosity,
                    not invoked_for_django, wrap, location, no_obsolete)


class Command(NoArgsCommand):
    option_list = NoArgsCommand.option_list + (