Feb. 13, 2022 | Categories: python django
As a first web development project, I wanted to create a blog that was tailored to both English and Spanish-speaking users. Localized blogs like this usually feature different URLs for each language (e.g. /blog/en
, /blog/es
). To avoid this, I used of Django's capabilities and the django-translation-manager
package. Assuming you already have Python installed, let's go through the set-up. We create a virtual environment inside the directory of our choosing and proceed to activate it:
$ python -m virtualenv venv
$ source venv/bin/activate
Now we install Django and the translation manager package within the virtual environment:
(venv) $ pip install django
(venv) $ pip install django-translation-manager
To create the Django project:
(venv) $ django-admin startproject myproject
Now we should have a directory myproject
inside of which there's a similarly named subdirectory, as well as a manage.py
file. We can check our installation by using this command:
(venv) $ python manage.py runserver
Now if we go to localhost:8000
in our browser, we should be greeted with the Django rocket.
To enable translations, we need to edit the settings.py
file within the myproject
subdirectory. We also need to add the translation_manager
to the installed apps, make sure Django's internationalization and localizations settings are set to True
, as well as add the local middleware between the session middleware and common middleware:
settings.py
INSTALLED_APPS = (
...
'translation_manager',
...
)
USE_I18N = True
USE_L10N = True
MIDDLEWARE = [
# Take note of the ordering of these
...
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
The locale
path is where Django will store the django.po
files. These will contain the translations.
import os.path
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
We have to make migrations to set up our database, and migrate to create the translation migration files.
(venv) $ python manage.py makemigrations
(venv) $ python manage.py migrate
Now we have to install gettext
, a set of tools to produce multi-lingual messages.
(venv) $ sudo apt install gettext
At this point we have all the tools we need. Inside the project .py
files which feature strings of text which will be shown o the user, we can import gettext
as follows:
from django.utils.translation import gettext as _
Or gettext_lazy
, to translate strings that are part of modules and forms, when the translation needs to happen at template rendering.
from django.utils.translation import gettext_lazy as _
And thus we can tag a string for translation by wrapping it around _()
, that is:
from django.utils.translation import gettext as _
example = 'string'
tagged = _('string')
class Meta:
labels = {
'name': _('Name'),
'email': _('Email'),
}
These will be written into the .po
file, as we'll see in a moment.
Inside our .html
templates, we can tag strings for translation by using the {% translate %}
and {% blocktranslate %}
tags after putting the {% load i18n %}
at the top of our file:
file.html
{% load i18n %}
<h1>{% trans "string" %}</h1>
<p>{% blocktranslate %} This is an example string.{% endblocktranslate %}<p/>
After tagging the strings, we have to load them into the .po
file by running this command:
(venv) $ django-admin makemessages -l es
Now that we have the strings loaded, we would usually need to navigate to the .po
file and write the desired translations like so:
#. Translators: string
# path/to/template/file.html:10
msgid "string"
msgstr "cadena"
#. Translators: example
# path/to/template/file.html:13
msgid ""
"This is an example"
"string."
msgstr ""
"Este es un ejemplo de"
"cadena."
However, the translation manager gives us a nice admin interface to edit the strings. First we create the superuser by running:
(venv) $ python manage.py createsuperuser
Then we can log in to localhost:8000/admin
, navigate to our translations panel in the translation entries section, load the translations from the .po
file, save our custom translations, update the list and publish to the website. After running our server again, we should see our translations applied.
Now we can create our blog app inside our project by running:
(venv) $ python manage.py startapp blog
To get some ideas on how to make a fully-featured blog application, I used this and this, as well as various other resources. After getting your views and templates set up, you can apply the translation tags and edit the translations in the manager.
However, what if we want our model fields to be translated as well? These can vary, and so if we place variable tags within our translation tags, the tag will pick out only the placeholder name, and not the field contents.
To achieve model translation, we must create models such that they have two fields: one in the original language, and one in the translation language. Such a model might look something like this:
models.py
from django.db import models
class Post(models.Model):
title = models.CharField() # Original field
title_es = models.CharField() # Translation field
body = models.TextField()
body_es = models.TextField()
Thus, when we call our model's field inside a tag in our template, we can write an if
statement to render the field that matches the user's language (provided it exists), or render the original field. Such a statement might look something like this:
file.html
{% load i18n%}
{% get_current_language as LANGUAGE_CODE %}
{% if LANGUAGE_CODE == 'es' %}
<h2>{{ post.title_es }}</h2>
{% elif post.title %}
<h2>{{ post.title }}</h2>
{% endif %}
{% get_current_language as LANGUAGE_CODE %}
{% if LANGUAGE_CODE == 'es' %}
<p>{{ post.body_es }}</p>
{% elif post.body %}
<p>{{ post.body }}</p>
{% endif %}
In this way, all the content on our site can be translated by using the translation manager and the translation fields in our models.
You can subscribe to the blog using RSS.