diff --git a/AUTHORS b/AUTHORS index 5f9cb980c69..c603833f595 100644 --- a/AUTHORS +++ b/AUTHORS @@ -328,6 +328,7 @@ answer newbie questions, and generally made Django that much better: Denis Kuzmichyov Panos Laganakos Nick Lane + Ɓukasz Langa Stuart Langridge Paul Lanier David Larlet diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py index ace87fab4b5..10a6cd60fc2 100644 --- a/django/utils/translation/__init__.py +++ b/django/utils/translation/__init__.py @@ -187,10 +187,10 @@ def get_language_info(lang_code): try: return LANG_INFO[lang_code] except KeyError: - if '-' in lang_code: - splited_lang_code = lang_code.split('-')[0] - try: - return LANG_INFO[splited_lang_code] - except KeyError: - raise KeyError("Unknown language code %s and %s." % (lang_code, splited_lang_code)) - raise KeyError("Unknown language code %s." % lang_code) + if '-' not in lang_code: + raise KeyError("Unknown language code %s." % lang_code) + generic_lang_code = lang_code.split('-')[0] + try: + return LANG_INFO[generic_lang_code] + except KeyError: + raise KeyError("Unknown language code %s and %s." % (lang_code, generic_lang_code)) diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index 8014b5ea3a9..ad172407de1 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -356,6 +356,20 @@ def check_for_language(lang_code): return True return False +def get_supported_language_variant(lang_code, supported=None): + """ + Returns the language-code that's listed in supported languages, possibly + selecting a more generic variant. Raises LookupError if nothing found. + """ + if supported is None: + from django.conf import settings + supported = dict(settings.LANGUAGES) + if lang_code and lang_code not in supported: + lang_code = lang_code.split('-')[0] # e.g. if fr-ca is not supported fallback to fr + if lang_code and lang_code in supported and check_for_language(lang_code): + return lang_code + raise LookupError(lang_code) + def get_language_from_path(path, supported=None): """ Returns the language-code if there is a valid language-code @@ -396,11 +410,10 @@ def get_language_from_request(request, check_path=False): lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME) - if lang_code and lang_code not in supported: - lang_code = lang_code.split('-')[0] # e.g. if fr-ca is not supported fallback to fr - - if lang_code and lang_code in supported and check_for_language(lang_code): - return lang_code + try: + return get_supported_language_variant(lang_code, supported) + except LookupError: + pass accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '') for accept_lang, unused in parse_accept_lang_header(accept): @@ -434,7 +447,10 @@ def get_language_from_request(request, check_path=False): _accepted[normalized] = lang return lang - return settings.LANGUAGE_CODE + try: + return get_supported_language_variant(settings.LANGUAGE_CODE, supported) + except LookupError: + return settings.LANGUAGE_CODE dot_re = re.compile(r'\S') def blankout(src, char): diff --git a/tests/regressiontests/i18n/patterns/tests.py b/tests/regressiontests/i18n/patterns/tests.py index 0a785ab1d61..3f77136efbf 100644 --- a/tests/regressiontests/i18n/patterns/tests.py +++ b/tests/regressiontests/i18n/patterns/tests.py @@ -19,7 +19,7 @@ from django.utils import translation TEMPLATE_DIRS=( os.path.join(os.path.dirname(upath(__file__)), 'templates'), ), - LANGUAGE_CODE='en', + LANGUAGE_CODE='en-us', LANGUAGES=( ('nl', 'Dutch'), ('en', 'English'), @@ -171,6 +171,14 @@ class URLRedirectTests(URLTestCaseBase): response = self.client.get(response['location']) self.assertEqual(response.status_code, 200) + def test_pl_pl_redirect(self): + # language from outside of the supported LANGUAGES list + response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='pl-pl') + self.assertRedirects(response, '/en/account/register/') + + response = self.client.get(response['location']) + self.assertEqual(response.status_code, 200) + class URLVaryAcceptLanguageTests(URLTestCaseBase): """ diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py index aaa9b12c3b5..520469ca795 100644 --- a/tests/regressiontests/i18n/tests.py +++ b/tests/regressiontests/i18n/tests.py @@ -958,7 +958,7 @@ class TestLanguageInfo(TestCase): self.assertEqual(li['bidi'], False) def test_unknown_language_code(self): - six.assertRaisesRegex(self, KeyError, "Unknown language code '?xx'?.", get_language_info, 'xx-xx') + six.assertRaisesRegex(self, KeyError, r"Unknown language code xx\.", get_language_info, 'xx') def test_unknown_only_country_code(self): li = get_language_info('de-xx') @@ -968,7 +968,7 @@ class TestLanguageInfo(TestCase): self.assertEqual(li['bidi'], False) def test_unknown_language_code_and_country_code(self): - six.assertRaisesRegex(self, KeyError, "Unknown language code '?xx-xx'? and '?xx'?.", get_language_info, 'xx-xx') + six.assertRaisesRegex(self, KeyError, r"Unknown language code xx-xx and xx\.", get_language_info, 'xx-xx') class MultipleLocaleActivationTests(TestCase):