X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=mediagoblin%2Ftools%2Ftranslate.py;h=b20e57d1ea2791e1e9773ed95d532cc41e5a8c7b;hb=be49edba0516eb4ebfbf4773bd09e07f665c8254;hp=2c2a710d3ef3b3ae97e5632aabd8ec41e4de2874;hpb=ae3bc7fabf8e0abb5f3d8b6534ca451890bbe90b;p=mediagoblin.git diff --git a/mediagoblin/tools/translate.py b/mediagoblin/tools/translate.py index 2c2a710d..b20e57d1 100644 --- a/mediagoblin/tools/translate.py +++ b/mediagoblin/tools/translate.py @@ -1,5 +1,5 @@ # 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 @@ -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 @@ -25,14 +27,40 @@ 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) @@ -46,7 +74,7 @@ def locale_to_lower_upper(locale): 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) @@ -57,37 +85,32 @@ def locale_to_lower_lower(locale): 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 @@ -95,21 +118,19 @@ def setup_gettext(locale): # 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): @@ -119,7 +140,17 @@ 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) @@ -129,9 +160,12 @@ def lazy_pass_to_ugettext(*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): @@ -141,7 +175,7 @@ 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) @@ -153,7 +187,17 @@ def lazy_pass_to_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):