Image

Imageice_b wrote in Imageru_python

Pylons и i18n с возможностью Cascaded Domains

В продолжение к предыдущему посту.

Ещё раз посмотрев на внутренности pylons, нашел наиболее лаконичное решение, не использующее ни переопределение _() для библиотек, ни явный вызов dgettext. Всё в рамках существующих объектов фреймворка.

Можно заменить/добавить аналог функции pylons.i18n.translation.add_fallback, которая бы принимала в качестве аргументов не только наименование языка (так реализовано в pylons), но и имя домена с locale-директорией. Внутри функция вызывает pylons.i18n.translation._get_translator, поэтому её также необходимо переписать.

Возможная реализация выглядит так.
from gettext import NullTranslations, translation
import pylons

def _get_translator(domain, localedir, lang=None, **kwargs):
    """Utility method to get a valid translator object from the
    given conditions"""
    if not lang:
        return NullTranslations()
    
    if not isinstance(lang, list):
        lang = [lang]
    try:
        translator = translation(domain, localedir,
                                 languages=lang, **kwargs)
    except IOError as ioe:
        raise LanguageError('IOError: {0}'.format(ioe))
    
    translator.pylons_lang = lang
    return translator


def add_domain_fallback(domain, localedir, lang, **kwargs):
    """Add a fallback domain from which words not matched in primary
    domain (project's domain) will be searched to.

    This fallback will be associated with the currently selected
    language -- that is, resetting the language via set_lang() resets
    the current fallbacks.
    """
    
    return pylons.translator.add_fallback(
                _get_translator(
                    domain,
                    localedir,
                    lang,
                    **kwargs
                )
            )


После чего, где-нибудь в BaseController указываем:
class BaseController(WSGIController):
    def __call__(self, environ, start_response):
        ...

        # i18n
        set_lang(variable_with_lang)
        add_domain_fallback(
            domain='library_domain',
            localedir='path_to_localedir',
            lang=variable_with_lang)

        ...


Всего этого можно было бы избежать, если бы API pylons не урезал функциональность API pygettext. В стандартном определении, pylons.i18n.translation._get_translator принимает дополнительные **kwargs и далее передаёт их вызову gettext.translation. Однако в теле функции зачем-то явно определяются domain и localedir, которые затем передаются в gettext.translation в виде позиционных параметров.
Поэтому, если мы попытаемся вызвать стандартный фреймворковский add_fallback() с самостоятельно заданными domain и localedir в качестве **kwargs, то получим закономерное TypeError: translation() got multiple values for keyword argument 'domain'.
Что очень досадно.