Django Translation
Translation is a key part of Django's internationalization framework. It allows your application to present its content in different languages based on user preferences. In this guide, we'll explore how to implement translations in your Django projects to make your web applications truly global.
Introduction to Django Translation
Django's translation system is based on GNU gettext, a widely used standard for internationalization. The translation process involves marking strings in your code as translatable, extracting those strings to message files, translating the messages, and then compiling them for use in your application.
Django's translation features allow you to:
- Mark strings for translation in Python code, templates, and JavaScript
- Generate translation files for different languages
- Switch languages based on user preferences
- Format dates, times, and numbers according to locale conventions
Setting Up Translation in Your Django Project
Before we start translating content, we need to configure our Django project properly.
Step 1: Configure Settings
First, ensure your settings.py
file is properly configured:
# settings.py
# Enable internationalization
USE_I18N = True
# List of languages your application supports
LANGUAGES = [
('en', 'English'),
('fr', 'French'),
('es', 'Spanish'),
]
# Default language
LANGUAGE_CODE = 'en'
# Location of translation files
LOCALE_PATHS = [
BASE_DIR / 'locale',
]
# Add the LocaleMiddleware
MIDDLEWARE = [
# ...
'django.middleware.locale.LocaleMiddleware',
# ...
]
The LocaleMiddleware
must be placed after SessionMiddleware
and before CommonMiddleware
.
Step 2: Create Locale Directory
Create a directory structure for your translations:
mkdir -p locale/en/LC_MESSAGES
mkdir -p locale/fr/LC_MESSAGES
mkdir -p locale/es/LC_MESSAGES
Marking Strings for Translation
In Python Code
To mark strings in Python code for translation, use the gettext
function, typically imported as _
:
from django.utils.translation import gettext as _
def my_view(request):
output = _("Welcome to my site.")
return render(request, 'my_template.html', {'message': output})
You can also use gettext_lazy
for strings that should be translated when they are accessed rather than when they are defined:
from django.utils.translation import gettext_lazy as _
class MyModel(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(help_text=_("Enter a brief description"))
In Templates
For Django templates, first load the i18n template tag library:
{% load i18n %}
<h1>{% translate "Welcome to my site." %}</h1>
<p>{% blocktranslate %}This is a longer paragraph that needs translation.{% endblocktranslate %}</p>
For variables in translations, use:
{% blocktranslate with username=user.username %}Welcome, {{ username }}!{% endblocktranslate %}
In JavaScript
To translate strings in JavaScript, you'll need to use the Django JavaScript translation catalog:
<!-- In your template -->
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript">
alert(gettext('Welcome to my site.'));
</script>
Add a URL pattern in urls.py
:
from django.views.i18n import JavaScriptCatalog
urlpatterns = [
# ...
path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]
Creating and Compiling Translation Files
Step 1: Extract Messages
Once you've marked strings for translation, extract them into message files:
django-admin makemessages -l fr
django-admin makemessages -l es
This creates or updates .po
files in the locale directories. For example, for French:
locale/fr/LC_MESSAGES/django.po
Step 2: Translate Messages
Edit the .po
files to provide translations. Each file contains entries like:
#: templates/myapp/index.html:10
msgid "Welcome to my site."
msgstr "Bienvenue sur mon site."
Edit the msgstr
value to provide the translation for each msgid
.
Step 3: Compile Messages
After translating, compile the messages:
django-admin compilemessages
This creates .mo
files that Django uses to load translations at runtime.
Language Switching
URL-based Language Prefix
Django's LocaleMiddleware
can detect the language from the URL. Add the following to your urls.py
:
from django.conf.urls.i18n import i18n_patterns
from django.urls import path, include
urlpatterns = [
# URLs not to be translated
path('admin/', admin.site.urls),
]
# Translatable URLs
urlpatterns += i18n_patterns(
path('', include('myapp.urls')),
prefix_default_language=False, # Don't prefix the default language
)
With this configuration, you'll get URLs like /fr/about/
for the French version of your about page.
Language Selector Form
Add a language selector to your templates:
{% load i18n %}
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}">
<select name="language" onchange="this.form.submit()">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% for lang_code, lang_name in LANGUAGES %}
<option value="{{ lang_code }}" {% if lang_code == LANGUAGE_CODE %}selected{% endif %}>
{{ lang_name }}
</option>
{% endfor %}
</select>
</form>
Add this URL pattern to enable the language selection view:
from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path
urlpatterns = [
path('i18n/', include('django.conf.urls.i18n')),
# ... your other URL patterns
]
Real-World Example: A Multilingual Blog
Let's build a simple multilingual blog post model and view:
Models
# models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
class BlogPost(models.Model):
title = models.CharField(_('title'), max_length=200)
content = models.TextField(_('content'))
pub_date = models.DateTimeField(_('publication date'), auto_now_add=True)
class Meta:
verbose_name = _('blog post')
verbose_name_plural = _('blog posts')
def __str__(self):
return self.title
Views
# views.py
from django.shortcuts import render
from django.utils.translation import gettext as _
from .models import BlogPost
def blog_list(request):
posts = BlogPost.objects.all().order_by('-pub_date')
page_title = _("Blog Posts")
return render(request, 'blog/list.html', {
'posts': posts,
'page_title': page_title,
})
Templates
{# blog/list.html #}
{% load i18n %}
<h1>{{ page_title }}</h1>
{% if posts %}
<ul>
{% for post in posts %}
<li>
<h2>{{ post.title }}</h2>
<p>{{ post.content|truncatewords:30 }}</p>
<p>{% blocktranslate with date=post.pub_date|date:"F j, Y" %}Published on {{ date }}{% endblocktranslate %}</p>
</li>
{% endfor %}
</ul>
{% else %}
<p>{% translate "No posts available." %}</p>
{% endif %}
<p>{% translate "Thank you for visiting our blog!" %}</p>
Translation Context
Sometimes the same word in English may have different translations depending on context. Use the context
parameter to disambiguate:
# Different translations for the word "May"
_("May", context="month name") # "Mayo" in Spanish
_("May", context="verb") # "Poder" in Spanish
In templates:
{% translate "May" context "month name" %}
Best Practices for Django Translation
-
Plan ahead: Design your application with internationalization in mind from the start.
-
Use lazy translation: Use
gettext_lazy
for model fields and other strings defined at module level. -
Context matters: Provide context for ambiguous terms using the
context
parameter. -
Keep translations updated: Run
makemessages
regularly as you update your code. -
Test in multiple languages: Verify that your UI works properly in all supported languages.
-
Use placeholders correctly: Always use named placeholders in translatable strings to maintain flexibility for different language structures.
-
Document translation requirements: Provide guidelines for translators explaining any context or special formatting requirements.
Common Challenges and Solutions
Long Translations
Some languages require more space than English. Ensure your UI can handle longer texts:
/* Allow elements to expand based on content */
.translatable-content {
min-width: 100px;
max-width: 300px;
height: auto;
}
Right-to-Left Languages
For RTL languages like Arabic and Hebrew, add the dir
attribute:
<html lang="{{ LANGUAGE_CODE }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
Include RTL-specific CSS:
/* RTL-specific styles */
[dir="rtl"] .sidebar {
float: right;
}
Pluralization
Different languages have different pluralization rules. Django handles this with ngettext
:
from django.utils.translation import ngettext
def display_count(count):
return ngettext(
'There is %(count)d object.',
'There are %(count)d objects.',
count
) % {'count': count}
In templates:
{% blocktranslate count counter=list|length %}
There is {{ counter }} object.
{% plural %}
There are {{ counter }} objects.
{% endblocktranslate %}
Summary
Django's translation system provides a comprehensive framework for making your web applications available in multiple languages. By properly marking strings for translation, generating message files, and implementing language switching, you can create a truly global application.
Remember these key steps:
- Configure your settings for internationalization
- Mark strings for translation in Python, templates, and JavaScript
- Generate translation files with
makemessages
- Translate the strings in the
.po
files - Compile the translations with
compilemessages
- Implement language switching mechanisms
With these tools at your disposal, you can reach a global audience and provide a native experience for users around the world.
Additional Resources
- Django's Official Translation Documentation
- GNU gettext documentation
- Weblate - A web-based translation tool for managing translation files
- Transifex - A platform for managing translations with collaboration features
Exercises
- Set up internationalization in a simple Django project and add support for at least two languages.
- Create a model with translatable fields and implement the admin interface for it.
- Build a language selector that remembers the user's language preference in a cookie.
- Implement translations for a form, including error messages and help text.
- Create a multilingual blog site with content available in multiple languages.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)