diff -r 57b4279d8c4e -r 03e267d67478 app/django/views/i18n.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/django/views/i18n.py Fri Jul 18 18:22:23 2008 +0000 @@ -0,0 +1,193 @@ +from django import http +from django.utils.translation import check_for_language, activate, to_locale, get_language +from django.utils.text import javascript_quote +from django.conf import settings +import os +import gettext as gettext_module + +def set_language(request): + """ + Redirect to a given url while setting the chosen language in the + session or cookie. The url and the language code need to be + specified in the request parameters. + + Since this view changes how the user will see the rest of the site, it must + only be accessed as a POST request. If called as a GET request, it will + redirect to the page in the request (the 'next' parameter) without changing + any state. + """ + next = request.REQUEST.get('next', None) + if not next: + next = request.META.get('HTTP_REFERER', None) + if not next: + next = '/' + response = http.HttpResponseRedirect(next) + if request.method == 'POST': + lang_code = request.POST.get('language', None) + if lang_code and check_for_language(lang_code): + if hasattr(request, 'session'): + request.session['django_language'] = lang_code + else: + response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code) + return response + +NullSource = """ +/* gettext identity library */ + +function gettext(msgid) { return msgid; } +function ngettext(singular, plural, count) { return (count == 1) ? singular : plural; } +function gettext_noop(msgid) { return msgid; } +""" + +LibHead = """ +/* gettext library */ + +var catalog = new Array(); +""" + +LibFoot = """ + +function gettext(msgid) { + var value = catalog[msgid]; + if (typeof(value) == 'undefined') { + return msgid; + } else { + return (typeof(value) == 'string') ? value : value[0]; + } +} + +function ngettext(singular, plural, count) { + value = catalog[singular]; + if (typeof(value) == 'undefined') { + return (count == 1) ? singular : plural; + } else { + return value[pluralidx(count)]; + } +} + +function gettext_noop(msgid) { return msgid; } +""" + +SimplePlural = """ +function pluralidx(count) { return (count == 1) ? 0 : 1; } +""" + +InterPolate = r""" +function interpolate(fmt, obj, named) { + if (named) { + return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])}); + } else { + return fmt.replace(/%s/g, function(match){return String(obj.shift())}); + } +} +""" + +PluralIdx = r""" +function pluralidx(n) { + var v=%s; + if (typeof(v) == 'boolean') { + return v ? 1 : 0; + } else { + return v; + } +} +""" + +def null_javascript_catalog(request, domain=None, packages=None): + """ + Returns "identity" versions of the JavaScript i18n functions -- i.e., + versions that don't actually do anything. + """ + return http.HttpResponse(NullSource + InterPolate, 'text/javascript') + +def javascript_catalog(request, domain='djangojs', packages=None): + """ + Returns the selected language catalog as a javascript library. + + Receives the list of packages to check for translations in the + packages parameter either from an infodict or as a +-delimited + string from the request. Default is 'django.conf'. + + Additionally you can override the gettext domain for this view, + but usually you don't want to do that, as JavaScript messages + go to the djangojs domain. But this might be needed if you + deliver your JavaScript source from Django templates. + """ + if request.GET: + if 'language' in request.GET: + if check_for_language(request.GET['language']): + activate(request.GET['language']) + if packages is None: + packages = ['django.conf'] + if type(packages) in (str, unicode): + packages = packages.split('+') + packages = [p for p in packages if p == 'django.conf' or p in settings.INSTALLED_APPS] + default_locale = to_locale(settings.LANGUAGE_CODE) + locale = to_locale(get_language()) + t = {} + paths = [] + # first load all english languages files for defaults + for package in packages: + p = __import__(package, {}, {}, ['']) + path = os.path.join(os.path.dirname(p.__file__), 'locale') + paths.append(path) + try: + catalog = gettext_module.translation(domain, path, ['en']) + t.update(catalog._catalog) + except IOError: + # 'en' catalog was missing. This is harmless. + pass + # next load the settings.LANGUAGE_CODE translations if it isn't english + if default_locale != 'en': + for path in paths: + try: + catalog = gettext_module.translation(domain, path, [default_locale]) + except IOError: + catalog = None + if catalog is not None: + t.update(catalog._catalog) + # last load the currently selected language, if it isn't identical to the default. + if locale != default_locale: + for path in paths: + try: + catalog = gettext_module.translation(domain, path, [locale]) + except IOError: + catalog = None + if catalog is not None: + t.update(catalog._catalog) + src = [LibHead] + plural = None + if '' in t: + for l in t[''].split('\n'): + if l.startswith('Plural-Forms:'): + plural = l.split(':',1)[1].strip() + if plural is not None: + # this should actually be a compiled function of a typical plural-form: + # 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; + plural = [el.strip() for el in plural.split(';') if el.strip().startswith('plural=')][0].split('=',1)[1] + src.append(PluralIdx % plural) + else: + src.append(SimplePlural) + csrc = [] + pdict = {} + for k, v in t.items(): + if k == '': + continue + if type(k) in (str, unicode): + csrc.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(v))) + elif type(k) == tuple: + if k[0] not in pdict: + pdict[k[0]] = k[1] + else: + pdict[k[0]] = max(k[1], pdict[k[0]]) + csrc.append("catalog['%s'][%d] = '%s';\n" % (javascript_quote(k[0]), k[1], javascript_quote(v))) + else: + raise TypeError, k + csrc.sort() + for k,v in pdict.items(): + src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1)))) + src.extend(csrc) + src.append(LibFoot) + src.append(InterPolate) + src = ''.join(src) + return http.HttpResponse(src, 'text/javascript')