How do I get the Django admin to respect grammar cases in languages ββlike Polish?
Django allows you to overwrite verbose_name
and verbose_name_plural
for Model
, which allows us to specify correct plural forms Model
for non-English languages ββ(for example, Kandydaci
as a plural Kandydat
instead of the standard Kandydats
, which looks strange in Polish).
However, this is not enough for languages ββwith grammatical cases. For example, Django Admin happily displays something like this to us:
(Where Zaznacz kandydat do zmiany
means Select kandydat to change
- Kandydat
is a name Model
)
This is not true. In this sentence, the model name must appear in the accusative case , which is kandydata
. However, I cannot simply point out that verbose_name
this Model
is kandydata
, as it will also affect all places where
This is incorrect because the table header should be called Kandydat
not kandydata
.
How to fix it?
source to share
The line is 'Select <verbose_name> to change'
declared inside the main admin view
self.title = title % force_text(self.opts.verbose_name)
as a {{ title }}
template variable
{% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
So touching the inline view is out of the question. But there is another way to do it! You see, Django Admin templates are complete {% block %}
, acting like placeholders to override them. Read more in the official docs overriding admin templates .
So to your question.
- In the root directory of your project, create a directory
templates
(if it doesn't already exist). - The
my_project/templates/
create another oneadmin
. - In
my_project/templates/admin/
create a filechange_list.html
. -
Inside,
my_project/templates/admin/change_list.html
put these:{% extends 'admin/change_list.html' %} {% load myutils_filters %} {% comment %} You have to create an app that will hold all common tags/filters that are re-usable across your entire project. The model class itself is passed as cl.model {% endcomment %} {% block content_title %}{{ block.super|to_accusative:cl.model }}{% endblock %}
-
Inside your file
myutils/templatetags/myutils_filters.py
put:from django import template from django.utils.html import format_html from django.utils.encoding import force_text register = template.Library() @register.filter() def to_accusative(value, model): verbose_name = model._meta.verbose_name # declared in Meta new_name = force_text(model.accusative case()) # a custom class method (lives in your Model) return format_html(value.replace(verbose_name, new_name))
-
Finally, below your application,
models.py
in each model,class
define a methodclassmethod
:from django.db import models from django.utils.translation import ugettext_lazy as _ class MyModel(models.Model): # model fields here def __str__(): return self.a_field class Meta: verbose_name = 'verbose name' verbose_name_plural = 'verbose name plural' # accusative_case = 'accusative name case' # BAD. Raises error. Implement a class method intead ;) @classmethod def accusative_case(cls): # You'll define the Polish translation as soon as you run makemessages return _('Name in english of the accusative case')
-
Launch
manage.py makemessages
,manage.py compilemessages
restart your browser and voila!
Note. The above might look a little hacky, but it works great. Field tested and working.
source to share