Commit | Line | Data |
---|---|---|
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 | ||
17 | import gettext | |
18 | import pkg_resources | |
6ef75af5 SS |
19 | |
20 | ||
21 | from babel import localedata | |
ae3bc7fa AW |
22 | from babel.support import LazyProxy |
23 | ||
24 | from mediagoblin import mg_globals | |
25 | ||
26 | ################### | |
27 | # Translation tools | |
28 | ################### | |
29 | ||
826919c9 | 30 | AVAILABLE_LOCALES = None |
ae3bc7fa AW |
31 | TRANSLATIONS_PATH = pkg_resources.resource_filename( |
32 | 'mediagoblin', 'i18n') | |
33 | ||
34 | ||
826919c9 SS |
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 | |
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 |
45 | def 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 | ||
59 | def 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 | ||
70 | def get_locale_from_request(request): | |
71 | """ | |
c39b9afc | 72 | Return most appropriate language based on prefs/request request |
ae3bc7fa | 73 | """ |
c39b9afc | 74 | request_args = (request.args, request.form)[request.method=='POST'] |
ae3bc7fa | 75 | |
04453ccf | 76 | if 'lang' in request_args: |
c39b9afc SS |
77 | # User explicitely demanded a language, normalize lower_uppercase |
78 | target_lang = locale_to_lower_upper(request_args['lang']) | |
ae3bc7fa | 79 | |
7b9f9d1e SS |
80 | elif 'target_lang' in request.session: |
81 | # TODO: Uh, ohh, this is never ever set anywhere? | |
ae3bc7fa | 82 | target_lang = request.session['target_lang'] |
ae3bc7fa | 83 | else: |
c39b9afc SS |
84 | # Pull the most acceptable language based on browser preferences |
85 | # This returns one of AVAILABLE_LOCALES which is aready case-normalized. | |
86 | # Note: in our tests request.accept_languages is None, so we need | |
87 | # to explicitely fallback to en here. | |
88 | target_lang = request.accept_languages.best_match(AVAILABLE_LOCALES) \ | |
89 | or "en_US" | |
90 | ||
91 | return target_lang | |
ae3bc7fa AW |
92 | |
93 | SETUP_GETTEXTS = {} | |
94 | ||
6ef75af5 | 95 | def get_gettext_translation(locale): |
ae3bc7fa | 96 | """ |
6ef75af5 | 97 | Return the gettext instance based on this locale |
ae3bc7fa AW |
98 | """ |
99 | # Later on when we have plugins we may want to enable the | |
100 | # multi-translations system they have so we can handle plugin | |
101 | # translations too | |
102 | ||
103 | # TODO: fallback nicely on translations from pt_PT to pt if not | |
104 | # available, etc. | |
c80982c7 | 105 | if locale in SETUP_GETTEXTS: |
ae3bc7fa AW |
106 | this_gettext = SETUP_GETTEXTS[locale] |
107 | else: | |
108 | this_gettext = gettext.translation( | |
109 | 'mediagoblin', TRANSLATIONS_PATH, [locale], fallback=True) | |
6ef75af5 | 110 | if localedata.exists(locale): |
ae3bc7fa | 111 | SETUP_GETTEXTS[locale] = this_gettext |
6ef75af5 | 112 | return this_gettext |
ae3bc7fa AW |
113 | |
114 | ||
ae3bc7fa AW |
115 | def pass_to_ugettext(*args, **kwargs): |
116 | """ | |
117 | Pass a translation on to the appropriate ugettext method. | |
118 | ||
119 | The reason we can't have a global ugettext method is because | |
120 | mg_globals gets swapped out by the application per-request. | |
121 | """ | |
c80982c7 | 122 | return mg_globals.thread_scope.translations.ugettext( |
ae3bc7fa AW |
123 | *args, **kwargs) |
124 | ||
125 | ||
126 | def lazy_pass_to_ugettext(*args, **kwargs): | |
127 | """ | |
128 | Lazily pass to ugettext. | |
129 | ||
130 | This is useful if you have to define a translation on a module | |
131 | level but you need it to not translate until the time that it's | |
c843de8a SS |
132 | used as a string. For example, in: |
133 | def func(self, message=_('Hello boys and girls')) | |
134 | ||
135 | you would want to use the lazy version for _. | |
ae3bc7fa AW |
136 | """ |
137 | return LazyProxy(pass_to_ugettext, *args, **kwargs) | |
138 | ||
139 | ||
140 | def 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 | ||
151 | def 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 | ||
162 | def 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 |