1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

i18n: reworked part of the translation loader to be cleaner, simpler and faster

git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@964 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Georg Bauer 2005-10-19 23:55:37 +00:00
parent 6ec8d14619
commit 72dcdd4de1
3 changed files with 89 additions and 88 deletions

View File

@ -6,7 +6,7 @@ import os, sys
# switch to english, because django-admin creates database content # switch to english, because django-admin creates database content
# like permissions, and those shouldn't contain any translations # like permissions, and those shouldn't contain any translations
translation.activate('*', 'en-us') translation.activate('en-us')
ACTION_MAPPING = { ACTION_MAPPING = {
'adminindex': management.get_admin_index, 'adminindex': management.get_admin_index,

View File

@ -3,9 +3,6 @@
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils import translation from django.utils import translation
# this is a cache that will build a map from modules to applications
_module_to_app = {}
class LocaleMiddleware: class LocaleMiddleware:
""" """
This is a very simple middleware that parses a request This is a very simple middleware that parses a request
@ -15,30 +12,13 @@ class LocaleMiddleware:
is available, of course). is available, of course).
""" """
def process_view(self, request, view_func, param_dict): def process_request(self, request):
global _module_to_app language = translation.get_language_from_request(request)
translation.activate(language)
def findapp(module):
app = _module_to_app.get(view_func.__module__, None)
if app is not None:
return app
from django.conf import settings
for app in settings.INSTALLED_APPS:
if module.startswith(app):
_module_to_app[module] = app
return app
return '*'
app = findapp(view_func.__module__)
lang = translation.get_language_from_request(request)
translation.activate(app, lang)
request.LANGUAGE_CODE = translation.get_language() request.LANGUAGE_CODE = translation.get_language()
def process_response(self, request, response): def process_response(self, request, response):
patch_vary_headers(response, ('Accept-Language',)) patch_vary_headers(response, ('Accept-Language',))
translation.deactivate()
return response return response

View File

@ -36,7 +36,7 @@ def to_locale(language):
"turn a language name (en-us) into a locale name (en_US)" "turn a language name (en-us) into a locale name (en_US)"
p = language.find('-') p = language.find('-')
if p >= 0: if p >= 0:
return language[:p].lower()+'_'+language[p:].upper() return language[:p].lower()+'_'+language[p+1:].upper()
else: else:
return language.lower() return language.lower()
@ -44,7 +44,7 @@ def to_language(locale):
"turns a locale name (en_US) into a language name (en-us)" "turns a locale name (en_US) into a language name (en-us)"
p = locale.find('_') p = locale.find('_')
if p >= 0: if p >= 0:
return locale[:p].lower()+'-'+locale[p:].lower() return locale[:p].lower()+'-'+locale[p+1:].lower()
else: else:
return locale.lower() return locale.lower()
@ -67,18 +67,19 @@ class DjangoTranslation(gettext_module.GNUTranslations):
except AttributeError: except AttributeError:
pass pass
self.django_output_charset = settings.DEFAULT_CHARSET self.django_output_charset = settings.DEFAULT_CHARSET
self.__app = '?.?.?'
self.__language = '??' self.__language = '??'
def merge(self, other):
self._catalog.update(other._catalog)
def set_app_and_language(self, app, language): def set_language(self, language):
self.__app = app
self.__language = language self.__language = language
def language(self): def language(self):
return self.__language return self.__language
def __repr__(self): def __repr__(self):
return "<DjangoTranslation app:%s lang:%s>" % (self.__app, self.__language) return "<DjangoTranslation lang:%s>" % self.__language
class DjangoTranslation23(DjangoTranslation): class DjangoTranslation23(DjangoTranslation):
@ -101,28 +102,27 @@ class DjangoTranslation23(DjangoTranslation):
res = self.ungettext(msgid1, msgid2, n) res = self.ungettext(msgid1, msgid2, n)
return res.encode(self.django_output_charset) return res.encode(self.django_output_charset)
def translation(appname, language): def translation(language):
""" """
This function returns a translation object. This function returns a translation object. app must be the fully
app must be the fully qualified name of the qualified name of the application.
application.
This function will first look into the app This translation object will be constructed out of multiple GNUTranslations
messages directory for the django message file, objects by merging their catalogs. It will construct a object for the requested
then in the project messages directory for the language and add a fallback to the default language, if that is different
django message file and last in the global from the requested language.
messages directory for the django message file.
""" """
global _translations
t = _translations.get((appname, language), None) if language == 'en' or language.startswith('en-'):
return gettext_module.NullTranslations()
t = _translations.get(language, None)
if t is not None: if t is not None:
return t return t
from django.conf import settings from django.conf import settings
default_locale = to_locale(settings.LANGUAGE_CODE)
locale = to_locale(language)
# set up the right translation class # set up the right translation class
klass = DjangoTranslation klass = DjangoTranslation
if sys.version_info < (2, 4): if sys.version_info < (2, 4):
@ -130,61 +130,79 @@ def translation(appname, language):
globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale') globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale')
try:
t = gettext_module.translation('django', globalpath, [locale, default_locale], klass)
t.set_app_and_language(appname, language)
except IOError: t = gettext_module.NullTranslations()
_translations[(appname, language)] = t
if hasattr(settings, 'LOCALE_PATHS'):
for localepath in settings.LOCALE_PATHS:
try:
t = gettext_module.translation('django', localepath, [locale, default_locale], klass)
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
parts = os.environ['DJANGO_SETTINGS_MODULE'].split('.') parts = os.environ['DJANGO_SETTINGS_MODULE'].split('.')
project = __import__(parts[0], {}, {}, []) project = __import__(parts[0], {}, {}, [])
projectpath = os.path.join(os.path.dirname(project.__file__), 'locale') projectpath = os.path.join(os.path.dirname(project.__file__), 'locale')
try: def _fetch(lang, fallback=None):
t = gettext_module.translation('django', projectpath, [locale, default_locale], klass)
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
if appname != '*': global _translations
app = __import__(appname, {}, {}, ['views'])
apppath = os.path.join(os.path.dirname(app.__file__), 'locale') loc = to_locale(lang)
try: res = _translations.get(lang, None)
t = gettext_module.translation('django', apppath, [locale, default_locale], klass) if res is not None:
t.set_app_and_language(appname, language) return res
except IOError: t = None
if t is not None:
t.add_fallback(_translations[(appname, language)])
_translations[(appname, language)] = t
return _translations[(appname, language)] def _translation(path):
try:
t = gettext_module.translation('django', path, [loc], klass)
t.set_language(lang)
return t
except IOError, e:
return None
res = _translation(globalpath)
def activate(appname, language): def _merge(path):
t = _translation(path)
if t is not None:
if res is None:
return t
else:
res.merge(t)
return res
if hasattr(settings, 'LOCALE_PATHS'):
for localepath in settings.LOCALE_PATHS:
if os.path.isdir(localepath):
res = _merge(localepath)
if os.path.isdir(projectpath):
res = _merge(projectpath)
for appname in settings.INSTALLED_APPS:
p = appname.rfind('.')
if p >= 0:
app = getattr(__import__(appname[:p], {}, {}, [appname[p+1:]]), appname[p+1:])
else:
app = __import__(appname, {}, {}, [])
apppath = os.path.join(os.path.dirname(app.__file__), 'locale')
if os.path.isdir(apppath):
res = _merge(apppath)
if res is None:
if fallback is not None:
res = fallback
else:
return gettext_module.NullTranslations()
_translations[lang] = res
return res
default_translation = _fetch(settings.LANGUAGE_CODE)
current_translation = _fetch(language, fallback=default_translation)
return current_translation
def activate(language):
""" """
This function fetches the translation object for a given This function fetches the translation object for a given
tuple of application name and language and installs it as tuple of application name and language and installs it as
the current translation object for the current thread. the current translation object for the current thread.
""" """
if language == 'en' or language.startswith('en-'): _active[currentThread()] = translation(language)
t = gettext_module.NullTranslations()
else:
t = translation(appname, language)
_active[currentThread()] = t
def deactivate(): def deactivate():
""" """
@ -192,7 +210,10 @@ def deactivate():
object so that further _ calls will resolve against the object so that further _ calls will resolve against the
default translation object, again. default translation object, again.
""" """
del _active[currentThread()] global _active
if _active.has_key(currentThread()):
del _active[currentThread()]
def get_language(): def get_language():
""" """
@ -225,7 +246,7 @@ def gettext(message):
return t.gettext(message) return t.gettext(message)
if _default is None: if _default is None:
from django.conf import settings from django.conf import settings
_default = translation('*', settings.LANGUAGE_CODE) _default = translation(settings.LANGUAGE_CODE)
return _default.gettext(message) return _default.gettext(message)
def gettext_noop(message): def gettext_noop(message):
@ -335,7 +356,7 @@ def get_language_from_request(request):
# report de_DE if we only have de available, but # report de_DE if we only have de available, but
# did find de_DE because of language normalization # did find de_DE because of language normalization
lang = langfile[len(globalpath):].split('/')[1] lang = langfile[len(globalpath):].split('/')[1]
_accepted[accept] = to_language(lang) _accepted[accept] = lang
return lang return lang
return settings.LANGUAGE_CODE return settings.LANGUAGE_CODE