Skip to content

Commit

Permalink
[1.9.x] Fixed #25915 -- Allowed language not in Django's default LANG…
Browse files Browse the repository at this point in the history
…UAGES

This fixes a regression introduced by a5f6cbc.
Thanks Gavin Wahl for the report and Tim Graham for the review.
Backport of cd3c042 from master.
  • Loading branch information
claudep committed Dec 18, 2015
1 parent 12b0d07 commit f0a4ff2
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 17 deletions.
33 changes: 16 additions & 17 deletions django/utils/translation/trans_real.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,14 @@ def __init__(self, language):
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):
Expand All @@ -125,32 +129,19 @@ def _new_gnu_trans(self, localedir, use_null_fallback=True):
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."""
Expand Down Expand Up @@ -183,7 +174,15 @@ def _add_fallback(self):

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."""
Expand Down
3 changes: 3 additions & 0 deletions docs/releases/1.8.8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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`).
3 changes: 3 additions & 0 deletions docs/releases/1.9.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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`).
Binary file added tests/i18n/commands/locale/xxx/LC_MESSAGES/django.mo
Binary file not shown.
21 changes: 21 additions & 0 deletions tests/i18n/commands/locale/xxx/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
@@ -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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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"
19 changes: 19 additions & 0 deletions tests/i18n/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1845,3 +1845,22 @@ def test_failure_finding_default_mo_files(self):
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")

0 comments on commit f0a4ff2

Please sign in to comment.