Moving thingiview.js into extlib/
[mediagoblin.git] / mediagoblin / tools / translate.py
CommitLineData
ae3bc7fa 1# GNU MediaGoblin -- federated, autonomous media hosting
cf29e8a8 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
ae3bc7fa
AW
3#
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.
8#
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.
13#
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/>.
16
17import gettext
18import pkg_resources
6ef75af5
SS
19
20
21from babel import localedata
ae3bc7fa
AW
22from babel.support import LazyProxy
23
24from mediagoblin import mg_globals
25
26###################
27# Translation tools
28###################
29
826919c9 30AVAILABLE_LOCALES = None
ae3bc7fa
AW
31TRANSLATIONS_PATH = pkg_resources.resource_filename(
32 'mediagoblin', 'i18n')
33
34
826919c9
SS
35def 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
6ef75af5
SS
39 for locale in localedata.list():
40 if gettext.find('mediagoblin', TRANSLATIONS_PATH, [locale]):
41 locales.append(locale)
826919c9 42 AVAILABLE_LOCALES = locales
6ef75af5
SS
43
44
ae3bc7fa
AW
45def locale_to_lower_upper(locale):
46 """
7b9f9d1e 47 Take a locale, regardless of style, and format it like "en_US"
ae3bc7fa
AW
48 """
49 if '-' in locale:
50 lang, country = locale.split('-', 1)
51 return '%s_%s' % (lang.lower(), country.upper())
52 elif '_' in locale:
53 lang, country = locale.split('_', 1)
54 return '%s_%s' % (lang.lower(), country.upper())
55 else:
56 return locale.lower()
57
58
59def locale_to_lower_lower(locale):
60 """
9d3e56d5 61 Take a locale, regardless of style, and format it like "en_us"
ae3bc7fa
AW
62 """
63 if '_' in locale:
64 lang, country = locale.split('_', 1)
65 return '%s-%s' % (lang.lower(), country.lower())
66 else:
67 return locale.lower()
68
69
70def get_locale_from_request(request):
71 """
72 Figure out what target language is most appropriate based on the
73 request
74 """
826919c9 75 global AVAILABLE_LOCALES
7b9f9d1e 76 request_form = request.args or request.form
ae3bc7fa
AW
77
78 if request_form.has_key('lang'):
7b9f9d1e
SS
79 # User explicitely demanded a language
80 target_lang = request_form['lang']
ae3bc7fa 81
7b9f9d1e
SS
82 elif 'target_lang' in request.session:
83 # TODO: Uh, ohh, this is never ever set anywhere?
ae3bc7fa 84 target_lang = request.session['target_lang']
ae3bc7fa 85 else:
7b9f9d1e
SS
86 # Pull the first acceptable language or English
87 # This picks your favorite browser lingo, falling back to 'en'
88
89 # TODO: We need a list of available locales, and match with the list
90 # of accepted locales, and serve the best available locale rather than
91 # the most preferred, or fall back to 'en' immediately.
826919c9 92 target_lang = request.accept_languages.best_match(AVAILABLE_LOCALES)
e4e7fbee
CAW
93
94 return locale_to_lower_upper(target_lang)
ae3bc7fa
AW
95
96SETUP_GETTEXTS = {}
97
6ef75af5 98def get_gettext_translation(locale):
ae3bc7fa 99 """
6ef75af5 100 Return the gettext instance based on this locale
ae3bc7fa
AW
101 """
102 # Later on when we have plugins we may want to enable the
103 # multi-translations system they have so we can handle plugin
104 # translations too
105
106 # TODO: fallback nicely on translations from pt_PT to pt if not
107 # available, etc.
c80982c7 108 if locale in SETUP_GETTEXTS:
ae3bc7fa
AW
109 this_gettext = SETUP_GETTEXTS[locale]
110 else:
111 this_gettext = gettext.translation(
112 'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True)
6ef75af5 113 if localedata.exists(locale):
ae3bc7fa 114 SETUP_GETTEXTS[locale] = this_gettext
6ef75af5 115 return this_gettext
ae3bc7fa
AW
116
117
ae3bc7fa
AW
118def pass_to_ugettext(*args, **kwargs):
119 """
120 Pass a translation on to the appropriate ugettext method.
121
122 The reason we can't have a global ugettext method is because
123 mg_globals gets swapped out by the application per-request.
124 """
c80982c7 125 return mg_globals.thread_scope.translations.ugettext(
ae3bc7fa
AW
126 *args, **kwargs)
127
128
129def lazy_pass_to_ugettext(*args, **kwargs):
130 """
131 Lazily pass to ugettext.
132
133 This is useful if you have to define a translation on a module
134 level but you need it to not translate until the time that it's
135 used as a string.
136 """
137 return LazyProxy(pass_to_ugettext, *args, **kwargs)
138
139
140def pass_to_ngettext(*args, **kwargs):
141 """
142 Pass a translation on to the appropriate ngettext method.
143
144 The reason we can't have a global ngettext method is because
145 mg_globals gets swapped out by the application per-request.
146 """
c80982c7 147 return mg_globals.thread_scope.translations.ngettext(
ae3bc7fa
AW
148 *args, **kwargs)
149
150
151def lazy_pass_to_ngettext(*args, **kwargs):
152 """
153 Lazily pass to ngettext.
154
155 This is useful if you have to define a translation on a module
156 level but you need it to not translate until the time that it's
157 used as a string.
158 """
159 return LazyProxy(pass_to_ngettext, *args, **kwargs)
160
161
162def fake_ugettext_passthrough(string):
163 """
164 Fake a ugettext call for extraction's sake ;)
165
166 In wtforms there's a separate way to define a method to translate
167 things... so we just need to mark up the text so that it can be
168 extracted, not so that it's actually run through gettext.
169 """
170 return string