From 6ef75af50ecd9b71a5d9455f616c421b1d84b732 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Sun, 2 Dec 2012 00:29:30 +0100 Subject: [PATCH] Honor user's browser language (#558) Previously we would attempt to satisfy the user's first language preference, immediately falling back to english if that was not possible. Now, we will get the best match of the user's preferred languages. This requires storing the available locales on app startup, so we have mg_globals.available_locales ready to compare them against the list of preferred user languages. Signed-off-by: Sebastian Spaeth --- mediagoblin/app.py | 5 ++++- mediagoblin/init/__init__.py | 6 ++++++ mediagoblin/mg_globals.py | 2 ++ mediagoblin/tools/template.py | 4 ++-- mediagoblin/tools/translate.py | 28 +++++++++++++++++++--------- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/mediagoblin/app.py b/mediagoblin/app.py index de421aca..876ded4e 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -31,7 +31,7 @@ from mediagoblin.mg_globals import setup_globals from mediagoblin.init.celery import setup_celery_from_config from mediagoblin.init.plugins import setup_plugins from mediagoblin.init import (get_jinja_loader, get_staticdirector, - setup_global_and_app_config, setup_workbench, setup_database, + setup_global_and_app_config, setup_locales, setup_workbench, setup_database, setup_storage, setup_beaker_cache) from mediagoblin.tools.pluginapi import PluginManager @@ -68,6 +68,9 @@ class MediaGoblinApp(object): # Setup other connections / useful objects ########################################## + # load all available locales + setup_locales() + # Set up plugins -- need to do this early so that plugins can # affect startup. _log.info("Setting up plugins.") diff --git a/mediagoblin/init/__init__.py b/mediagoblin/init/__init__.py index 9b0025c9..88af377e 100644 --- a/mediagoblin/init/__init__.py +++ b/mediagoblin/init/__init__.py @@ -19,6 +19,7 @@ from beaker.util import parse_cache_config_options import jinja2 from mediagoblin.tools import staticdirect +from mediagoblin.tools.translate import get_available_locales from mediagoblin.init.config import ( read_mediagoblin_config, generate_validation_report) from mediagoblin import mg_globals @@ -37,6 +38,11 @@ class ImproperlyConfigured(Error): pass +def setup_locales(): + """Checks which language translations are available and sets them""" + setup_globals(available_locales=get_available_locales()) + + def setup_global_and_app_config(config_path): global_config, validation_result = read_mediagoblin_config(config_path) app_config = global_config['mediagoblin'] diff --git a/mediagoblin/mg_globals.py b/mediagoblin/mg_globals.py index 356a944d..646fbdbd 100644 --- a/mediagoblin/mg_globals.py +++ b/mediagoblin/mg_globals.py @@ -45,6 +45,8 @@ workbench_manager = None # A thread-local scope thread_scope = threading.local() +# a list of translated locales +available_locales = None # gettext (this will be populated on demand with gettext.Translations) thread_scope.translations = None diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py index 158d5321..6f603bab 100644 --- a/mediagoblin/tools/template.py +++ b/mediagoblin/tools/template.py @@ -20,7 +20,7 @@ from babel.localedata import exists from mediagoblin import mg_globals from mediagoblin import messages from mediagoblin.tools import common -from mediagoblin.tools.translate import setup_gettext +from mediagoblin.tools.translate import get_gettext_translation from mediagoblin.meddleware.csrf import render_csrf_form_token @@ -34,7 +34,7 @@ def get_jinja_env(template_loader, locale): (In the future we may have another system for providing theming; for now this is good enough.) """ - setup_gettext(locale) + mg_globals.thread_scope.translations = get_gettext_translation(locale) # If we have a jinja environment set up with this locale, just # return that one. diff --git a/mediagoblin/tools/translate.py b/mediagoblin/tools/translate.py index ce670451..b6b7a527 100644 --- a/mediagoblin/tools/translate.py +++ b/mediagoblin/tools/translate.py @@ -16,7 +16,9 @@ import gettext import pkg_resources -from babel.localedata import exists + + +from babel import localedata from babel.support import LazyProxy from mediagoblin import mg_globals @@ -30,6 +32,15 @@ TRANSLATIONS_PATH = pkg_resources.resource_filename( 'mediagoblin', 'i18n') +def get_available_locales(): + """Return a list of locales for which we have translations""" + locales=[] + for locale in localedata.list(): + if gettext.find('mediagoblin', TRANSLATIONS_PATH, [locale]): + locales.append(locale) + return locales + + def locale_to_lower_upper(locale): """ Take a locale, regardless of style, and format it like "en_US" @@ -76,15 +87,15 @@ def get_locale_from_request(request): # TODO: We need a list of available locales, and match with the list # of accepted locales, and serve the best available locale rather than # the most preferred, or fall back to 'en' immediately. - target_lang = request.accept_languages.best - - return locale_to_lower_upper(target_lang) + target_lang = request.accept_languages.best_match( + mg_globals.available_locales) + return locale_to_lower_upper(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 @@ -97,10 +108,9 @@ def setup_gettext(locale): else: this_gettext = gettext.translation( 'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True) - if exists(locale): + if localedata.exists(locale): SETUP_GETTEXTS[locale] = this_gettext - - mg_globals.thread_scope.translations = this_gettext + return this_gettext def pass_to_ugettext(*args, **kwargs): -- 2.25.1