Are you looking to adapt your Django application to different linguistic and cultural settings? From a developer starting out on a project to one wanting to adapt an existing Django application, this beginner’s guide talks about the nuances of working using the process of i18n in Django.
Mastering software internationalization (i18n) in Django is essential for creating applications that can effectively reach and engage diverse global audiences.
First, we’ll cover how you can modify your Django application to enable i18n and then how to integrate your i18n with Lokalise. Then, we’ll talk about various techniques in Django that may help you with i18n concepts.
You may also be interested in learning more advanced Django I18n concepts.
Check out how our translation management system can help you translate your apps faster.
Step 1: Prepare your Django Project for I18n with Lokalise
1.1 Setup New Project
Let us start by creating a project in Django using:
django-admin startproject blog
The directory structure of your project is as follows:
blog
├── blog
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3
└── manage.py
1.2 Enable I18n in Django
The first task before we get started with any of the techniques is to enable i18n in Django. By default, Django is geared up to handle 18n. If you navigate to your project’s settings.py
, you will notice that the variable USE_I18N
is set to True
. Even if your project does not use i18n, this can remain enabled in Django as it causes no overhead to your overall project.
USE_I18N = True
Also, you can set the default language using the variable LANGUAGE_CODE
in the same settings.py
file.
LANGUAGE_CODE = 'en'
Next, you can set up the languages that you plan to support in your Django application:
LANGUAGES = [
('en','English'),
('bn', 'Bengali')
]
You can also set the variable LANGUAGE_BIDI
, which decides the direction in which the text is read. It should be set to True
for right-to-left languages like Arabic, and to False
otherwise.
1.3 Start a New Django App
Next, let’s start an application called blogs
to test our i18n techniques on:
python manage.py startapp blogs
This creates the basic structure of an application within a Django project, as shown below:
blog
├── blog
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3
├── manage.py
└── blogs
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ └── __init__.py
├── models.py
├── templates
├── tests.py
├── urls.py
└── views.py
1.4 Create Translation Files in Django
Next, we need to start a makemessages
process in Django, which automatically creates and updates PO files for the application to use. You may encounter an error with the following command if gettext
is not installed on your local system:
./manage.py makemessages -l en
The last argument, en
sets the language for translation. You can run this file from the root of the project or the application directory. This script essentially scans your project for all strings that require translation management system and identifies those that need to be translated. The following is the updated structure of the project:
blog
├── blog
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3
├── manage.py
└── blogs
├── __init__.py
├── admin.py
├── apps.py
├── locale
│ └── en
│ └── LC_MESSAGES
│ └── django.po
├── migrations
│ └── __init__.py
├── models.py
├── templates
├── tests.py
├── urls.py
└── views.py
Notice that a locale
directory has been created within the project. In this, a directory for each language is created. The django.po
file has been created within the LC_MESSAGES
directory, which contains all strings for translation. We will now see how you can integrate your Django application with your Lokalise account.
A PO file generated by Django looks like this:
# blogs/locale/de/LC_MESSAGES/django.po
#: templates/blogs/index.html:3
msgid "Hello World"
msgstr ""
You can edit the PO file to fill in the msgstr
values that store the translations.
Step 2: Integrate with Lokalise
2.1 Setup Lokalise CLI
Before you can build an interface between your Django application and your Lokalise application, you need to install the Lokalise CLI client. Here are the installation instructions for the CLI client. The latest version of the CLI tool is now v2 — make sure you upgrade if you are using the older version.
If you use a Mac, installation of the CLI client is carried out through Homebrew. Run the following commands to download and install v2 of the Lokalise CLI client:
brew tap lokalise/brew
brew install lokalise
If you do not use Homebrew, you can download the installer directly.
On Linux systems, you can download the installation script and run it in a single command as shown below:
curl -sfL https://raw.githubusercontent.com/lokalise/lokalise-cli-2-go/master/install.sh | sh
Alternately, you can install Lokalise CLI v2 using the installer for Linux (32 bit | 64 bit).
If you are working on Windows, you can only install the CLI client using the installers (32 bit | 64 bit).
2.2 Configure the CLI tool
Once you have installed the CLI, the command lokalise2
is available for you to use. Any interaction that you perform with your Lokalise account is validated through a token. A token essentially mimics your user access and can be generated from your Lokalise account. Additionally, if you are working on a certain project within Lokalise, you also need to supply the project ID.
You can save the token and project IDs in the /etc/lokalise.cfg
file or supply them as parameters to every lokalise2
command. For instance:
Token = "xxxxxxxxxx"
Project = "xxxxx.xxxxx"
Please note that supplying the token in your commands may save it to your bash history, which is a potential security risk.
2.3 Exchange Files between Lokalise and your Django Application
To upload a file to your Lokalise project, run the following command and replace <token>
and <project_id>
with your actual tokens and project IDs:
lokalise2
--token <token>
--project-id <project_id>
file upload
--file "locale/en/LC_MESSAGES/default.po"
--lang-iso en
You can download the files from your Lokalise project using the following command:
lokalise2
--token <token>
--project-id <project_id>
file download
--format po
--filter-langs en
--original-filenames=true
--directory-prefix ""
--unzip-to "locale/en/LC_MESSAGES/"
You will need to re-run the command to download the files for each language.
Step 3: Set a Locale in Django
3.1 Use Inbuilt Functions in Django
Django comes with a default view django.conf.urls.i18n
that sets the user’s language in Python. You can simply set a particular URL to trigger this function. For example:
path('i18n/', include('django.conf.urls.i18n')),
This view expects the language
parameter as a POST
variable, which saves the current user’s language preference in the session. In addition to this, there is an optional next
parameter that sets the URL to which the view should redirect after setting the language.
3.2 Set Locale Settings Manually
While the default implementation is good for basic i18n, you may need to set additional parameters to set the locale to store variables, such as a geography, in addition to the language. To set such a variable, you would need to create a custom view. In this example, let’s manually set a language ID in our Django application. You can follow the same process to set any other variable related to the locale of the user.
First, set the URL pattern in your application’s urls.py
file as shown below. We set the variable language_id
as a GET
variable embedded within the URL. Whenever someone visits the URL /your_app/set_language/15/
, Django will call up the set_language
view with the parameter language_id
as 15
.
urlpatterns = patterns( 'my_app.views', (r'^set_language/(?P<language_id>d+)/$', 'set_language') )
Now we’ll define the set_language()
view to set a session variable to the language_id
that has come as a part of the GET
payload.
def set_language(request): if request.GET.has_key('language_id'): # Set language in Session variable # Redirect to home request.session['language_id'] = request.GET['language_id'] return HttpResponseRedirect('/')
Translation of Text: Integrate with gettext
in Python
We have explored the usage of the gettext
module in Python i18n. Django has a wrapper in its translation module. The following view searches for the msgid
“Hello World” in the current locale’s PO file and returns the output as an HTTP response.
from django.utils.translation import gettext as _ def display_message(request): output = _("Hello World") return HttpResponse(output)
Here is the part of the PO file that is relevant to this translation and here is the translation if the language is set of Bengali:
msgid "Hello World"
msgstr "ওহে বিশ্ব"
The HTTP response would simply be ওহে বিশ্ব
, i.e., the translated string in the PO file.
The argument to the gettext
function may be any string. For instance, if you would like to print a string that displays how many days ago you last logged in, you can modify the function as shown below.
def my_view(request, day): if day > 1: output = _('You logged in %(day)s days ago.') % {'day': day} else: output = _('You logged in %(day)s day ago.') % {'day': day} return HttpResponse(output)
The corresponding files to handle such a situation in the PO file are shown below:
msgid "You logged in %d day ago."
msgid_plural "You logged in %d days ago."
msgstr[0] "আপনি একদিন আগে লগ ইন করেছেন"
msgstr[1] "আপনি %d দিন আগে লগ ইন করেছেন"
Lazy Translation with Django
If you follow this path of translation, Django translates all strings on the go. An interesting feature of Django is the ability to defer translation until it is absolutely necessary.
Django has a pre-defined function, gettext_lazy()
, which translates strings lazily. The translation takes place when the application needs to use the value of a string, and not when the view is called up.
from django.utils.translation import gettext_lazy as _ def display_message(request): output = _("Hello World") return HttpResponse(output)
In this example, the translation does not occur until the value needs to be sent as an HTTP response.
Django i18n in Templates
While we have spoken extensively about i18n in the back end. In such use cases, you send the translated strings directly to the front end, which you can simply display in the templating engine. You can also translate a string from Django templates.
To use this feature, you first need to enable it in the templating engine. You need to load the i18n
module if you would like to translate a string using the templates. Next, use the trans
keyword followed by the string to translate, as shown below:
{% extends 'admin.html' %} {% load i18n %} {% block content %} <h1>{% trans 'Hello World' %}</h1> {% endblock %}
Translations in Django with JavaScript
The gettext
module is available for you to use only through the backend in Python; therefore, it is not possible for you to translate using gettext
in JavaScript. Furthermore, your JavaScript code would not have direct access to the translation files.
Django provides a solution for passing the translations to JavaScript. This enables you to call the gettext()
function from within your JavaScript code.
First, enable the URL where JavaScript will get the required resources.
from django.views.i18n import JavaScriptCatalog urlpatterns = [ path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog') ]
Next, call the catalog from your templates to fetch the translation resources.
https://gist.github.com/sdaityari/90bcbf05b19db2c60946e6a6953eb669
You can call the gettext()
function, just like you would in Python, to get a related translation.
$ console.log(gettext('Hello World'));
ওহে বিশ্ব
Here is a complete list of gettext
related functions that you can call from within your JavaScript code.
Final Thoughts on Django I18n
In this tutorial, we explored the topic of i18n in Django. Here is what we learned to do:
- Set up a Django project and enable I18n
- Create and manage translations in Django
- Integrate the translations in your Django application with your Lokalise account
- Translate strings in Django and work with lazy translations
- Translate strings on the go within templates
- Integrate translations with JavaScript in Django