How to create i18n switcher for Django Admin?

I could create i18n switcher for English and French below in Django following The set_language redirect view and this is how I set up translation(English and French) in Django. *I use Django 4.2.1:

# "core/settings.py"

from django.contrib import admin
from django.urls import path, include
from django.conf.urls.i18n import i18n_patterns

urlpatterns = i18n_patterns(
    path('admin/', admin.site.urls),
    path("my_app1/", include('my_app1.urls')),
)

urlpatterns += [
    path("i18n/", include("django.conf.urls.i18n"))
]
# "templates/index.html"

{% load i18n %}

<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
    <input name="next" type="hidden" value="{{ redirect_to }}">
    <select name="language">
        {% get_current_language as LANGUAGE_CODE %}
        {% get_available_languages as LANGUAGES %}
        {% get_language_info_list for LANGUAGES as languages %}
        {% for language in languages %}
            <option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
                {{ language.name_local }} ({{ language.code }})
            </option>
        {% endfor %}
    </select>
    <input type="submit" value="Go">
</form>

{% translate "Hello" %} {% trans "World" %}

Then, I can switch French to English as shown below:

enter image description here

And, I can switch English to French as shown below:

enter image description here

But, I don't know how to create it for Django Admin.

So, how can I create i18n switcher for Django Admin?

Upvotes: 1

Views: 517

Answers (2)

Amin Basiri
Amin Basiri

Reputation: 184

you must override admin/base.html and translate admin views by i18n_patterns.

you can use this gist

Upvotes: 0

First, set up translation(English and French) following my answer.

Then, you need to create custom_admin.css in core/static/core/admin/css/ and prepare usa_flag.png and france_flag.png in core/static/core/admin/images/ and create __init__.py(Empty file) and i18n_switcher.py in core/templatetags/ and copy base.html from django/contrib/admin/templates/admin/base.html in your virtual environment to templates/admin/ as shown below:

django-project
 |-core
 |  |-settings.py
 |  |-urls.py
 |  |-static
 |  |  └-core
 |  |     └-admin
 |  |        |-css
 |  |        |  └-custom_admin.css # Here
 |  |        └-images
 |  |           |-usa_flag.png # Here
 |  |           └-france_flag.png # Here
 |  └-templatetags
 |     |-__init__.py # Here
 |     └-i18n_switcher.py # Here
 |-my_app1
 |  |-views.py
 |  |-urls.py
 |  |-models.py
 |  |_admin.py
 |  └-apps.py
 |-my_app2
 |-templates
 |  |-admin
 |  |  └-base.html # Here
 |  └-index.html
 └-locale
    └-fr
       └-LC_MESSAGES
          |-django.po
          └-django.mo

And, put the code below to custom_admin.css:

/* "core/static/core/admin/css/custom_admin.css" */ 

img.i18n_flag {
    width: 16px;
    vertical-align: text-top;
}

And, put the code below to i18n_switcher.py:

# "core/templatetags/i18n_switcher.py"

from django import template
from django.conf import settings

register = template.Library()

@register.simple_tag
def switch_i18n(full_path, prefix_lang):
    lang_codes = [list[0] for list in settings.LANGUAGES]

    if prefix_lang not in lang_codes:
        raise Exception('%s is not a supported language code' % prefix_lang)
 
    parts = full_path.split('/')

    parts[1] = prefix_lang
    
    return '/'.join(parts)

And, add <link ... 'core/admin/css/custom_admin.css' %}"/> after <link ... "admin/css/base.css" %}{% endblock %}"> and add <a ...><img ... 'core/admin/images/usa_flag.png' %}"/></a> / and <a ...><img ... 'core/admin/images/france_flag.png' %}"/></a> / after {% block userlinks %} as shown below:

{% "templates/admin/base.html" %}

...
<head>
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}">
{% ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ Here ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ %}
<link rel="stylesheet" type="text/css" href="{% static 'core/admin/css/custom_admin.css' %}"/>
... 
<!-- Container -->
<div id="container">
    ...
    <div id="header">
        ...    
        <div id="user-tools">
            ....
            {% block userlinks %}
                {% ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ Here ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ %} 
                <a href="{% switch_i18n request.get_full_path 'en' %}">
                    <img class="i18n_flag" src="{% static 'core/admin/images/usa_flag.png' %}"/>
                </a> /
                {% ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ Here ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ %} 
                <a href="{% switch_i18n request.get_full_path 'fr' %}">
                    <img class="i18n_flag" src="{% static 'core/admin/images/france_flag.png' %}"/>
                </a> /
                ...

Now, you can switch French to English by clicking on USA flag as shown below:

enter image description here

And, you can switch English to French by clicking on France flag as shown below:

enter image description here

Actually, you can add your code <form ...></form> after <div id="branding">...</div> as shown below to create i18n switcher for English and French in Django Admin:

{% "templates/admin/base.html" %}

...
<!-- Container -->
<div id="container">
    ...
    <div id="header">
        <div id="branding">
        {% block branding %}{% endblock %}
        </div>
        {% ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ Here ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ %}
        <form action="{% url 'set_language' %}" method="post">{% csrf_token %}
            <input name="next" type="hidden" value="{{ redirect_to }}">
            <select name="language">
                {% get_current_language as LANGUAGE_CODE %}
                {% get_available_languages as LANGUAGES %}
                {% get_language_info_list for LANGUAGES as languages %}
                {% for language in languages %}
                    <option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
                        {{ language.name_local }} ({{ language.code }})
                    </option>
                {% endfor %}
            </select>
            <input type="submit" value="Go">
        </form>

Then, you can switch French to English as shown below:

enter image description here

And, you can switch English to French as shown below:

enter image description here

But, I prefer the 1st solution.

Upvotes: 0

Related Questions