Introduction
This tutorial shows how to translate texts, URLs and database content.
For example, here is an English blog post:
And here is its German translation:
The text "Title" is defined in the post_detail.html template and translated to "Titel" using Django's default translation system.
The actual title, body, and the slug are stored in the database and translated using the admin (with the help of the django-modeltranslation package).
Prerequisities
Use this to setup a base project:
Django - Blog App Tutorial (Python)
Update Settings
Edit mysite/settings.py and add this line:
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 toLANGUAGE_CODE = 'de'
if you want German to be the default language.
URL Prefix
Edit mysite/settings.py and add LocaleMiddleware
above CommonMiddleware
:
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', # here
'django.middleware.common.CommonMiddleware',
]
Edit mysite/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
)
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.
Translate Text In Templates
Edit templates/blog/post_detail.html. Load the i18n
tag, and use the trans
tag to translate a string:
{% load i18n %}
<div class="post">
<h1>{% trans "Title" %}: {{ post.title }}</h1>
<div class="body">{{ post.body }}</div>
</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
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
Install gettext from here: https://mlocati.github.io/articles/gettext-iconv-windows.html
You probably want the 64 bit static installer.
macOS, Linux
Run these commands:
sudo apt-get update
sudo apt-get install gettext
Then, you can create translation files:
django-admin makemessages -l fi --ignore venv
Edit locale/de/LC_MESSAGES/django.po
and add the translation:
#: .\templates\blog\post_detail.html:3
msgid "Title"
msgstr "Titel" # here
Run this command:
django-admin compilemessages --ignore venv
Restart the development server.
Visit /de/blog/how-to-make-money/
and you should see this:
This is something you might actually want. You might want the slug to be in English for all languages.
Slug And Content Translation
On the other hand, it might make more sense to do something like this:
- /blog/how-to-make-money/ (English version)
- /de/blog/wie-man-geld-verdient/ (German version)
Install django-modeltranslation:
pip install django-modeltranslation
Edit mysite/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
is used to translate the actual language names.- If we don't specify the
LANGUAGES
setting, Django's default value is used, which includes a lot of languages.
Create blog/translation.py:
Create a translation class for the Post
model and register 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 (that you are trying to translate) with the database.
Restart the development server.
Visit /admin/ and edit a blog post:
The first "Title" field shows the currently active translation:
http://127.0.0.1:8000/de/admin/blog/post/1/change/
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:
/admin/ provides the login form in the default language:
Admin URL Translation
You can also translate the admin url: /de/verwaltung/
Edit the mysite/urls.py file, 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
)
- The
gettext_lazy
function translates the string when the value is accessed, not when we call the function.
Run the makemessages
command:
django-admin makemessages -l de --ignore venv
Edit locale/de/LC_MESSAGES/django.po and translate the admin/ path:
#: .\mysite\urls.py:25
msgid "admin/"
msgstr "verwaltung/" # here
Run the compilemessages
command:
django-admin compilemessages --ignore venv
Now you can find the admin page translated to German in here:
http://127.0.0.1:8000/de/verwaltung/
The English translated admin can be accessed here: