Django - Translation Tutorial (Internationalization) (Python)

How to create multilingual websites using Django.

Updated May 11, 2024

Making Money with Django and AI: How to Build SaaS Services Using Python

Learn how to build AI-driven websites with the Django web framework and monetize your services.
Read More
You will receive the book in PDF and ePub formats.

Table of contents

You will learn

  • How to translate static texts.
  • How to translate database content.
  • How to translate URLs.
  • How to translate the admin (including the /admin/ URL).

Settings

Edit settings.py and add this line to it:

LOCALE_PATHS = [BASE_DIR / 'locale'] # here
LANGUAGE_CODE = 'en-us' 
  • LOCALE_PATHS setting is used to specify the directories where the application should look for translation files.
  • LANGUAGE_CODE specifies the default language for the project. Set it to LANGUAGE_CODE = 'de' if you want German to be the default language.

Add LocaleMiddleware above CommonMiddleware:

MIDDLEWARE = [ 
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware', # here
    'django.middleware.common.CommonMiddleware',
] 

URL prefix

Edit urls.py, import i18n_patterns and use it like this:

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

# wrap the paths with i18n_patterns:
urlpatterns = i18n_patterns(
    path('blog/', include('blog.urls')),
    path('admin/', admin.site.urls),
    prefix_default_language=False # add this
)                     
  • i18n_patterns prepends the current active language code to all URL patterns defined inside the function.
  • prefix_default_language=False argument hides the language prefix for the default language.

So, the default language content can be found at /blog/lorem-ipsum/ and its translation at /de/blog/lorem-ipsum/.

Translate text in templates

Let's translate static text. Edit a template and load the i18n tag, and use the trans tag to translate a string:

{% load i18n %}
<div class="about">
    <h1>{% trans "About" %}</h1>
    <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. 
    </p>
</div>

Create a directory in the project's root for the translation files and execute the makemessages command:

mkdir locale
django-admin makemessages -l de --ignore venv

Edit locale/de/LC_MESSAGES/django.po and add the translation:

#: .\templates\about.html:3
msgid "About"
msgstr "Über uns"

Run this command:

django-admin compilemessages --ignore venv

Visit /about/ and you should see the default text:

Visit /de/about/ and you should see the German translation:

Slug and database content translation

You might also want to translate the slug and dynamic content from the database, like this:

  • /blog/lorem-ipsum/ (English version)
  • /de/blog/german-slug/ (German version)

Install django-modeltranslation:

pip install django-modeltranslation

Edit settings.py:

INSTALLED_APPS = [
    'modeltranslation', # here, put it on top
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
]

# add languages to the project:
from django.utils.translation import gettext_lazy as _
LANGUAGES = (
    ('en', _('English')),
    ('de', _('German')),
)
  • gettext_lazy performs the translation when the string is actually used, not when the Python code is evaluated.
  • If we don't specify the LANGUAGES setting, Django's default value is used, which includes a lot of languages.

Create blog/translation.py and add these lines to it:

from modeltranslation.translator import translator, TranslationOptions
from .models import Post

class PostTranslationOptions(TranslationOptions):
    fields = ('title', 'body', 'slug') # specify the fields you want to translate

translator.register(Post, PostTranslationOptions)

Run these commands:

python manage.py makemigrations
python manage.py migrate
python manage.py update_translation_fields
  • Run update_translation_fields if you have an existing project and you have already synced the model fields with the database.

Restart the development server, visit /admin/ and edit a blog post:

Now we have the English post...

...and its German translation:

Admin translation

The admin UI is translated automatically for the added languages.

You can see this in action by visiting /de/admin...

...and /admin/:

Admin URL translation

You can also translate the admin url: /de/verwaltung/. Edit urls.py and make these changes:

from django.contrib import admin
from django.urls import include, path
from django.conf.urls.i18n import i18n_patterns
from django.utils.translation import gettext_lazy as _ # here


urlpatterns = i18n_patterns(
    path('blog/', include('blog.urls')),
    path(_('admin/'), admin.site.urls), # here
    prefix_default_language=False
)  

Run makemessages:

django-admin makemessages -l de --ignore venv

Edit locale/de/LC_MESSAGES/django.po and translate the admin/ path:

#: .\mysite\urls.py:47
msgid "admin/"
msgstr "verwaltung/"

Run compilemessages:

django-admin compilemessages --ignore venv

You can find the admin app translated to German in here: http://127.0.0.1:8000/de/verwaltung/

Troubleshooting: CommandError: Can't find msguniq

Are you getting an error like this: CommandError: Can't find msguniq. Make sure you have GNU gettext tools 0.15 or newer installed.?

Windows

macOS, Linux

Run these commands:

sudo apt-get update
sudo apt-get install gettext

Then, you can create translation files:

django-admin makemessages -l de --ignore venv

Leave a comment

You can use Markdown to format your comment.


Comments

#3 2024.05.16 01:00:51 UTC
· mar*******@gmail.com

Great tutorial, thanks!