Loading django/utils/translation/trans_real.py +32 −9 Original line number Diff line number Diff line Loading @@ -100,9 +100,13 @@ class DjangoTranslation(gettext_module.GNUTranslations): requested language and add a fallback to the default language, if it's different from the requested language. """ def __init__(self, language): domain = 'django' def __init__(self, language, domain=None, localedirs=None): """Create a GNUTranslations() using many locale directories""" gettext_module.GNUTranslations.__init__(self) if domain is not None: self.domain = domain self.set_output_charset('utf-8') # For Python 2 gettext() (#25720) self.__language = language Loading @@ -110,13 +114,26 @@ class DjangoTranslation(gettext_module.GNUTranslations): self.__locale = to_locale(language) self._catalog = None if self.domain == 'django': if localedirs is not None: # A module-level cache is used for caching 'django' translations warnings.warn("localedirs is ignored when domain is 'django'.", RuntimeWarning) localedirs = None self._init_translation_catalog() if localedirs: for localedir in localedirs: translation = self._new_gnu_trans(localedir) self.merge(translation) else: self._add_installed_apps_translations() self._add_local_translations() if self.__language == settings.LANGUAGE_CODE and self._catalog is None: if (self.__language == settings.LANGUAGE_CODE and self.domain == 'django' and self._catalog is None): # default lang should have at least one translation file available. raise IOError("No translation files found for default language %s." % settings.LANGUAGE_CODE) self._add_fallback() self._add_fallback(localedirs) if self._catalog is None: # No catalogs found for this language, set an empty catalog. self._catalog = {} Loading @@ -133,7 +150,7 @@ class DjangoTranslation(gettext_module.GNUTranslations): references to 'fallback'. """ return gettext_module.translation( domain='django', domain=self.domain, localedir=localedir, languages=[self.__locale], codeset='utf-8', Loading Loading @@ -166,13 +183,19 @@ class DjangoTranslation(gettext_module.GNUTranslations): translation = self._new_gnu_trans(localedir) self.merge(translation) def _add_fallback(self): def _add_fallback(self, localedirs=None): """Sets the GNUTranslations() fallback with the default language.""" # Don't set a fallback for the default language or any English variant # (as it's empty, so it'll ALWAYS fall back to the default language) if self.__language == settings.LANGUAGE_CODE or self.__language.startswith('en'): return if self.domain == 'django': # Get from cache default_translation = translation(settings.LANGUAGE_CODE) else: default_translation = DjangoTranslation( settings.LANGUAGE_CODE, domain=self.domain, localedirs=localedirs ) self.add_fallback(default_translation) def merge(self, other): Loading @@ -198,7 +221,7 @@ class DjangoTranslation(gettext_module.GNUTranslations): def translation(language): """ Returns a translation object. Returns a translation object in the default 'django' domain. """ global _translations if language not in _translations: Loading django/views/i18n.py +20 −60 Original line number Diff line number Diff line import gettext as gettext_module import importlib import itertools import json import os Loading @@ -16,6 +16,7 @@ from django.utils.http import is_safe_url from django.utils.translation import ( LANGUAGE_SESSION_KEY, check_for_language, get_language, to_locale, ) from django.utils.translation.trans_real import DjangoTranslation DEFAULT_PACKAGES = ['django.conf'] LANGUAGE_QUERY_PARAMETER = 'language' Loading Loading @@ -202,67 +203,25 @@ def render_javascript_catalog(catalog=None, plural=None): def get_javascript_catalog(locale, domain, packages): default_locale = to_locale(settings.LANGUAGE_CODE) app_configs = apps.get_app_configs() allowable_packages = set(app_config.name for app_config in app_configs) allowable_packages.update(DEFAULT_PACKAGES) packages = [p for p in packages if p in allowable_packages] t = {} paths = [] en_selected = locale.startswith('en') en_catalog_missing = True # paths of requested packages for package in packages: p = importlib.import_module(package) path = os.path.join(os.path.dirname(upath(p.__file__)), 'locale') paths.append(path) # add the filesystem paths listed in the LOCALE_PATHS setting paths.extend(reversed(settings.LOCALE_PATHS)) # first load all english languages files for defaults for path in paths: try: catalog = gettext_module.translation(domain, path, ['en']) t.update(catalog._catalog) except IOError: pass else: # 'en' is the selected language and at least one of the packages # listed in `packages` has an 'en' catalog if en_selected: en_catalog_missing = False # 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: # If the currently selected language is English but it doesn't have a # translation catalog (presumably due to being the language translated # from) then a wrong language catalog might have been loaded in the # previous step. It needs to be discarded. if en_selected and en_catalog_missing: t = {} else: locale_t = {} for path in paths: try: catalog = gettext_module.translation(domain, path, [locale]) except IOError: catalog = None if catalog is not None: locale_t.update(catalog._catalog) if locale_t: t = locale_t trans = DjangoTranslation(locale, domain=domain, localedirs=paths) trans_cat = trans._catalog plural = None if '' in t: for l in t[''].split('\n'): if l.startswith('Plural-Forms:'): plural = l.split(':', 1)[1].strip() if '' in trans_cat: for line in trans_cat[''].split('\n'): if line.startswith('Plural-Forms:'): plural = line.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 : Loading @@ -272,18 +231,19 @@ def get_javascript_catalog(locale, domain, packages): pdict = {} maxcnts = {} catalog = {} for k, v in t.items(): if k == '': trans_fallback_cat = trans._fallback._catalog if trans._fallback else {} for key, value in itertools.chain(six.iteritems(trans_cat), six.iteritems(trans_fallback_cat)): if key == '' or key in catalog: continue if isinstance(k, six.string_types): catalog[k] = v elif isinstance(k, tuple): msgid = k[0] cnt = k[1] if isinstance(key, six.string_types): catalog[key] = value elif isinstance(key, tuple): msgid = key[0] cnt = key[1] maxcnts[msgid] = max(cnt, maxcnts.get(msgid, 0)) pdict.setdefault(msgid, {})[cnt] = v pdict.setdefault(msgid, {})[cnt] = value else: raise TypeError(k) raise TypeError(key) for k, v in pdict.items(): catalog[k] = [v.get(i, '') for i in range(maxcnts[msgid] + 1)] Loading tests/view_tests/locale/fr/LC_MESSAGES/djangojs.po +3 −1 Original line number Diff line number Diff line Loading @@ -19,10 +19,12 @@ msgstr "" msgid "this is to be translated" msgstr "il faut le traduire" msgid "Choose a time" msgstr "Choisir une heure" msgctxt "month name" msgid "May" msgstr "mai" msgid "Untranslated string" msgstr "" tests/view_tests/tests/test_i18n.py +1 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,7 @@ class JsI18NTests(SimpleTestCase): with self.settings(LANGUAGE_CODE='fr'), override('fi'): response = self.client.get('/jsi18n/') self.assertContains(response, 'il faut le traduire') self.assertNotContains(response, "Untranslated string") def test_i18n_language_non_english_default(self): """ Loading Loading
django/utils/translation/trans_real.py +32 −9 Original line number Diff line number Diff line Loading @@ -100,9 +100,13 @@ class DjangoTranslation(gettext_module.GNUTranslations): requested language and add a fallback to the default language, if it's different from the requested language. """ def __init__(self, language): domain = 'django' def __init__(self, language, domain=None, localedirs=None): """Create a GNUTranslations() using many locale directories""" gettext_module.GNUTranslations.__init__(self) if domain is not None: self.domain = domain self.set_output_charset('utf-8') # For Python 2 gettext() (#25720) self.__language = language Loading @@ -110,13 +114,26 @@ class DjangoTranslation(gettext_module.GNUTranslations): self.__locale = to_locale(language) self._catalog = None if self.domain == 'django': if localedirs is not None: # A module-level cache is used for caching 'django' translations warnings.warn("localedirs is ignored when domain is 'django'.", RuntimeWarning) localedirs = None self._init_translation_catalog() if localedirs: for localedir in localedirs: translation = self._new_gnu_trans(localedir) self.merge(translation) else: self._add_installed_apps_translations() self._add_local_translations() if self.__language == settings.LANGUAGE_CODE and self._catalog is None: if (self.__language == settings.LANGUAGE_CODE and self.domain == 'django' and self._catalog is None): # default lang should have at least one translation file available. raise IOError("No translation files found for default language %s." % settings.LANGUAGE_CODE) self._add_fallback() self._add_fallback(localedirs) if self._catalog is None: # No catalogs found for this language, set an empty catalog. self._catalog = {} Loading @@ -133,7 +150,7 @@ class DjangoTranslation(gettext_module.GNUTranslations): references to 'fallback'. """ return gettext_module.translation( domain='django', domain=self.domain, localedir=localedir, languages=[self.__locale], codeset='utf-8', Loading Loading @@ -166,13 +183,19 @@ class DjangoTranslation(gettext_module.GNUTranslations): translation = self._new_gnu_trans(localedir) self.merge(translation) def _add_fallback(self): def _add_fallback(self, localedirs=None): """Sets the GNUTranslations() fallback with the default language.""" # Don't set a fallback for the default language or any English variant # (as it's empty, so it'll ALWAYS fall back to the default language) if self.__language == settings.LANGUAGE_CODE or self.__language.startswith('en'): return if self.domain == 'django': # Get from cache default_translation = translation(settings.LANGUAGE_CODE) else: default_translation = DjangoTranslation( settings.LANGUAGE_CODE, domain=self.domain, localedirs=localedirs ) self.add_fallback(default_translation) def merge(self, other): Loading @@ -198,7 +221,7 @@ class DjangoTranslation(gettext_module.GNUTranslations): def translation(language): """ Returns a translation object. Returns a translation object in the default 'django' domain. """ global _translations if language not in _translations: Loading
django/views/i18n.py +20 −60 Original line number Diff line number Diff line import gettext as gettext_module import importlib import itertools import json import os Loading @@ -16,6 +16,7 @@ from django.utils.http import is_safe_url from django.utils.translation import ( LANGUAGE_SESSION_KEY, check_for_language, get_language, to_locale, ) from django.utils.translation.trans_real import DjangoTranslation DEFAULT_PACKAGES = ['django.conf'] LANGUAGE_QUERY_PARAMETER = 'language' Loading Loading @@ -202,67 +203,25 @@ def render_javascript_catalog(catalog=None, plural=None): def get_javascript_catalog(locale, domain, packages): default_locale = to_locale(settings.LANGUAGE_CODE) app_configs = apps.get_app_configs() allowable_packages = set(app_config.name for app_config in app_configs) allowable_packages.update(DEFAULT_PACKAGES) packages = [p for p in packages if p in allowable_packages] t = {} paths = [] en_selected = locale.startswith('en') en_catalog_missing = True # paths of requested packages for package in packages: p = importlib.import_module(package) path = os.path.join(os.path.dirname(upath(p.__file__)), 'locale') paths.append(path) # add the filesystem paths listed in the LOCALE_PATHS setting paths.extend(reversed(settings.LOCALE_PATHS)) # first load all english languages files for defaults for path in paths: try: catalog = gettext_module.translation(domain, path, ['en']) t.update(catalog._catalog) except IOError: pass else: # 'en' is the selected language and at least one of the packages # listed in `packages` has an 'en' catalog if en_selected: en_catalog_missing = False # 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: # If the currently selected language is English but it doesn't have a # translation catalog (presumably due to being the language translated # from) then a wrong language catalog might have been loaded in the # previous step. It needs to be discarded. if en_selected and en_catalog_missing: t = {} else: locale_t = {} for path in paths: try: catalog = gettext_module.translation(domain, path, [locale]) except IOError: catalog = None if catalog is not None: locale_t.update(catalog._catalog) if locale_t: t = locale_t trans = DjangoTranslation(locale, domain=domain, localedirs=paths) trans_cat = trans._catalog plural = None if '' in t: for l in t[''].split('\n'): if l.startswith('Plural-Forms:'): plural = l.split(':', 1)[1].strip() if '' in trans_cat: for line in trans_cat[''].split('\n'): if line.startswith('Plural-Forms:'): plural = line.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 : Loading @@ -272,18 +231,19 @@ def get_javascript_catalog(locale, domain, packages): pdict = {} maxcnts = {} catalog = {} for k, v in t.items(): if k == '': trans_fallback_cat = trans._fallback._catalog if trans._fallback else {} for key, value in itertools.chain(six.iteritems(trans_cat), six.iteritems(trans_fallback_cat)): if key == '' or key in catalog: continue if isinstance(k, six.string_types): catalog[k] = v elif isinstance(k, tuple): msgid = k[0] cnt = k[1] if isinstance(key, six.string_types): catalog[key] = value elif isinstance(key, tuple): msgid = key[0] cnt = key[1] maxcnts[msgid] = max(cnt, maxcnts.get(msgid, 0)) pdict.setdefault(msgid, {})[cnt] = v pdict.setdefault(msgid, {})[cnt] = value else: raise TypeError(k) raise TypeError(key) for k, v in pdict.items(): catalog[k] = [v.get(i, '') for i in range(maxcnts[msgid] + 1)] Loading
tests/view_tests/locale/fr/LC_MESSAGES/djangojs.po +3 −1 Original line number Diff line number Diff line Loading @@ -19,10 +19,12 @@ msgstr "" msgid "this is to be translated" msgstr "il faut le traduire" msgid "Choose a time" msgstr "Choisir une heure" msgctxt "month name" msgid "May" msgstr "mai" msgid "Untranslated string" msgstr ""
tests/view_tests/tests/test_i18n.py +1 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,7 @@ class JsI18NTests(SimpleTestCase): with self.settings(LANGUAGE_CODE='fr'), override('fi'): response = self.client.get('/jsi18n/') self.assertContains(response, 'il faut le traduire') self.assertNotContains(response, "Untranslated string") def test_i18n_language_non_english_default(self): """ Loading