1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 from babel
import localedata
22 from babel
.support
import LazyProxy
24 from mediagoblin
import mg_globals
30 AVAILABLE_LOCALES
= None
31 TRANSLATIONS_PATH
= pkg_resources
.resource_filename(
32 'mediagoblin', 'i18n')
35 def set_available_locales():
36 """Set available locales for which we have translations"""
37 global AVAILABLE_LOCALES
38 locales
=['en', 'en_US'] # these are available without translations
39 for locale
in localedata
.list():
40 if gettext
.find('mediagoblin', TRANSLATIONS_PATH
, [locale
]):
41 locales
.append(locale
)
42 AVAILABLE_LOCALES
= locales
45 class ReallyLazyProxy(LazyProxy
):
47 Like LazyProxy, except that it doesn't cache the value ;)
51 return self
._func
(*self
._args
, **self
._kwargs
)
54 return "<%s for %s(%r, %r)>" % (
55 self
.__class
__.__name
__,
61 def locale_to_lower_upper(locale
):
63 Take a locale, regardless of style, and format it like "en_US"
66 lang
, country
= locale
.split('-', 1)
67 return '%s_%s' % (lang
.lower(), country
.upper())
69 lang
, country
= locale
.split('_', 1)
70 return '%s_%s' % (lang
.lower(), country
.upper())
75 def locale_to_lower_lower(locale
):
77 Take a locale, regardless of style, and format it like "en_us"
80 lang
, country
= locale
.split('_', 1)
81 return '%s-%s' % (lang
.lower(), country
.lower())
86 def get_locale_from_request(request
):
88 Return most appropriate language based on prefs/request request
90 request_args
= (request
.args
, request
.form
)[request
.method
=='POST']
92 if 'lang' in request_args
:
93 # User explicitely demanded a language, normalize lower_uppercase
94 target_lang
= locale_to_lower_upper(request_args
['lang'])
96 elif 'target_lang' in request
.session
:
97 # TODO: Uh, ohh, this is never ever set anywhere?
98 target_lang
= request
.session
['target_lang']
100 # Pull the most acceptable language based on browser preferences
101 # This returns one of AVAILABLE_LOCALES which is aready case-normalized.
102 # Note: in our tests request.accept_languages is None, so we need
103 # to explicitely fallback to en here.
104 target_lang
= request
.accept_languages
.best_match(AVAILABLE_LOCALES
) \
111 def get_gettext_translation(locale
):
113 Return the gettext instance based on this locale
115 # Later on when we have plugins we may want to enable the
116 # multi-translations system they have so we can handle plugin
119 # TODO: fallback nicely on translations from pt_PT to pt if not
121 if locale
in SETUP_GETTEXTS
:
122 this_gettext
= SETUP_GETTEXTS
[locale
]
124 this_gettext
= gettext
.translation(
125 'mediagoblin', TRANSLATIONS_PATH
, [locale
], fallback
=True)
126 if localedata
.exists(locale
):
127 SETUP_GETTEXTS
[locale
] = this_gettext
131 def set_thread_locale(locale
):
132 """Set the current translation for this thread"""
133 mg_globals
.thread_scope
.translations
= get_gettext_translation(locale
)
136 def pass_to_ugettext(*args
, **kwargs
):
138 Pass a translation on to the appropriate ugettext method.
140 The reason we can't have a global ugettext method is because
141 mg_globals gets swapped out by the application per-request.
143 return mg_globals
.thread_scope
.translations
.ugettext(
146 def pass_to_ungettext(*args
, **kwargs
):
148 Pass a translation on to the appropriate ungettext method.
150 The reason we can't have a global ugettext method is because
151 mg_globals gets swapped out by the application per-request.
153 return mg_globals
.thread_scope
.translations
.ungettext(
157 def lazy_pass_to_ugettext(*args
, **kwargs
):
159 Lazily pass to ugettext.
161 This is useful if you have to define a translation on a module
162 level but you need it to not translate until the time that it's
163 used as a string. For example, in:
164 def func(self, message=_('Hello boys and girls'))
166 you would want to use the lazy version for _.
168 return ReallyLazyProxy(pass_to_ugettext
, *args
, **kwargs
)
171 def pass_to_ngettext(*args
, **kwargs
):
173 Pass a translation on to the appropriate ngettext method.
175 The reason we can't have a global ngettext method is because
176 mg_globals gets swapped out by the application per-request.
178 return mg_globals
.thread_scope
.translations
.ngettext(
182 def lazy_pass_to_ngettext(*args
, **kwargs
):
184 Lazily pass to ngettext.
186 This is useful if you have to define a translation on a module
187 level but you need it to not translate until the time that it's
190 return ReallyLazyProxy(pass_to_ngettext
, *args
, **kwargs
)
192 def lazy_pass_to_ungettext(*args
, **kwargs
):
194 Lazily pass to ungettext.
196 This is useful if you have to define a translation on a module
197 level but you need it to not translate until the time that it's
200 return ReallyLazyProxy(pass_to_ungettext
, *args
, **kwargs
)
203 def fake_ugettext_passthrough(string
):
205 Fake a ugettext call for extraction's sake ;)
207 In wtforms there's a separate way to define a method to translate
208 things... so we just need to mark up the text so that it can be
209 extracted, not so that it's actually run through gettext.