diff options
| author | Georg Bauer <gb@hugo.westfalen.de> | 2005-09-29 17:01:05 +0000 |
|---|---|---|
| committer | Georg Bauer <gb@hugo.westfalen.de> | 2005-09-29 17:01:05 +0000 |
| commit | 98d74306099d73a4e6765bf677207b240f82dd16 (patch) | |
| tree | 062de72e915bce4475f5bf7470970cfb9cbee74e /django/utils | |
| parent | a60b2050c643314996434117892136fba8adb487 (diff) | |
i18n patch - references #65
git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@726 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/utils')
| -rw-r--r-- | django/utils/translation.py | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/django/utils/translation.py b/django/utils/translation.py new file mode 100644 index 0000000000..293c7ed261 --- /dev/null +++ b/django/utils/translation.py @@ -0,0 +1,195 @@ +"translation helper functions" + +import os +import gettext as gettext_module + +try: + import threading + hasThreads = True +except ImportError: + hasThreads = False + +if hasThreads: + currentThread = threading.currentThread +else: + def currentThread(): + return 'no threading' + +# translations are cached in a dictionary for +# every language+app tuple. The active translations +# are stored by threadid to make them thread local. +_translations = {} +_active = {} + +# the default translation is based on the settings file +_default = None + +# this is a cache for accept-header to translation +# object mappings to prevent the accept parser to +# run multiple times for one user +_accepted = {} + +class DjangoTranslation(gettext_module.GNUTranslations): + """ + This class sets up the GNUTranslations context with + regard to output charset. Django allways uses utf-8 + as the output charset. + """ + + def __init__(self, *args, **kw): + gettext_module.GNUTranslations.__init__(self, *args, **kw) + self.__charset = self.charset() + self.set_output_charset('utf-8') + self.__app = '?.?.?' + self.__language = '??' + + def set_app_and_language(self, app, language): + self.__app = app + self.__language = language + + def __repr__(self): + return "<DjangoTranslation app:%s lang:%s>" % (self.__app, self.__language) + +def translation(appname, language): + """ + This function returns a translation object. + app must be the fully qualified name of the + application. + + This function will first look into the app + messages directory for the django message file, + then in the project messages directory for the + django message file and last in the global + messages directory for the django message file. + """ + + t = _translations.get((appname, language), None) + if t is not None: + return t + + from django.conf import settings + + globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale') + + try: + t = gettext_module.translation('django', globalpath, [language, settings.LANGUAGE_CODE], DjangoTranslation) + t.set_app_and_language(appname, language) + except IOError: t = gettext_module.NullTranslations() + _translations[(appname, language)] = t + + if appname != '*': + parts = appname.split('.') + project = __import__(parts[0], {}, {}, []) + app = __import__(appname, {}, {}, ['views']) + + apppath = os.path.join(os.path.dirname(app.__file__), 'locale') + projectpath = os.path.join(os.path.dirname(project.__file__), 'locale') + + try: + t = gettext_module.translation('django', projectpath, [language, settings.LANGUAGE_CODE], DjangoTranslation) + t.set_app_and_language(appname, language) + except IOError: t = None + if t is not None: + t.add_fallback(_translations[(appname, language)]) + _translations[(appname, language)] = t + + try: + t = gettext_module.translation('django', apppath, [language, settings.LANGUAGE_CODE], DjangoTranslation) + t.set_app_and_language(appname, language) + except IOError: t = None + if t is not None: + t.add_fallback(_translations[(appname, language)]) + _translations[(appname, language)] = t + + return _translations[(appname, language)] + +def activate(appname, language): + """ + This function fetches the translation object for a given + tuple of application name and language and installs it as + the current translation object for the current thread. + """ + t = translation(appname, language) + _active[currentThread()] = t + +def deactivate(): + """ + This function deinstalls the currently active translation + object so that further _ calls will resolve against the + default translation object, again. + """ + del _active[currentThread()] + +def gettext(message): + """ + This function will be patched into the builtins module to + provide the _ helper function. It will use the current + thread as a discriminator to find the translation object + to use. If no current translation is activated, the + message will be run through the default translation + object. + """ + global _default, _active + + t = _active.get(currentThread(), None) + if t is not None: + return t.gettext(message) + if _default is None: + from django.conf import settings + _default = translation('*', settings.LANGUAGE_CODE) + return _default.gettext(message) + +def get_language_from_request(request): + """ + analyze the request to find what language the user + wants the system to show. + """ + global _accepted + + if hasattr(request, 'session'): + lang = getattr(request.session, 'django_language', None) + if lang is not None: + return lang + + lang = request.COOKIES.get('django_language', None) + if lang is not None: + return lang + + from django.conf import settings + + accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None) + if accept is not None: + + t = _accepted.get(accept, None) + if t is not None: + return t + + def _parsed(el): + p = el.find(';q=') + if p >= 0: + lang = el[:p].strip() + order = int(float(el[p+3:].strip())*100) + else: + lang = el + order = 100 + return (lang, order) + + langs = [_parsed(el) for el in accept.split(',')] + langs.sort(lambda a,b: cmp(a[1], b[1])) + + globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale') + + for lang, order in langs: + if os.path.isfile(os.path.join(globalpath, lang, 'LC_MESSAGES', 'django.mo')): + _accepted[accept] = lang + return lang + + return settings.LANGUAGE_CODE + +def install(): + """ + This installs the gettext function as the default + translation function under the name _. + """ + __builtins__['_'] = gettext + |
