1
"""Translation/Localization functions.
3
Provides :mod:`gettext` translation functions via an app's
4
``pylons.translator`` and get/set_lang for changing the language
9
from gettext import NullTranslations, translation
13
__all__ = ['_', 'add_fallback', 'get_lang', 'gettext', 'gettext_noop',
14
'lazy_gettext', 'lazy_ngettext', 'lazy_ugettext', 'lazy_ungettext',
15
'ngettext', 'set_lang', 'ugettext', 'ungettext', 'LanguageError',
18
class LanguageError(Exception):
19
"""Exception raised when a problem occurs with changing languages"""
23
class LazyString(object):
24
"""Has a number of lazily evaluated functions replicating a
25
string. Just override the eval() method to produce the actual value.
27
This method copied from TurboGears.
30
def __init__(self, func, *args, **kwargs):
36
return self.func(*self.args, **self.kwargs)
38
def __unicode__(self):
39
return unicode(self.eval())
42
return str(self.eval())
44
def __mod__(self, other):
45
return self.eval() % other
47
def format(self, other):
48
return self.eval().format(other)
52
"""Decorator to return a lazy-evaluated version of the original"""
53
def newfunc(*args, **kwargs):
54
return LazyString(func, *args, **kwargs)
55
newfunc.__name__ = 'lazy_%s' % func.__name__
56
newfunc.__doc__ = 'Lazy-evaluated version of the %s function\n\n%s' % \
57
(func.__name__, func.__doc__)
61
def gettext_noop(value):
62
"""Mark a string for translation without translating it. Returns
65
Used for global strings, e.g.::
71
self.local_foo = _(foo)
74
assert Bar().local_foo == 'Bonjour'
76
assert Bar().local_foo == 'Hola'
85
"""Mark a string for translation. Returns the localized string of
88
Mark a string to be localized as follows::
90
gettext('This should be in lots of languages')
93
return pylons.translator.gettext(value)
94
lazy_gettext = lazify(gettext)
98
"""Mark a string for translation. Returns the localized unicode
101
Mark a string to be localized as follows::
103
_('This should be in lots of languages')
106
return pylons.translator.ugettext(value)
108
lazy_ugettext = lazify(ugettext)
111
def ngettext(singular, plural, n):
112
"""Mark a string for translation. Returns the localized string of
113
the pluralized value.
115
This does a plural-forms lookup of a message id. ``singular`` is
116
used as the message id for purposes of lookup in the catalog, while
117
``n`` is used to determine which plural form to use. The returned
120
Mark a string to be localized as follows::
122
ngettext('There is %(num)d file here', 'There are %(num)d files here',
126
return pylons.translator.ngettext(singular, plural, n)
127
lazy_ngettext = lazify(ngettext)
130
def ungettext(singular, plural, n):
131
"""Mark a string for translation. Returns the localized unicode
132
string of the pluralized value.
134
This does a plural-forms lookup of a message id. ``singular`` is
135
used as the message id for purposes of lookup in the catalog, while
136
``n`` is used to determine which plural form to use. The returned
137
message is a Unicode string.
139
Mark a string to be localized as follows::
141
ungettext('There is %(num)d file here', 'There are %(num)d files here',
145
return pylons.translator.ungettext(singular, plural, n)
146
lazy_ungettext = lazify(ungettext)
149
def _get_translator(lang, **kwargs):
150
"""Utility method to get a valid translator object from a language
153
return NullTranslations()
154
if 'pylons_config' in kwargs:
155
conf = kwargs.pop('pylons_config')
157
conf = pylons.config.current_conf()
158
localedir = os.path.join(conf['pylons.paths']['root'], 'i18n')
159
if not isinstance(lang, list):
162
translator = translation(conf['pylons.package'], localedir,
163
languages=lang, **kwargs)
165
raise LanguageError('IOError: %s' % ioe)
166
translator.pylons_lang = lang
170
def set_lang(lang, **kwargs):
171
"""Set the current language used for translations.
173
``lang`` should be a string or a list of strings. If a list of
174
strings, the first language is set as the main and the subsequent
175
languages are added as fallbacks.
177
translator = _get_translator(lang, **kwargs)
178
environ = pylons.request.environ
179
environ['pylons.pylons'].translator = translator
180
if 'paste.registry' in environ:
181
environ['paste.registry'].replace(pylons.translator, translator)
185
"""Return the current i18n language used"""
186
return getattr(pylons.translator, 'pylons_lang', None)
189
def add_fallback(lang, **kwargs):
190
"""Add a fallback language from which words not matched in other
191
languages will be translated to.
193
This fallback will be associated with the currently selected
194
language -- that is, resetting the language via set_lang() resets
195
the current fallbacks.
197
This function can be called multiple times to add multiple
200
return pylons.translator.add_fallback(_get_translator(lang, **kwargs))