diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index 8042f6fdc4..173ad08639 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -474,14 +474,17 @@ def get_supported_language_variant(lang_code, strict=False): . """ if lang_code: - # If 'fr-ca' is not supported, try special fallback or language-only 'fr'. + # If 'zh-hant-tw' is not supported, try special fallback or subsequent + # language codes i.e. 'zh-hant' and 'zh'. possible_lang_codes = [lang_code] try: possible_lang_codes.extend(LANG_INFO[lang_code]['fallback']) except KeyError: pass - generic_lang_code = lang_code.split('-')[0] - possible_lang_codes.append(generic_lang_code) + i = None + while (i := lang_code.rfind('-', 0, i)) > -1: + possible_lang_codes.append(lang_code[:i]) + generic_lang_code = possible_lang_codes[-1] supported_lang_codes = get_languages() for code in possible_lang_codes: diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 8248122a97..7d81f2a07d 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -1424,6 +1424,26 @@ class MiscTests(SimpleTestCase): r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-my,en'} self.assertEqual(get_language_from_request(r), 'zh-hans') + def test_subsequent_code_fallback_language(self): + """ + Subsequent language codes should be used when the language code is not + supported. + """ + tests = [ + ('zh-Hans-CN', 'zh-hans'), + ('zh-hans-mo', 'zh-hans'), + ('zh-hans-HK', 'zh-hans'), + ('zh-Hant-HK', 'zh-hant'), + ('zh-hant-tw', 'zh-hant'), + ('zh-hant-SG', 'zh-hant'), + ] + r = self.rf.get('/') + r.COOKIES = {} + for value, expected in tests: + with self.subTest(value=value): + r.META = {'HTTP_ACCEPT_LANGUAGE': f'{value},en'} + self.assertEqual(get_language_from_request(r), expected) + def test_parse_language_cookie(self): """ Now test that we parse language preferences stored in a cookie correctly.