예제 #1
0
def xml2po(resources, translations=None, resfilter=None, warnfunc=dummy_warn):
    """Return ``resources`` as a Babel .po ``Catalog`` instance.

    If given, ``translations`` will be used for the translated values.
    In this case, the returned value is a 2-tuple (catalog, unmatched),
    with the latter being a list of Android string resource names that
    are in the translated file, but not in the original.

    Both ``resources`` and ``translations`` must be ``ResourceTree``
    objects, as returned by ``read_xml()``.

    From the application perspective, it will call this function with
    a ``translations`` object when initializing a new .po file based on
    an existing resource file (the 'init' command). For 'export', this
    function is called without translations. It will thus generate what
    is essentially a POT file (an empty .po file), and this will be
    merged into the existing .po catalogs, as per how gettext usually
    """
    assert not translations or translations.language

    catalog = Catalog()
    if translations is not None:
        catalog.locale = translations.language.locale
        # We cannot let Babel determine the plural expr for the locale by
        # itself. It will use a custom list of plural expressions rather
        # than generate them based on CLDR.
        # See http://babel.edgewall.org/ticket/290.
        set_catalog_plural_forms(catalog, translations.language)

    for name, org_value in resources.items():
        if resfilter and resfilter(name):
            continue

        trans_value = None
        if translations:
            trans_value = translations.pop(name, trans_value)

        if isinstance(org_value, StringArray):
            # a string-array, write as "name:index"
            if len(org_value) == 0:
                warnfunc("Warning: string-array '%s' is empty" % name,
                         'warning')
                continue

            if not isinstance(trans_value, StringArray):
                if trans_value:
                    warnfunc(('""%s" is a string-array in the reference '
                              'file, but not in the translation.') % name,
                             'warning')
                trans_value = StringArray()

            for index, item in enumerate(org_value):
                item_trans = trans_value[index].text if index < len(
                    trans_value) else ''

                # If the string has formatting markers, indicate it in
                # the gettext output
                flags = []
                if item.formatted:
                    flags.append('c-format')

                ctx = "%s:%d" % (name, index)
                catalog.add(item.text,
                            item_trans,
                            auto_comments=item.comments,
                            flags=flags,
                            context=ctx)

        elif isinstance(org_value, Plurals):
            # a plurals, convert to a gettext plurals
            if len(org_value) == 0:
                warnfunc("Warning: plurals '%s' is empty" % name, 'warning')
                continue

            if not isinstance(trans_value, Plurals):
                if trans_value:
                    warnfunc(('""%s" is a plurals in the reference '
                              'file, but not in the translation.') % name,
                             'warning')
                trans_value = Plurals()

            # Taking the Translation objects for each quantity in ``org_value``,
            # we build a list of strings, which is how plurals are represented
            # in Babel.
            #
            # Since gettext only allows comments/flags on the whole
            # thing at once, we merge the comments/flags of all individual
            # plural strings into one.
            formatted = False
            comments = []
            for _, translation in list(org_value.items()):
                if translation.formatted:
                    formatted = True
                comments.extend(translation.comments)

            # For the message id, choose any two plural forms, but prefer
            # "one" and "other", assuming an English master resource.
            temp = org_value.copy()
            singular =\
                temp.pop('one') if 'one' in temp else\
                temp.pop('other') if 'other' in temp else\
                temp.pop(list(temp.keys())[0])
            plural =\
                temp.pop('other') if 'other' in temp else\
                temp[list(temp.keys())[0]] if temp else\
                singular
            msgid = (singular.text, plural.text)
            del temp, singular, plural

            # We pick the quantities supported by the language (the rest
            # would be ignored by Android as well).
            msgstr = ''
            if trans_value:
                allowed_keywords = translations.language.plural_keywords
                msgstr = ['' for i in range(len(allowed_keywords))]
                for quantity, translation in list(trans_value.items()):
                    try:
                        index = translations.language.plural_keywords.index(
                            quantity)
                    except ValueError:
                        warnfunc(
                            ('"plurals "%s" uses quantity "%s", which '
                             'is not supported for this language. See '
                             'the README for an explanation. The '
                             'quantity has been ignored') % (name, quantity),
                            'warning')
                    else:
                        msgstr[index] = translation.text

            flags = []
            if formatted:
                flags.append('c-format')
            catalog.add(msgid,
                        tuple(msgstr),
                        flags=flags,
                        auto_comments=comments,
                        context=name)

        else:
            # a normal string

            # If the string has formatting markers, indicate it in
            # the gettext output
            # TODO DRY this.
            flags = []
            if org_value.formatted:
                flags.append('c-format')

            catalog.add(org_value.text,
                        trans_value.text if trans_value else '',
                        flags=flags,
                        auto_comments=org_value.comments,
                        context=name)

    if translations is not None:
        # At this point, trans_strings only contains those for which
        # no original existed.
        return catalog, list(translations.keys())
    else:
        return catalog
예제 #2
0
파일: convert.py 프로젝트: vvz/android2po
def xml2po(resources, translations=None, filter=None, warnfunc=dummy_warn):
    """Return ``resources`` as a Babel .po ``Catalog`` instance.

    If given, ``translations`` will be used for the translated values.
    In this case, the returned value is a 2-tuple (catalog, unmatched),
    with the latter being a list of Android string resource names that
    are in the translated file, but not in the original.

    Both ``resources`` and ``translations`` must be ``ResourceTree``
    objects, as returned by ``read_xml()``.

    From the application perspective, it will call this function with
    a ``translations`` object when initializing a new .po file based on
    an existing resource file (the 'init' command). For 'export', this
    function is called without translations. It will thus generate what
    is essentially a POT file (an empty .po file), and this will be
    merged into the existing .po catalogs, as per how gettext usually
    """
    assert not translations or translations.language

    catalog = Catalog()
    if translations is not None:
        catalog.locale = translations.language.locale
        # We cannot let Babel determine the plural expr for the locale by
        # itself. It will use a custom list of plural expressions rather
        # than generate them based on CLDR.
        # See http://babel.edgewall.org/ticket/290.
        set_catalog_plural_forms(catalog, translations.language)

    for name, org_value in resources.iteritems():
        if filter and filter(name):
            continue

        trans_value = None
        if translations:
            trans_value = translations.pop(name, trans_value)

        if isinstance(org_value, StringArray):
            # a string-array, write as "name:index"
            if len(org_value) == 0:
                warnfunc("Warning: string-array '%s' is empty" % name, "warning")
                continue

            if not isinstance(trans_value, StringArray):
                if trans_value:
                    warnfunc(
                        ('""%s" is a string-array in the reference ' "file, but not in the translation.") % name,
                        "warning",
                    )
                trans_value = StringArray()

            for index, item in enumerate(org_value):
                item_trans = trans_value[index].text if index < len(trans_value) else u""

                # If the string has formatting markers, indicate it in
                # the gettext output
                flags = []
                if item.formatted:
                    flags.append("c-format")

                ctx = "%s:%d" % (name, index)
                catalog.add(item.text, item_trans, auto_comments=item.comments, flags=flags, context=ctx)

        elif isinstance(org_value, Plurals):
            # a plurals, convert to a gettext plurals
            if len(org_value) == 0:
                warnfunc("Warning: plurals '%s' is empty" % name, "warning")
                continue

            if not isinstance(trans_value, Plurals):
                if trans_value:
                    warnfunc(
                        ('""%s" is a plurals in the reference ' "file, but not in the translation.") % name, "warning"
                    )
                trans_value = Plurals()

            # Taking the Translation objects for each quantity in ``org_value``,
            # we build a list of strings, which is how plurals are represented
            # in Babel.
            #
            # Since gettext only allows comments/flags on the whole
            # thing at once, we merge the comments/flags of all individual
            # plural strings into one.
            formatted = False
            comments = []
            for _, translation in org_value.items():
                if translation.formatted:
                    formatted = True
                comments.extend(translation.comments)

            # For the message id, choose any two plural forms, but prefer
            # "one" and "other", assuming an English master resource.
            temp = org_value.copy()
            singular = (
                temp.pop("one") if "one" in temp else temp.pop("other") if "other" in temp else temp.pop(temp.keys()[0])
            )
            plural = temp.pop("other") if "other" in temp else temp[temp.keys()[0]] if temp else singular
            msgid = (singular.text, plural.text)
            del temp, singular, plural

            # We pick the quantities supported by the language (the rest
            # would be ignored by Android as well).
            msgstr = ""
            if trans_value:
                allowed_keywords = translations.language.plural_keywords
                msgstr = ["" for i in range(len(allowed_keywords))]
                for quantity, translation in trans_value.items():
                    try:
                        index = translations.language.plural_keywords.index(quantity)
                    except ValueError:
                        warnfunc(
                            (
                                '"plurals "%s" uses quantity "%s", which '
                                "is not supported for this language. See "
                                "the README for an explanation. The "
                                "quantity has been ignored"
                            )
                            % (name, quantity),
                            "warning",
                        )
                    else:
                        msgstr[index] = translation.text

            flags = []
            if formatted:
                flags.append("c-format")
            catalog.add(msgid, tuple(msgstr), flags=flags, auto_comments=comments, context=name)

        else:
            # a normal string

            # If the string has formatting markers, indicate it in
            # the gettext output
            # TODO DRY this.
            flags = []
            if org_value.formatted:
                flags.append("c-format")

            catalog.add(
                org_value.text,
                trans_value.text if trans_value else u"",
                flags=flags,
                auto_comments=org_value.comments,
                context=name,
            )

    if translations is not None:
        # At this point, trans_strings only contains those for which
        # no original existed.
        return catalog, translations.keys()
    else:
        return catalog