[Django] #34853: [Date Input Localization] Accept-Language Header Takes Precedence Over Language Set With Cookie

46 views
Skip to first unread message

Django

unread,
Sep 19, 2023, 11:43:51 AM9/19/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue- | Owner: nobody
hexagon |
Type: | Status: new
Uncategorized |
Component: | Version: 4.1
Internationalization | Keywords: l10n localization
Severity: Normal | form input
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
= Accept-Language Header takes precedence over language set with cookie =

The input localization follows the browsers locale.

In the first image below, my browsers locale is 'da' (Danish/Dansk) while
Django language is en-GB - the form inputs should be localized to en-GB
and *not* danish!

In the second image, my browsers locale is 'en-GB' and Django language is
'da' (Danish) - the form inputs should be localized to danish and not en-
GB!

The images clearly shows the error.

I have provided every relevant piece of information I can think of below
the images.

Nowhere in the Django docs, does it mention that form inputs should be
localized to the browsers locale.

[[Image(https://i.imgur.com/twLMfDc.png)]]
[[Image(https://i.imgur.com/HnE2HgC.png)]]

== Middleware ==
{{{
#!python
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.middleware.gzip.GZipMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.locale.LocaleMiddleware',
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.middleware.common.BrokenLinkEmailsMiddleware",
]
}}}

== I18N / L10N ==
{{{
#!python
TIME_ZONE = "UTC"
LANGUAGE_CODE = "en"
LANGUAGES = [
('en', _('English')),
('en-gb', _('English')),
('da', _('Danish')),
]

USE_I18N = True
LANGUAGE_COOKIE_AGE = 31_536_000 # 1 year.

USE_L10N = True
USE_THOUSAND_SEPARATOR = True
USE_TZ = True

LOCALE_PATHS = [
BASE_DIR / 'locale/',
]
}}}

== Loan View ==
{{{
#!python
@login_required(login_url="/accounts/login/")
def loan_create(request, institution_id: int):
if request.POST:
form = LoanForm(request.POST)
if form.is_valid():
form.save()
messages.add_message(request, messages.SUCCESS, _("Loan
created successfully."))
return redirect(request.META.get("HTTP_REFERER",
request.path_info))
else:
messages.add_message(request, messages.ERROR, _("An error
occured."))
return redirect(request.META.get("HTTP_REFERER",
request.path_info))
form = LoanFormCreate(
institution_id=institution_id,
initial={
"staff": request.user.id,
"reminder_has_been_sent": 0,
"is_returned": False,
},
)
return render(
request,
template_name="crud/loan/create.html",
context={
"form": form,
},
)
}}}

== Modelforms for Loan ==
{{{
#!python
class LoanForm(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

class Meta:
model = Loan
fields = "__all__"


class LoanFormBase(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

class Meta:
localized_fields = [
"borrowed_from_date",
"borrowed_to_date",
"deposit"
]
model = Loan
fields = [
"id",
"borrower_user",
"staff_user",
"item",
"borrowed_from_date",
"borrowed_to_date",
"reminder_has_been_sent",
"is_returned",
"extra_information",
"deposit",
]
widgets = {
"id": forms.NumberInput(),
"staff_user": forms.Select(attrs={"class": "form-control"}),
"borrower_user": forms.Select(attrs={"class": "form-
control"}),
"item": forms.Select(attrs={"class": "form-control", "data-
live-search": True}),
"borrowed_from_date": forms.DateInput(
attrs={"class": "form-control", "type": "date"},
format=locale_format
),
"borrowed_to_date": forms.DateInput(attrs={"class": "form-
control", "type": "date"}),
"reminder_has_been_sent": forms.NumberInput(attrs={"class":
"form-control "}),
"is_returned": forms.CheckboxInput(attrs={"class": "form-
control"}),
"extra_information": forms.Textarea(attrs={"class": "form-
control", "rows": 4}),
"deposit": forms.TextInput(attrs={"class": "form-control"}),
}
labels = {
"staff_user": _("Lender"),
"borrower_user": _("Borrower"),
"item": _("Loaned Asset"),
"borrowed_from_date": _("Loaned From"),
"borrowed_to_date": _("Loaned To"),
"is_returned": _("Returned"),
"extra_information": _("Comments"),
"deposit": _("Deposit"),
"reminder_has_been_sent": _("Reminder Sent"),
}

help_texts = {
"staff_user": _("Select the person responsible for lending the
asset to the borrower."),
"borrower_user": _("Select the person who borrowed the
asset."),
"item": _("Select the asset that has been loaned out."),
"borrowed_from_date": _("Pick the date when the asset was
borrowed."),
"borrowed_to_date": _("Pick the expected return date for the
asset."),
"is_returned": _("Check this box when the asset has been
returned."),
"extra_information": _("Add any relevant comments or
additional information about the loan here."),
"deposit": _("Enter the deposit amount, if applicable."),
"reminder_has_been_sent": _("Check if a reminder has been sent
for this loan."),
}


class LoanFormCreate(LoanFormBase):
def __init__(self, institution_id: int, *args, **kwargs):
super().__init__(*args, **kwargs)
# Items shall belong to the institution
self.fields["item"].queryset =
Item.objects.filter(item_group__institution_id=institution_id)

# Borrower users shall belong to the institution
self.fields["borrower_user"].queryset = User.objects.filter()
institution_staff_ids =
StaffInstitution.objects.filter().values_list("staff_id")
self.fields["staff_user"].queryset =
User.objects.filter().exclude()

class Meta(LoanFormBase.Meta):
localized_fields = [
"borrowed_from_date",
"borrowed_to_date",
"deposit"
]
exclude = ["id", "is_returned"]
widgets = {
"extra_information": forms.Textarea(attrs={"class": "form-
control", "rows": 4}),
"borrowed_from_date": forms.DateInput(
attrs={"class": "form-control", "type": "date"},
),
"borrowed_to_date": forms.DateInput(
attrs={"class": "form-control", "type": "date"},
),
"item": forms.Select(
attrs={
"class": "form-control selectpicker border",
"data-live-search": "true",
"data-show-subtext": "true",
"data-style": "form-control",
}
),
"borrower_user": forms.Select(
attrs={
"class": "form-control selectpicker border",
"data-live-search": "true",
"data-show-subtext": "true",
"data-style": "form-control",
}
),
"staff_user": forms.Select(
attrs={
"class": "form-control selectpicker border ",
"data-live-search": "true",
"data-show-subtext": "true",
"data-style": "form-control",
"": "",
}
),
"reminder_has_been_sent": forms.NumberInput(attrs={"hidden":
None}),
}
}}}

== Input Dates in Images from HTML file ==
{{{
#!jinja
{# ---------------------------------------------------- #}
{# --- Trying out with and without filters and tags --- #}
{{ form.borrowed_to_date }}
{{ form.borrowed_to_date|localize }}
{% localize off %}
{{ form.borrowed_to_date }}
{% endlocalize %}
{% localize on %}
{{ form.borrowed_to_date }}
{% endlocalize %}
{# ---------------------------------------------------- #}
}}}

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

Django

unread,
Sep 19, 2023, 11:46:47 AM9/19/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new
Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by blue-hexagon):

* type: Uncategorized => Bug


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

Django

unread,
Sep 19, 2023, 11:51:48 AM9/19/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new
Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by blue-hexagon:

Old description:

New description:

= Accept-Language Header takes precedence over language set with cookie =

The input localization follows the browsers locale.

In the first image below, my browsers locale is 'da' (Danish/Dansk) while
Django language is en-GB - the form inputs should be localized to en-GB
and *not* danish!

In the second image, my browsers locale is 'en-GB' and Django language is
'da' (Danish) - the form inputs should be localized to danish and not en-
GB!

The images clearly shows the error.

I have provided every relevant piece of information I can think of below
the images.

Nowhere in the Django docs, does it mention that form inputs should be
localized to the browsers locale.

**Image 1**
[[Image(https://i.imgur.com/twLMfDc.png)]]

**Image 2**
[[Image(https://i.imgur.com/HnE2HgC.png)]]

--

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

Django

unread,
Sep 19, 2023, 2:09:04 PM9/19/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: closed
Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution: needsinfo

Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Natalia Bidart):

* status: new => closed
* resolution: => needsinfo


Comment:

Hello, thank you for your ticket and all the details!

Is there any chance that you could provide a minimal Django project to
reproduce this report, including the models? The smallest the example, the
better, to be able to isolate the issue and pursue a ticket resolution.
Also, could you please try with the latest stable Django (4.2) or the
latest pre-release (5.0a1)?

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

Django

unread,
Sep 22, 2023, 2:37:17 PM9/22/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: closed
Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution: needsinfo
Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by blue-hexagon):

Replying to [comment:3 Natalia Bidart]:


> Hello, thank you for your ticket and all the details!
>
> Is there any chance that you could provide a minimal Django project to
reproduce this report, including the models? The smallest the example, the
better, to be able to isolate the issue and pursue a ticket resolution.
Also, could you please try with the latest stable Django (4.2) or the
latest pre-release (5.0a1)?

= Minimal Django project which reproduces the bug (Django 4.2) =

== L10n Bug ==

''Accept-Language Header takes precedence over language set with cookie
when rendering date input form fields''

This is a minimal example of a previously submitted bug - the original
issue can be found here: https://code.djangoproject.com/ticket/34853

In the first example, the language and locale is set to '''en-US''' but
the form fields are localized to '''da_DK'''. The docs make no mention
that this should be the expected behaviour. I also show that output
localizations, such as times and dates strings are localized properly as
they should (see green text in images).

Expected formats:
* da_DK uses a dateformat of dd-MM-yyyy
* en_US uses a dateformat of mm/dd/yyyy

**Please refer to the Github repository which contains a minimal example
as well as the readme, which contains a full analysis with screenshot
documentation and relevant highlights of settings, modelforms and
models.**

https://github.com/blue-hexagon/dj-L10n_dateinput_bug

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

Django

unread,
Sep 22, 2023, 2:40:19 PM9/22/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new

Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by blue-hexagon):

* status: closed => new
* resolution: needsinfo =>


--
Ticket URL: <https://code.djangoproject.com/ticket/34853#comment:5>

Django

unread,
Sep 26, 2023, 12:04:11 AM9/26/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new
Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* cc: Claude Paroz (added)


--
Ticket URL: <https://code.djangoproject.com/ticket/34853#comment:6>

Django

unread,
Sep 28, 2023, 9:38:35 AM9/28/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new
Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Natalia Bidart):

Thank you blue-hexagon for the test project, I'm cloning it right now to
try to reproduce. While I do that, please note that when runninng
`makemigrations` I get this warning:

{{{
WARNINGS:
book_store.Book.borrowed_from_date: (fields.W161) Fixed default value
provided.
HINT: It seems you set a fixed date / time / datetime value as
default for this field. This may not be what you want. If you want to have
the current date as default, use `django.utils.timezone.now`
}}}

It seems that the `default` definition for `borrowed_from_date` should be
the callable `datetime.date.today` and not the actual result of the call.

--
Ticket URL: <https://code.djangoproject.com/ticket/34853#comment:7>

Django

unread,
Sep 28, 2023, 12:55:05 PM9/28/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new
Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by blue-hexagon):

Replying to [comment:7 Natalia Bidart]:


> Thank you blue-hexagon for the test project, I'm cloning it right now to
try to reproduce. While I do that, please note that when runninng
`makemigrations` I get this warning:
>
> {{{
> WARNINGS:
> book_store.Book.borrowed_from_date: (fields.W161) Fixed default value
provided.
> HINT: It seems you set a fixed date / time / datetime value as
default for this field. This may not be what you want. If you want to have
the current date as default, use `django.utils.timezone.now`
> }}}
>
> It seems that the `default` definition for `borrowed_from_date` should
be the callable `datetime.date.today` and not the actual result of the
call.

Corrected it to 'timezone.now' and pushed the change.

When testing it, please note the endpoint is:
**127.0.0.1:8000/book/create/** and not the root url.

Also note, the new repo is Django 4.2 and not 4.1 as the original ticket
is.

--
Ticket URL: <https://code.djangoproject.com/ticket/34853#comment:8>

Django

unread,
Sep 28, 2023, 3:20:23 PM9/28/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new
Component: | Version: 4.1
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage:
form input | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Natalia Bidart):

I have ran and tested the provided Django project. I have reproduced the
behavior as described, and after reading the docs, I think this may be a
valid issue. Though we would need confirmation from Claude in order to
pursue a fix, see below. It's worth noting that there is no issue when the
language cookie is not set.

What makes me doubt is that
[https://docs.djangoproject.com/en/4.2/topics/i18n/translation/#how-
django-discovers-translations the *translation* docs are very clear] that
the cookie should take precedence over the `Accept-Language`, for
translations, **BUT**
[https://docs.djangoproject.com/en/4.2/topics/i18n/formatting/#overview
the format localization docs] say:

>Django’s formatting system is capable of displaying dates, times and
numbers in templates using the format specified for the current locale. It
also handles localized input in forms.
>When it’s enabled, two users accessing the same content may see dates,
times and numbers formatted in different ways, depending on the formats
for their current locale.

But these docs do not mention what is considered `their current locale`.
Is it the cookie? Is it the `Accept-Language` header?

As a user, my personal expectation is to have the language cookie honoured
across a page, including the form date fields. And more so, it feels

--
Ticket URL: <https://code.djangoproject.com/ticket/34853#comment:9>

Django

unread,
Sep 28, 2023, 3:21:52 PM9/28/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new
Component: | Version: dev
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage: Accepted
form input |

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 1

-------------------------------------+-------------------------------------
Changes (by Natalia Bidart):

* ui_ux: 0 => 1
* version: 4.1 => dev
* stage: Unreviewed => Accepted


Comment:

Tentatively accepting given my rationale above, let's see what Claude
thinks :-)

--
Ticket URL: <https://code.djangoproject.com/ticket/34853#comment:10>

Django

unread,
Sep 28, 2023, 3:33:45 PM9/28/23
to django-...@googlegroups.com
#34853: [Date Input Localization] Accept-Language Header Takes Precedence Over
Language Set With Cookie
-------------------------------------+-------------------------------------
Reporter: blue-hexagon | Owner: nobody
Type: Bug | Status: new
Component: | Version: dev
Internationalization |
Severity: Normal | Resolution:
Keywords: l10n localization | Triage Stage: Accepted
form input |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 1
-------------------------------------+-------------------------------------

Comment (by Claude Paroz):

Is the behavior the same if you remove `localized_fields`?

--
Ticket URL: <https://code.djangoproject.com/ticket/34853#comment:11>

Reply all
Reply to author
Forward
0 new messages