[Django] #32886: Translation: clash between language cookie and i18n_patterns URLs

28 views
Skip to first unread message

Django

unread,
Jun 28, 2021, 2:59:29 AM6/28/21
to django-...@googlegroups.com
#32886: Translation: clash between language cookie and i18n_patterns URLs
------------------------------------------------+------------------------
Reporter: Seb G | Owner: nobody
Type: Bug | Status: new
Component: Internationalization | Version: 3.2
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
------------------------------------------------+------------------------
= Summary

When using `i18n_patterns`, language cookie is disregarded, even in
non-`i18n_patterns` views.

= Description

Given the following project `urls.py` file:


{{{
#!python
from django.conf.urls.i18n import i18n_patterns
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path("admin/", admin.site.urls),
]

urlpatterns += i18n_patterns(
path("app/", include("app.urls", namespace="app")),
prefix_default_language=False,
)
}}}

Browsing to `/admin/` with a valid `django_language` cookie whose value is
`fr` still returns an english-translated page.

This behavior seems to emerge from the `LocaleMiddleware.process_request`
method:

{{{
#!python
def process_request(self, request):
urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF)

# This returns (True, False) because i18n_patterns are indeed used
(albeit not on the requested route)
i18n_patterns_used, prefixed_default_language =
is_language_prefix_patterns_used(urlconf)

# This returns "fr" as expected from the django_language cookie
language = translation.get_language_from_request(request,
check_path=i18n_patterns_used)

# This returns None since, indeed, this route does not use
i18n_patterns
language_from_path =
translation.get_language_from_path(request.path_info)

# This test passes (somewhat unfortunately)
if not language_from_path and i18n_patterns_used and not
prefixed_default_language:
# This gets executed and reverts language to default language (en)
language = settings.LANGUAGE_CODE

# "en" gets activated instead of "fr"
translation.activate(language)
request.LANGUAGE_CODE = translation.get_language()
}}}

= Steps to reproduce

Using the provided test project

1. `python manage.py migrate`
2. `python manage.py createsuperuser`
3. `python manage.py runserver`
4. Browse to `/admin/`
5. Login as superuser
6. Edit your own user to set its language to "fr". Verify that you now
have a `django_language=fr` cookie
7. Browse to any admin page => not translated to "fr"

= Expected behavior

Cookie language should be respected on routes that do '''not''' use
i18n_patterns. It is ok though that path language overrides cookie
language on routes that '''do''' use i18n_patterns.

--
Ticket URL: <https://code.djangoproject.com/ticket/32886>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jun 28, 2021, 3:02:13 AM6/28/21
to django-...@googlegroups.com
#32886: Translation: clash between language cookie and i18n_patterns URLs
-------------------------------------+-------------------------------------

Reporter: Seb G | Owner: nobody
Type: Bug | Status: new
Component: | Version: 3.2
Internationalization |
Severity: Normal | Resolution:

Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Seb G):

* Attachment "test_project.zip" added.

Django

unread,
Jun 28, 2021, 5:59:07 PM6/28/21
to django-...@googlegroups.com
#32886: Translation: clash between language cookie and i18n_patterns URLs
--------------------------------------+------------------------------------

Reporter: Seb G | Owner: nobody
Type: Bug | Status: new
Component: Internationalization | Version: 3.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------------+------------------------------------
Changes (by Claude Paroz):

* stage: Unreviewed => Accepted


Comment:

Thanks for the well-prepared ticket.

--
Ticket URL: <https://code.djangoproject.com/ticket/32886#comment:1>

Django

unread,
Jun 29, 2021, 2:23:49 PM6/29/21
to django-...@googlegroups.com
#32886: Translation: clash between language cookie and i18n_patterns URLs
-------------------------------------+-------------------------------------
Reporter: Seb G | Owner: Charlie
| Overton
Type: Bug | Status: assigned
Component: | Version: 3.2
Internationalization |

Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Charlie Overton):

* owner: nobody => Charlie Overton
* status: new => assigned


Comment:

I'll start working on this issue.

--
Ticket URL: <https://code.djangoproject.com/ticket/32886#comment:2>

Django

unread,
Oct 2, 2022, 7:48:38 AM10/2/22
to django-...@googlegroups.com
#32886: Translation: clash between language cookie and i18n_patterns URLs
-------------------------------------+-------------------------------------
Reporter: Seb G | Owner: Charlie
| Overton
Type: Bug | Status: assigned
Component: | Version: 3.2
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by sergioisidoro):

I've drafted something that I think will solve this issue:
https://github.com/django/django/pull/16142

--
Ticket URL: <https://code.djangoproject.com/ticket/32886#comment:3>

Django

unread,
May 16, 2025, 9:22:41 AM5/16/25
to django-...@googlegroups.com
#32886: Translation: clash between language cookie and i18n_patterns URLs
-------------------------------------+-------------------------------------
Reporter: Seb G | Owner: Charlie
| Overton
Type: Bug | Status: assigned
Component: | Version: 3.2
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Foucauld Degeorges):

Hi,

The bug still seems present in django 5.2. The code in version 5.2 is
still identical to the code posted in the issue.
Was the PR reverted?

Thanks.
--
Ticket URL: <https://code.djangoproject.com/ticket/32886#comment:4>

Django

unread,
May 16, 2025, 9:54:54 AM5/16/25
to django-...@googlegroups.com
#32886: Translation: clash between language cookie and i18n_patterns URLs
-------------------------------------+-------------------------------------
Reporter: Seb G | Owner: Charlie
| Overton
Type: Bug | Status: assigned
Component: | Version: 3.2
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce):

Yes, see 0e444e84f87d174713a2aef0c4f9704ce2865586 and #34515
--
Ticket URL: <https://code.djangoproject.com/ticket/32886#comment:5>

Django

unread,
May 17, 2025, 6:10:01 AM5/17/25
to django-...@googlegroups.com
#32886: Translation: clash between language cookie and i18n_patterns URLs
-------------------------------------+-------------------------------------
Reporter: Seb G | Owner: Charlie
| Overton
Type: Bug | Status: assigned
Component: | Version: 3.2
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Foucauld Degeorges):

Quite logically, that revert recreated this bug.

A summary of my understanding of the issue:

The root cause seems to be that in an app where the following routes
coexist:

- type A: a language-independant route. The language cannot be inferred
from calling such routes.
- type B: a language-dependant route, with a prefix from `i18n_patterns`,
with `prefix_default_language=False`. The language can be inferred from
calling such routes, and will supersede other sources of language.

`LocaleMiddleware` cannot tell those apart. With the code currently on
master, `LocaleMiddleware` detects that at least one URL of type B exists
in the app, and will assume that all routes of type A or B are of type B.
It will always choose to infer the language.

If I understand correctly, this PR simply inverted the behaviour and
caused #34515. Reverting that PR recreated this one.

The actual fix would be for `LocaleMiddleware` to be able to know whether
the specific route is of type A or B, and based on that, choose to infer
the language of the request or not.
As a workaround, we have implemented our own `LocaleMiddleware` which:

- uses logic adapted from `django-extensions`' `show_urls` command to list
all routes in all enabled languages
- groups them by name to see whether some routes have more than one
distinct pattern
- this tells us whether a route is translated (of type B), or not
translated (of type A)
- if type B, `LocaleMiddleware` should infer the language from the route.
If type A, it shouldn't.
--
Ticket URL: <https://code.djangoproject.com/ticket/32886#comment:6>
Reply all
Reply to author
Forward
0 new messages