App Engine Python SDK version 1.7.4 (2)
[gae.git] / python / lib / django_1_4 / django / views / i18n.py
blob140dc543e3d5220c8ef7bce5d4f0367f7b8b1990
1 import os
2 import gettext as gettext_module
4 from django import http
5 from django.conf import settings
6 from django.utils import importlib
7 from django.utils.translation import check_for_language, activate, to_locale, get_language
8 from django.utils.text import javascript_quote
9 from django.utils.encoding import smart_unicode
10 from django.utils.formats import get_format_modules, get_format
12 def set_language(request):
13 """
14 Redirect to a given url while setting the chosen language in the
15 session or cookie. The url and the language code need to be
16 specified in the request parameters.
18 Since this view changes how the user will see the rest of the site, it must
19 only be accessed as a POST request. If called as a GET request, it will
20 redirect to the page in the request (the 'next' parameter) without changing
21 any state.
22 """
23 next = request.REQUEST.get('next', None)
24 if not next:
25 next = request.META.get('HTTP_REFERER', None)
26 if not next:
27 next = '/'
28 response = http.HttpResponseRedirect(next)
29 if request.method == 'POST':
30 lang_code = request.POST.get('language', None)
31 if lang_code and check_for_language(lang_code):
32 if hasattr(request, 'session'):
33 request.session['django_language'] = lang_code
34 else:
35 response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
36 return response
38 def get_formats():
39 """
40 Returns all formats strings required for i18n to work
41 """
42 FORMAT_SETTINGS = (
43 'DATE_FORMAT', 'DATETIME_FORMAT', 'TIME_FORMAT',
44 'YEAR_MONTH_FORMAT', 'MONTH_DAY_FORMAT', 'SHORT_DATE_FORMAT',
45 'SHORT_DATETIME_FORMAT', 'FIRST_DAY_OF_WEEK', 'DECIMAL_SEPARATOR',
46 'THOUSAND_SEPARATOR', 'NUMBER_GROUPING',
47 'DATE_INPUT_FORMATS', 'TIME_INPUT_FORMATS', 'DATETIME_INPUT_FORMATS'
49 result = {}
50 for module in [settings] + get_format_modules(reverse=True):
51 for attr in FORMAT_SETTINGS:
52 result[attr] = get_format(attr)
53 src = []
54 for k, v in result.items():
55 if isinstance(v, (basestring, int)):
56 src.append("formats['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(smart_unicode(v))))
57 elif isinstance(v, (tuple, list)):
58 v = [javascript_quote(smart_unicode(value)) for value in v]
59 src.append("formats['%s'] = ['%s'];\n" % (javascript_quote(k), "', '".join(v)))
60 return ''.join(src)
62 NullSource = """
63 /* gettext identity library */
65 function gettext(msgid) { return msgid; }
66 function ngettext(singular, plural, count) { return (count == 1) ? singular : plural; }
67 function gettext_noop(msgid) { return msgid; }
68 function pgettext(context, msgid) { return msgid; }
69 function npgettext(context, singular, plural, count) { return (count == 1) ? singular : plural; }
70 """
72 LibHead = """
73 /* gettext library */
75 var catalog = new Array();
76 """
78 LibFoot = """
80 function gettext(msgid) {
81 var value = catalog[msgid];
82 if (typeof(value) == 'undefined') {
83 return msgid;
84 } else {
85 return (typeof(value) == 'string') ? value : value[0];
89 function ngettext(singular, plural, count) {
90 value = catalog[singular];
91 if (typeof(value) == 'undefined') {
92 return (count == 1) ? singular : plural;
93 } else {
94 return value[pluralidx(count)];
98 function gettext_noop(msgid) { return msgid; }
100 function pgettext(context, msgid) {
101 var value = gettext(context + '\x04' + msgid);
102 if (value.indexOf('\x04') != -1) {
103 value = msgid;
105 return value;
108 function npgettext(context, singular, plural, count) {
109 var value = ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
110 if (value.indexOf('\x04') != -1) {
111 value = ngettext(singular, plural, count);
113 return value;
117 LibFormatHead = """
118 /* formatting library */
120 var formats = new Array();
124 LibFormatFoot = """
125 function get_format(format_type) {
126 var value = formats[format_type];
127 if (typeof(value) == 'undefined') {
128 return msgid;
129 } else {
130 return value;
135 SimplePlural = """
136 function pluralidx(count) { return (count == 1) ? 0 : 1; }
139 InterPolate = r"""
140 function interpolate(fmt, obj, named) {
141 if (named) {
142 return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
143 } else {
144 return fmt.replace(/%s/g, function(match){return String(obj.shift())});
149 PluralIdx = r"""
150 function pluralidx(n) {
151 var v=%s;
152 if (typeof(v) == 'boolean') {
153 return v ? 1 : 0;
154 } else {
155 return v;
160 def null_javascript_catalog(request, domain=None, packages=None):
162 Returns "identity" versions of the JavaScript i18n functions -- i.e.,
163 versions that don't actually do anything.
165 src = [NullSource, InterPolate, LibFormatHead, get_formats(), LibFormatFoot]
166 return http.HttpResponse(''.join(src), 'text/javascript')
168 def javascript_catalog(request, domain='djangojs', packages=None):
170 Returns the selected language catalog as a javascript library.
172 Receives the list of packages to check for translations in the
173 packages parameter either from an infodict or as a +-delimited
174 string from the request. Default is 'django.conf'.
176 Additionally you can override the gettext domain for this view,
177 but usually you don't want to do that, as JavaScript messages
178 go to the djangojs domain. But this might be needed if you
179 deliver your JavaScript source from Django templates.
181 if request.GET:
182 if 'language' in request.GET:
183 if check_for_language(request.GET['language']):
184 activate(request.GET['language'])
185 if packages is None:
186 packages = ['django.conf']
187 if isinstance(packages, basestring):
188 packages = packages.split('+')
189 packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS]
190 default_locale = to_locale(settings.LANGUAGE_CODE)
191 locale = to_locale(get_language())
192 t = {}
193 paths = []
194 en_selected = locale.startswith('en')
195 en_catalog_missing = True
196 # paths of requested packages
197 for package in packages:
198 p = importlib.import_module(package)
199 path = os.path.join(os.path.dirname(p.__file__), 'locale')
200 paths.append(path)
201 # add the filesystem paths listed in the LOCALE_PATHS setting
202 paths.extend(list(reversed(settings.LOCALE_PATHS)))
203 # first load all english languages files for defaults
204 for path in paths:
205 try:
206 catalog = gettext_module.translation(domain, path, ['en'])
207 t.update(catalog._catalog)
208 except IOError:
209 pass
210 else:
211 # 'en' is the selected language and at least one of the packages
212 # listed in `packages` has an 'en' catalog
213 if en_selected:
214 en_catalog_missing = False
215 # next load the settings.LANGUAGE_CODE translations if it isn't english
216 if default_locale != 'en':
217 for path in paths:
218 try:
219 catalog = gettext_module.translation(domain, path, [default_locale])
220 except IOError:
221 catalog = None
222 if catalog is not None:
223 t.update(catalog._catalog)
224 # last load the currently selected language, if it isn't identical to the default.
225 if locale != default_locale:
226 # If the currently selected language is English but it doesn't have a
227 # translation catalog (presumably due to being the language translated
228 # from) then a wrong language catalog might have been loaded in the
229 # previous step. It needs to be discarded.
230 if en_selected and en_catalog_missing:
231 t = {}
232 else:
233 locale_t = {}
234 for path in paths:
235 try:
236 catalog = gettext_module.translation(domain, path, [locale])
237 except IOError:
238 catalog = None
239 if catalog is not None:
240 locale_t.update(catalog._catalog)
241 if locale_t:
242 t = locale_t
243 src = [LibHead]
244 plural = None
245 if '' in t:
246 for l in t[''].split('\n'):
247 if l.startswith('Plural-Forms:'):
248 plural = l.split(':',1)[1].strip()
249 if plural is not None:
250 # this should actually be a compiled function of a typical plural-form:
251 # Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
252 plural = [el.strip() for el in plural.split(';') if el.strip().startswith('plural=')][0].split('=',1)[1]
253 src.append(PluralIdx % plural)
254 else:
255 src.append(SimplePlural)
256 csrc = []
257 pdict = {}
258 for k, v in t.items():
259 if k == '':
260 continue
261 if isinstance(k, basestring):
262 csrc.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(v)))
263 elif isinstance(k, tuple):
264 if k[0] not in pdict:
265 pdict[k[0]] = k[1]
266 else:
267 pdict[k[0]] = max(k[1], pdict[k[0]])
268 csrc.append("catalog['%s'][%d] = '%s';\n" % (javascript_quote(k[0]), k[1], javascript_quote(v)))
269 else:
270 raise TypeError(k)
271 csrc.sort()
272 for k, v in pdict.items():
273 src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1))))
274 src.extend(csrc)
275 src.append(LibFoot)
276 src.append(InterPolate)
277 src.append(LibFormatHead)
278 src.append(get_formats())
279 src.append(LibFormatFoot)
280 src = ''.join(src)
281 return http.HttpResponse(src, 'text/javascript')