Django

Code

Changeset 964

Show
Ignore:
Timestamp:
10/19/05 18:55:37 (3 years ago)
Author:
hugo
Message:

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

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/i18n/django/bin/django-admin.py

    r943 r964  
    77# switch to english, because django-admin creates database content 
    88# like permissions, and those shouldn't contain any translations 
    9 translation.activate('*', 'en-us') 
     9translation.activate('en-us') 
    1010 
    1111ACTION_MAPPING = { 
  • django/branches/i18n/django/middleware/locale.py

    r851 r964  
    33from django.utils.cache import patch_vary_headers 
    44from django.utils import translation 
    5  
    6 # this is a cache that will build a map from modules to applications 
    7 _module_to_app = {} 
    85 
    96class LocaleMiddleware: 
     
    1613    """ 
    1714 
    18     def process_view(self, request, view_func, param_dict): 
    19         global _module_to_app 
    20  
    21         def findapp(module): 
    22             app = _module_to_app.get(view_func.__module__, None) 
    23             if app is not None: 
    24                 return app 
    25  
    26             from django.conf import settings 
    27             for app in settings.INSTALLED_APPS: 
    28                 if module.startswith(app): 
    29                     _module_to_app[module] = app 
    30                     return app 
    31             return '*' 
    32  
    33         app = findapp(view_func.__module__) 
    34  
    35         lang = translation.get_language_from_request(request) 
    36  
    37         translation.activate(app, lang) 
    38  
     15    def process_request(self, request): 
     16        language = translation.get_language_from_request(request) 
     17        translation.activate(language) 
    3918        request.LANGUAGE_CODE = translation.get_language() 
    4019 
    4120    def process_response(self, request, response): 
    4221        patch_vary_headers(response, ('Accept-Language',)) 
     22        translation.deactivate() 
    4323        return response 
    4424 
  • django/branches/i18n/django/utils/translation.py

    r943 r964  
    3737    p = language.find('-') 
    3838    if p >= 0: 
    39         return language[:p].lower()+'_'+language[p:].upper() 
     39        return language[:p].lower()+'_'+language[p+1:].upper() 
    4040    else: 
    4141        return language.lower() 
     
    4545    p = locale.find('_') 
    4646    if p >= 0: 
    47         return locale[:p].lower()+'-'+locale[p:].lower() 
     47        return locale[:p].lower()+'-'+locale[p+1:].lower() 
    4848    else: 
    4949        return locale.lower() 
     
    6868            pass 
    6969        self.django_output_charset = settings.DEFAULT_CHARSET 
    70         self.__app = '?.?.?' 
    7170        self.__language = '??' 
    72      
    73     def set_app_and_language(self, app, language): 
    74         self.__app = app 
     71 
     72    def merge(self, other): 
     73        self._catalog.update(other._catalog) 
     74     
     75    def set_language(self, language): 
    7576        self.__language = language 
    7677 
     
    7980     
    8081    def __repr__(self): 
    81         return "<DjangoTranslation app:%s lang:%s>" % (self.__app, self.__language) 
     82        return "<DjangoTranslation lang:%s>" % self.__language 
    8283 
    8384 
     
    102103        return res.encode(self.django_output_charset) 
    103104 
    104 def translation(appname, language): 
    105     """ 
    106     This function returns a translation object. 
    107     app must be the fully qualified name of the 
    108     application. 
    109  
    110     This function will first look into the app 
    111     messages directory for the django message file, 
    112     then in the project messages directory for the 
    113     django message file and last in the global 
    114     messages directory for the django message file. 
    115     """ 
    116  
    117     t = _translations.get((appname, language), None) 
     105def translation(language): 
     106    """ 
     107    This function returns a translation object.  app must be the fully 
     108    qualified name of the application. 
     109 
     110    This translation object will be constructed out of multiple GNUTranslations 
     111    objects by merging their catalogs. It will construct a object for the requested 
     112    language and add a fallback to the default language, if that is different 
     113    from the requested language. 
     114    """ 
     115    global _translations 
     116 
     117    if language == 'en' or language.startswith('en-'): 
     118        return gettext_module.NullTranslations() 
     119 
     120    t = _translations.get(language, None) 
    118121    if t is not None: 
    119122        return t 
    120123     
    121124    from django.conf import settings 
    122  
    123     default_locale = to_locale(settings.LANGUAGE_CODE) 
    124     locale = to_locale(language) 
    125125 
    126126    # set up the right translation class 
     
    131131    globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale') 
    132132 
    133     try: 
    134         t = gettext_module.translation('django', globalpath, [locale, default_locale], klass) 
    135         t.set_app_and_language(appname, language) 
    136     except IOError: t = gettext_module.NullTranslations() 
    137     _translations[(appname, language)] = t 
    138  
    139     if hasattr(settings, 'LOCALE_PATHS'): 
    140         for localepath in settings.LOCALE_PATHS: 
    141             try: 
    142                 t = gettext_module.translation('django', localepath, [locale, default_locale], klass) 
    143                 t.set_app_and_language(appname, language) 
    144             except IOError: t = None 
    145             if t is not None: 
    146                 t.add_fallback(_translations[(appname, language)]) 
    147                 _translations[(appname, language)] = t 
    148  
    149133    parts = os.environ['DJANGO_SETTINGS_MODULE'].split('.') 
    150134    project = __import__(parts[0], {}, {}, []) 
    151  
    152135    projectpath = os.path.join(os.path.dirname(project.__file__), 'locale') 
    153136 
    154     try: 
    155         t = gettext_module.translation('django', projectpath, [locale, default_locale], klass) 
    156         t.set_app_and_language(appname, language) 
    157     except IOError: t = None 
    158     if t is not None: 
    159         t.add_fallback(_translations[(appname, language)]) 
    160         _translations[(appname, language)] = t 
    161  
    162     if appname != '*': 
    163         app = __import__(appname, {}, {}, ['views']) 
    164  
    165         apppath = os.path.join(os.path.dirname(app.__file__), 'locale') 
    166  
    167         try: 
    168             t = gettext_module.translation('django', apppath, [locale, default_locale], klass) 
    169             t.set_app_and_language(appname, language) 
    170         except IOError: t = None 
    171         if t is not None: 
    172             t.add_fallback(_translations[(appname, language)]) 
    173             _translations[(appname, language)] = t 
    174  
    175     return _translations[(appname, language)] 
    176  
    177 def activate(appname, language): 
     137    def _fetch(lang, fallback=None): 
     138 
     139        global _translations 
     140 
     141        loc = to_locale(lang) 
     142 
     143        res = _translations.get(lang, None) 
     144        if res is not None: 
     145            return res 
     146 
     147        def _translation(path): 
     148            try: 
     149                t = gettext_module.translation('django', path, [loc], klass) 
     150                t.set_language(lang) 
     151                return t 
     152            except IOError, e: 
     153                return None 
     154     
     155        res = _translation(globalpath) 
     156 
     157        def _merge(path): 
     158            t = _translation(path) 
     159            if t is not None: 
     160                if res is None: 
     161                    return t 
     162                else: 
     163                    res.merge(t) 
     164            return res 
     165 
     166        if hasattr(settings, 'LOCALE_PATHS'): 
     167            for localepath in settings.LOCALE_PATHS: 
     168                if os.path.isdir(localepath): 
     169                    res = _merge(localepath) 
     170 
     171        if os.path.isdir(projectpath): 
     172            res = _merge(projectpath) 
     173 
     174        for appname in settings.INSTALLED_APPS: 
     175            p = appname.rfind('.') 
     176            if p >= 0: 
     177                app = getattr(__import__(appname[:p], {}, {}, [appname[p+1:]]), appname[p+1:]) 
     178            else: 
     179                app = __import__(appname, {}, {}, []) 
     180 
     181            apppath = os.path.join(os.path.dirname(app.__file__), 'locale') 
     182 
     183            if os.path.isdir(apppath): 
     184                res = _merge(apppath) 
     185   
     186        if res is None: 
     187            if fallback is not None: 
     188                res = fallback 
     189            else: 
     190                return gettext_module.NullTranslations() 
     191        _translations[lang] = res 
     192        return res 
     193 
     194    default_translation = _fetch(settings.LANGUAGE_CODE) 
     195    current_translation = _fetch(language, fallback=default_translation) 
     196 
     197    return current_translation 
     198 
     199def activate(language): 
    178200    """ 
    179201    This function fetches the translation object for a given 
     
    181203    the current translation object for the current thread. 
    182204    """ 
    183     if language == 'en' or language.startswith('en-'): 
    184         t = gettext_module.NullTranslations() 
    185     else: 
    186         t = translation(appname, language) 
    187     _active[currentThread()] = t 
     205    _active[currentThread()] = translation(language) 
    188206 
    189207def deactivate(): 
     
    193211    default translation object, again. 
    194212    """ 
    195     del _active[currentThread()] 
     213    global _active 
     214 
     215    if _active.has_key(currentThread()): 
     216        del _active[currentThread()] 
    196217 
    197218def get_language(): 
     
    226247    if _default is None: 
    227248        from django.conf import settings 
    228         _default = translation('*', settings.LANGUAGE_CODE) 
     249        _default = translation(settings.LANGUAGE_CODE) 
    229250    return _default.gettext(message) 
    230251 
     
    336357                    # did find de_DE because of language normalization 
    337358                    lang = langfile[len(globalpath):].split('/')[1] 
    338                     _accepted[accept] = to_language(lang) 
     359                    _accepted[accept] = lang 
    339360                    return lang 
    340361