From cd3c042b0473e762b0e89bc69a9244c4a1fed66e Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Fri, 18 Dec 2015 17:00:53 +0100 Subject: [PATCH] Fixed #25915 -- Allowed language not in Django's default LANGUAGES This fixes a regression introduced by a5f6cbce07. Thanks Gavin Wahl for the report and Tim Graham for the review. --- django/utils/translation/trans_real.py | 33 +++++++++--------- docs/releases/1.8.8.txt | 3 ++ docs/releases/1.9.1.txt | 3 ++ .../commands/locale/xxx/LC_MESSAGES/django.mo | Bin 0 -> 457 bytes .../commands/locale/xxx/LC_MESSAGES/django.po | 21 +++++++++++ tests/i18n/tests.py | 19 ++++++++++ 6 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 tests/i18n/commands/locale/xxx/LC_MESSAGES/django.mo create mode 100644 tests/i18n/commands/locale/xxx/LC_MESSAGES/django.po diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index 6c6fe6d2f27..b73f2b48698 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -108,10 +108,14 @@ class DjangoTranslation(gettext_module.GNUTranslations): self.__language = language self.__to_language = to_language(language) self.__locale = to_locale(language) + self._catalog = None self._init_translation_catalog() self._add_installed_apps_translations() self._add_local_translations() + if self.__language == settings.LANGUAGE_CODE 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() def __repr__(self): @@ -125,32 +129,19 @@ class DjangoTranslation(gettext_module.GNUTranslations): Using param `use_null_fallback` to avoid confusion with any other references to 'fallback'. """ - translation = gettext_module.translation( + return gettext_module.translation( domain='django', localedir=localedir, languages=[self.__locale], codeset='utf-8', fallback=use_null_fallback) - if not hasattr(translation, '_catalog'): - # provides merge support for NullTranslations() - translation._catalog = {} - translation._info = {} - translation.plural = lambda n: int(n != 1) - return translation def _init_translation_catalog(self): """Creates a base catalog using global django translations.""" settingsfile = upath(sys.modules[settings.__module__].__file__) localedir = os.path.join(os.path.dirname(settingsfile), 'locale') - use_null_fallback = True - if self.__language == settings.LANGUAGE_CODE: - # default lang should be present and parseable, if not - # gettext will raise an IOError (refs #18192). - use_null_fallback = False - translation = self._new_gnu_trans(localedir, use_null_fallback) - self.plural = translation.plural - self._info = translation._info.copy() - self._catalog = translation._catalog.copy() + translation = self._new_gnu_trans(localedir) + self.merge(translation) def _add_installed_apps_translations(self): """Merges translations from each installed app.""" @@ -183,7 +174,15 @@ class DjangoTranslation(gettext_module.GNUTranslations): def merge(self, other): """Merge another translation into this catalog.""" - self._catalog.update(other._catalog) + if not getattr(other, '_catalog', None): + return # NullTranslations() has no _catalog + if self._catalog is None: + # Take plural and _info from first catalog found (generally Django's). + self.plural = other.plural + self._info = other._info.copy() + self._catalog = other._catalog.copy() + else: + self._catalog.update(other._catalog) def language(self): """Returns the translation language.""" diff --git a/docs/releases/1.8.8.txt b/docs/releases/1.8.8.txt index 6ba76d71cbd..e35ed250f52 100644 --- a/docs/releases/1.8.8.txt +++ b/docs/releases/1.8.8.txt @@ -37,3 +37,6 @@ Bugfixes * Fixed a state bug when using an ``AlterModelManagers`` operation (:ticket:`25852`). + +* Fixed a regression which prevented using a language not in Django's default + language list (:setting:`LANGUAGES`) (:ticket:`25915`). diff --git a/docs/releases/1.9.1.txt b/docs/releases/1.9.1.txt index 2e1aa7cbb16..d5bfdd27395 100644 --- a/docs/releases/1.9.1.txt +++ b/docs/releases/1.9.1.txt @@ -50,3 +50,6 @@ Bugfixes * Fixed incorrect timezone warnings in custom admin templates that don't have a ``data-admin-utc-offset`` attribute in the ``body`` tag. (:ticket:`25845`). + +* Fixed a regression which prevented using a language not in Django's default + language list (:setting:`LANGUAGES`) (:ticket:`25915`). diff --git a/tests/i18n/commands/locale/xxx/LC_MESSAGES/django.mo b/tests/i18n/commands/locale/xxx/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..1d9eeba048f557211c99e34f14b44bdd34561c30 GIT binary patch literal 457 zcmZ9I!A`izyG{8~GeQi&Hd` z_-DUlCi!Rf-~Bpmd>E)>Y2nKo9lqx-VC{$HthJNTBo@h5Mb0~%8 z0&mD}F#d0#1YEx1W Y#l9__Ru6tk=R&}_1NNn9;BW1WZzxK5tN;K2 literal 0 HcmV?d00001 diff --git a/tests/i18n/commands/locale/xxx/LC_MESSAGES/django.po b/tests/i18n/commands/locale/xxx/LC_MESSAGES/django.po new file mode 100644 index 00000000000..8fe7b7fa3d9 --- /dev/null +++ b/tests/i18n/commands/locale/xxx/LC_MESSAGES/django.po @@ -0,0 +1,21 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-12-04 04:59-0600\n" +"PO-Revision-Date: 2011-12-10 19:12-0300\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: xxx\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +msgid "year" +msgstr "reay" diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 7b387cd15be..6456a08e241 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -1849,3 +1849,22 @@ class TranslationFilesMissing(SimpleTestCase): self.patchGettextFind() trans_real._translations = {} self.assertRaises(IOError, activate, 'en') + + +class NonDjangoLanguageTests(SimpleTestCase): + """ + A language non present in default Django languages can still be + installed/used by a Django project. + """ + @override_settings( + USE_I18N=True, + LANGUAGES=[ + ('en-us', 'English'), + ('xxx', 'Somelanguage'), + ], + LANGUAGE_CODE='xxx', + LOCALE_PATHS=[os.path.join(here, 'commands', 'locale')], + ) + def test_non_django_language(self): + self.assertEqual(get_language(), 'xxx') + self.assertEqual(ugettext("year"), "reay")