#23689 closed Bug (fixed)
Django detects HTTP Accept-Language header in case-sensitive manner
| Reported by: | wayneye | Owned by: | Zainab Amir |
|---|---|---|---|
| Component: | Internationalization | Version: | 4.0 |
| Severity: | Normal | Keywords: | |
| Cc: | Claude Paroz, Daniel Finch | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
This issue was originally discussed in django-developers: https://groups.google.com/forum/#!topic/django-developers/1Y9LZSAOSnE
Per w3c, rfc2616 and bcp47, Language tags should be parsed in case-insensitive, however, I noticed that Django detects HTTP Accept-Language headers in case-sensitive manner.
For example, the following headers:
Chrome: Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4 Firefox: Accept-Language: zh-tw,zh;q=0.8,en-us;q=0.5,en;q=0.3
Django will correctly display Traditional Chinese for Chrome, but won't for Firefox because of lower-cased TW.
The fix contains two parts:
- Fix potential case-sensitive places in code to follow case-insensitive (for example parse_accept_lang_header())
- Fix documentation, correct the sentence "Browsers send the names of the languages they accept in the Accept-Language HTTP header using this format. Examples: it, de-at, es, pt-br. Both the language and the country parts are in lower case. ", which obviously incorrect, Chrome uses tags like zh-TW, pt-BR.
Change History (17)
comment:3 by , 3 years ago
I've just hit this same problem today, here's some example code:
views.py:
class ExampleView(TemplateView): template_name = 'example.html' def get_context_data(self, **kwargs: Any) -> Dict[str, Any]: context = super().get_context_data(**kwargs) context['language_code'] = translation.get_language() # ^-- should be pt-BR, but is pt return context
test_views.py
def test_example_view(db, client): language_code = 'pt-BR' resp = client.get(reverse('example'), HTTP_ACCEPT_LANGUAGE=language_code) assert resp.context_data['language_code'] == language_code # ^-- AssertionError: pt-BR != pt
The code path that's going wrong is:
LocaleMiddleware.process_requestcallstranslation.get_language_from_requestget_language_from_requestcallsparse_accept_lang_headerwhich turnspt-BRintopt-brget_language_from_requestthen callsget_supported_language_variant, passingpt-bras thelang_codeget_supported_language_variantthen runsif code in supported_lang_codes, which isFalse(note that'pt-BR' in supported_lang_codes == True)get_supported_language_variantthen returns the fallback lang_codept
comment:4 by , 3 years ago
| Resolution: | needsinfo |
|---|---|
| Status: | closed → new |
comment:5 by , 3 years ago
I've created a simple reproduction using the above example code as a basis. You can find it here: https://github.com/danielsamuels/django_23689
comment:6 by , 3 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:7 by , 3 years ago
| Cc: | added |
|---|---|
| Easy pickings: | unset |
comment:9 by , 3 years ago
Created a fix for it on my branch: https://github.com/django/django/compare/main...zainab-amir:ticket_23689
I will create a PR on django if no one has any suggestions or comments.
- The documentation already mentions that the header should be case sensitive, so I fixed that
- Also noticed that running django server with these settings throw an error as mentioned below. This is also fixed.
LANGUAGES = (
('EN-US', 'English (US)'),
('De', 'Deutsche'),
('ar', 'عربى'),
)
LANGUAGE_CODE = 'en-us'
ERROR:
ERRORS: ?: (translation.E004) You have provided a value for the LANGUAGE_CODE setting that is not in the LANGUAGES setting.
comment:10 by , 3 years ago
| Version: | 1.7 → 4.0 |
|---|
follow-up: 12 comment:11 by , 3 years ago
I will create a PR on django if no one has any suggestions or comments.
You don't need to wait for an approval. PR is the right place for suggestions and comments.
Also noticed that running django server with these settings throw an error as mentioned below. This is also fixed.
I don't see anything to fix here 🤔
comment:12 by , 3 years ago
Replying to Mariusz Felisiak:
Also noticed that running django server with these settings throw an error as mentioned below. This is also fixed.
I don't see anything to fix here 🤔
This is the ripple effect of fixing the header parsing to be case insensitive.
comment:13 by , 3 years ago
| Cc: | added |
|---|
comment:15 by , 3 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Case sensitivity should have been resolved by 2bab9d6d9ea095c4bcaeede2df576708afd46291
I have done some local tests and couldn't reproduce your issue. Having a failing test case would help.