diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index 6e7ef9b742..aa50c02fb2 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -112,10 +112,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):
@@ -129,32 +133,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."""
@@ -187,7 +178,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 6ba76d71cb..e35ed250f5 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/tests/i18n/commands/locale/xxx/LC_MESSAGES/django.mo b/tests/i18n/commands/locale/xxx/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000..1d9eeba048
Binary files /dev/null and b/tests/i18n/commands/locale/xxx/LC_MESSAGES/django.mo differ
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 0000000000..8fe7b7fa3d
--- /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 <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"
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index 29bb2e9cb6..8b9f83bf4a 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -1527,3 +1527,22 @@ class TranslationFilesMissing(TestCase):
         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")