Multi-language blog app in Django

Multi-language blog app in Django

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.

RSS Feed

You can subscribe to the blog using RSS.

0 comments

Leave a comment