Practical guide to internationalize a Django app in 5 steps.

polyglot Django
Image: polyglot Django (License: CC-BY-SA-NC Marcelo Canina)

An easy workflow to understand basic steps



Making an app available in different languages can be a daunting task in Django, because it uses some external resources (e.g.:gettext) that you need to be familiar with, before doing it.

This is a guide put emphasis in the steps required to translate an app, to understand the process of translating strings works in Django at a higher level.

For a detailed explanation of each step, please check the official documentation at:

Basically, Django expects to find files containing translation for each language (message files with a .po file extension).

These files are generated with a command and needs to be updated after you change some of the translation keys in your code.


1. Translate strings

1.1 Translations in code

Translate all your desired strings in your Python code, for example a description in an view:

from django.views.generic.base import TemplateView
from django.utils.translation import gettext as _

class HomePageView(TemplateView):
    template_name = "games/home.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['description'] = _("description")

These are known as: translation strings.

1.2 Translations in templates

Translations in templates requires to load i18n and use the translate templatetag.

e.g.: in a site-wide template templates/base.html:

{% load i18n %} 
	{% translate "This is my title" as my_title %}
	<title>{% block title %}{{my_title}}{% endblock %}</title>

2. Set up paths for translations

Create a locale directory in each app, where each language file will reside.

This directory can be at your project root level / or inside each app where are translations.

2.1 Add the base translate directory

If you use translation in apps registered in the INSTALLED_APPS setting, you can skip this step.

When you have a /locale directory at your root you will have to specify it in Django’s file with the LOCALES_PATH variable like:

LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale'),]

If you skip this step, the template tags at your /templates/base.html for example will compile but won’t detect any other language.

3. Create message files

Use the command makemessages to create the translation files (django.po):

Runs over the entire source tree of the current directory and pulls out all strings marked for translation. It creates (or updates) a message file in the conf/locale (in the django tree) or locale (for projects and applications) directory. You must run this command with one of either the –locale, –exclude, or –all options.

We create a translation file for Spanish: ./ makemessages --locale es.

$ ./ makemessages --locale es
processing locale es

They would look like: $APPPATH/locale/<language>/LC_MESSAGES/django.po or like /locale/<language>/LC_MESSAGES/django.po at root level.

For example, with an app called games, the tree structure after the command is run will look similar to:

β”œβ”€β”€ db.sqlite3
β”œβ”€β”€ games
β”‚Β Β  β”œβ”€β”€
β”‚Β Β  β”œβ”€β”€
β”‚Β Β  β”œβ”€β”€
β”‚Β Β  β”œβ”€β”€ locale
β”‚Β Β  β”‚Β Β  └── es
β”‚Β Β  β”‚Β Β      └── LC_MESSAGES
β”‚Β Β  β”‚Β Β          └── django.po
└── locale
    └── es
        └── LC_MESSAGES
            └── django.po

And each file looking like:


#: games/
msgid "This is my description"
msgstr ""

Any translation not in games app, like for example a template at root directory at templates/base.html, would appear at base: /locale/es/LC_MESSAGES/django.po

#: templates/base.html:6
msgid "This is my title"
msgstr ""
If you didn't create any locale directory you will see: CommandError: Unable to find a locale path to store translations for file

4. Translate the strings

Go to each django.po file and translate put the translation of msgid into msgstr.

For example: /locale/es/LC_MESSAGES/django.po:

#: games/
msgid "This is my description"
msgstr "Esta es mi descripciΓ³n"

5. Compile translations

To make it possible for Django to understand each translation, we compile them with ./ compilemessages.

Compiles .po files created by makemessages to .mo files for use with the built-in gettext support

$ ./ compilemessages
processing file django.po in /locale/es/LC_MESSAGES
processing file django.po in /games/locale/es/LC_MESSAGES



To test it works you can change the default language of the website in using: LANGUAGE_CODE = 'es' and running the local server.


Every time you modify or create a new translation string, you will have to run again:

  • makemessages (if adding or moving translation strings)
  • compilemessages (when some translation changes)


Marcelo Canina
I'm Marcelo Canina, a developer from Uruguay. I build websites and web-based applications from the ground up and share what I learn here.
comments powered by Disqus

Except as otherwise noted, the content of this page is licensed under CC BY-NC-ND 4.0 . Terms and Policy.

Powered by SimpleIT Hugo Theme