# GNU MediaGoblin -- federated, autonomous media hosting
-# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS.
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
import gettext
import pkg_resources
-from babel.localedata import exists
+
+
+from babel import localedata
from babel.support import LazyProxy
from mediagoblin import mg_globals
# Translation tools
###################
-
+AVAILABLE_LOCALES = None
TRANSLATIONS_PATH = pkg_resources.resource_filename(
'mediagoblin', 'i18n')
+def set_available_locales():
+ """Set available locales for which we have translations"""
+ global AVAILABLE_LOCALES
+ locales=['en', 'en_US'] # these are available without translations
+ for locale in localedata.list():
+ if gettext.find('mediagoblin', TRANSLATIONS_PATH, [locale]):
+ locales.append(locale)
+ AVAILABLE_LOCALES = locales
+
+
+class ReallyLazyProxy(LazyProxy):
+ """
+ Like LazyProxy, except that it doesn't cache the value ;)
+ """
+ @property
+ def value(self):
+ return self._func(*self._args, **self._kwargs)
+
+ def __repr__(self):
+ return "<%s for %s(%r, %r)>" % (
+ self.__class__.__name__,
+ self._func,
+ self._args,
+ self._kwargs)
+
+
def locale_to_lower_upper(locale):
"""
- Take a locale, regardless of style, and format it like "en-us"
+ Take a locale, regardless of style, and format it like "en_US"
"""
if '-' in locale:
lang, country = locale.split('-', 1)
def locale_to_lower_lower(locale):
"""
- Take a locale, regardless of style, and format it like "en_US"
+ Take a locale, regardless of style, and format it like "en_us"
"""
if '_' in locale:
lang, country = locale.split('_', 1)
def get_locale_from_request(request):
"""
- Figure out what target language is most appropriate based on the
- request
+ Return most appropriate language based on prefs/request request
"""
- request_form = request.GET or request.POST
+ request_args = (request.args, request.form)[request.method=='POST']
- if request_form.has_key('lang'):
- return locale_to_lower_upper(request_form['lang'])
+ if 'lang' in request_args:
+ # User explicitely demanded a language, normalize lower_uppercase
+ target_lang = locale_to_lower_upper(request_args['lang'])
- accept_lang_matches = request.accept_language.best_matches()
-
- # Your routing can explicitly specify a target language
- matchdict = request.matchdict or {}
-
- if matchdict.has_key('locale'):
- target_lang = matchdict['locale']
- elif request.session.has_key('target_lang'):
+ elif 'target_lang' in request.session:
+ # TODO: Uh, ohh, this is never ever set anywhere?
target_lang = request.session['target_lang']
- # Pull the first acceptable language
- elif accept_lang_matches:
- target_lang = accept_lang_matches[0]
- # Fall back to English
else:
- target_lang = 'en'
+ # Pull the most acceptable language based on browser preferences
+ # This returns one of AVAILABLE_LOCALES which is aready case-normalized.
+ # Note: in our tests request.accept_languages is None, so we need
+ # to explicitely fallback to en here.
+ target_lang = request.accept_languages.best_match(AVAILABLE_LOCALES) \
+ or "en_US"
- return locale_to_lower_upper(target_lang)
+ return target_lang
SETUP_GETTEXTS = {}
-def setup_gettext(locale):
+def get_gettext_translation(locale):
"""
- Setup the gettext instance based on this locale
+ Return the gettext instance based on this locale
"""
# Later on when we have plugins we may want to enable the
# multi-translations system they have so we can handle plugin
# TODO: fallback nicely on translations from pt_PT to pt if not
# available, etc.
- if SETUP_GETTEXTS.has_key(locale):
+ if locale in SETUP_GETTEXTS:
this_gettext = SETUP_GETTEXTS[locale]
else:
this_gettext = gettext.translation(
'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True)
- if exists(locale):
+ if localedata.exists(locale):
SETUP_GETTEXTS[locale] = this_gettext
+ return this_gettext
- mg_globals.setup_globals(
- translations=this_gettext)
-
-# Force en to be setup before anything else so that
-# mg_globals.translations is never None
-setup_gettext('en')
+def set_thread_locale(locale):
+ """Set the current translation for this thread"""
+ mg_globals.thread_scope.translations = get_gettext_translation(locale)
def pass_to_ugettext(*args, **kwargs):
The reason we can't have a global ugettext method is because
mg_globals gets swapped out by the application per-request.
"""
- return mg_globals.translations.ugettext(
+ return mg_globals.thread_scope.translations.ugettext(
+ *args, **kwargs)
+
+def pass_to_ungettext(*args, **kwargs):
+ """
+ Pass a translation on to the appropriate ungettext method.
+
+ The reason we can't have a global ugettext method is because
+ mg_globals gets swapped out by the application per-request.
+ """
+ return mg_globals.thread_scope.translations.ungettext(
*args, **kwargs)
This is useful if you have to define a translation on a module
level but you need it to not translate until the time that it's
- used as a string.
+ used as a string. For example, in:
+ def func(self, message=_('Hello boys and girls'))
+
+ you would want to use the lazy version for _.
"""
- return LazyProxy(pass_to_ugettext, *args, **kwargs)
+ return ReallyLazyProxy(pass_to_ugettext, *args, **kwargs)
def pass_to_ngettext(*args, **kwargs):
The reason we can't have a global ngettext method is because
mg_globals gets swapped out by the application per-request.
"""
- return mg_globals.translations.ngettext(
+ return mg_globals.thread_scope.translations.ngettext(
*args, **kwargs)
level but you need it to not translate until the time that it's
used as a string.
"""
- return LazyProxy(pass_to_ngettext, *args, **kwargs)
+ return ReallyLazyProxy(pass_to_ngettext, *args, **kwargs)
+
+def lazy_pass_to_ungettext(*args, **kwargs):
+ """
+ Lazily pass to ungettext.
+
+ This is useful if you have to define a translation on a module
+ level but you need it to not translate until the time that it's
+ used as a string.
+ """
+ return ReallyLazyProxy(pass_to_ungettext, *args, **kwargs)
def fake_ugettext_passthrough(string):