Pylons и i18n с возможностью Cascaded Domains
В продолжение к предыдущему посту.
Ещё раз посмотрев на внутренности pylons, нашел наиболее лаконичное решение, не использующее ни переопределение _() для библиотек, ни явный вызов dgettext. Всё в рамках существующих объектов фреймворка.
Можно заменить/добавить аналог функции pylons.i18n.translation.add_fallback, которая бы принимала в качестве аргументов не только наименование языка (так реализовано в pylons), но и имя домена с locale-директорией. Внутри функция вызывает pylons.i18n.translation._get_translator, поэтому её также необходимо переписать.
Возможная реализация выглядит так.
После чего, где-нибудь в BaseController указываем:
Всего этого можно было бы избежать, если бы 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'.
Что очень досадно.
Ещё раз посмотрев на внутренности 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'.
Что очень досадно.
