Opened 3 weeks ago

Last modified 6 days ago

#36884 assigned Bug

Translation of admin log messages fails due to case inconsistency in field names

Reported by: Meiyer Owned by: Thrishagowdabl
Component: contrib.admin Version: 3.0
Severity: Normal Keywords:
Cc: jaffar Khan Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

The Django Admin builds the log messages using construct_change_message, which looks at the fields of the change form, specifically their labels (https://github.com/django/django/blob/9814676ea75bfe5c5d5244c50ccfe1f652a2f058/django/contrib/admin/utils.py#L618). The helper function turns off the translation when building the change JSON, to apply the translation when a LogMessage is displayed. However, there is a flaw in the logic:

  • the verbose_name parameter of the model field would typically be lower-cased (from the docs: “The convention is not to capitalize the first letter of the verbose_name. Django will automatically capitalize the first letter where it needs to.” ).
  • the labels generated by the forms have the first letter capitalized (from the docs: “the default label for a Field is generated from the field name by converting all underscores to spaces and upper-casing the first letter”) where for Model Forms, “Django will fall back on that model field’s verbose_name and then the field’s attribute name”.

This results in translation mismatch at render time. For example, the log message would include "fields": ["Occupation"] while the translation catalog has only the key “occupation”, coming from that field’s verbose_name. As a result, the field names are not properly translated.

I tracked the issue back to changes introduced in 3.0 and it persists in all versions up to 6.0.

Change History (7)

comment:1 by Thrishagowdabl, 3 weeks ago

Owner: set to Thrishagowdabl
Status: newassigned

comment:2 by Jacob Walls, 3 weeks ago

Summary: Translation of fields in admin log messages works incorrectlyTranslation of admin log messages fails due to case inconsistency in field names
Triage Stage: UnreviewedAccepted

Thanks for the clear report and diagnosis.

comment:3 by Jacob Walls, 3 weeks ago

Patch needs improvement: set

Linters are failing.

comment:4 by jaffar Khan, 13 days ago

Wants to work on this ticket if the current assignee is no longer interested

Last edited 13 days ago by jaffar Khan (previous) (diff)

comment:5 by jaffar Khan, 13 days ago

Cc: jaffar Khan added

comment:6 by master, 7 days ago

I confirm the issue.
The capitalisation is probably done in db\models\fields\__init__.py with "label": capfirst(self.verbose_name),.

For example, this column content: [{'changed': {'fields': ['Status']}}] is rendered in French str as: Modification de « t2>t2:90 » — Modification de Status.
According to the app .po file, the end of the text should be état., or maybe État.

comment:7 by master, 6 days ago

Here is a proposed patch of contrib/admin/utils.py:

--- C:/D/tmp/utils_old.py	Tue Feb 10 11:20:50 2026
+++ C:/D/tmp/utils_new.py	Tue Feb 10 11:21:01 2026
@@ -1,8 +1,10 @@
 def _get_changed_field_labels_from_form(form, changed_data):
     changed_field_labels = []
+    opts = form.instance._meta
     for field_name in changed_data:
         try:
-            verbose_field_name = form.fields[field_name].label or field_name
+            # can't use form.fields[field_name].label because it is wrapped in capfirst()
+            verbose_field_name = opts.get_field(field_name).verbose_name or field_name
         except KeyError:
             verbose_field_name = field_name
         changed_field_labels.append(str(verbose_field_name))

Now, my example is:
column content: [{"changed": {"fields": ["status"]}}]
str of logentry: Modification de « t2>t2:90 » — Modification de état.

Note: See TracTickets for help on using tickets.
Back to Top