Skip to main content

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:

python
# 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:

bash
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 _:

python
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:

python
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:

html
{% 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:

html
{% 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:

html
<!-- 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:

python
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:

bash
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:

bash
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:

python
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:

html
{% 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:

python
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

python
# 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

python
# 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

html
{# 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:

python
# Different translations for the word "May"
_("May", context="month name") # "Mayo" in Spanish
_("May", context="verb") # "Poder" in Spanish

In templates:

html
{% translate "May" context "month name" %}

Best Practices for Django Translation

  1. Plan ahead: Design your application with internationalization in mind from the start.

  2. Use lazy translation: Use gettext_lazy for model fields and other strings defined at module level.

  3. Context matters: Provide context for ambiguous terms using the context parameter.

  4. Keep translations updated: Run makemessages regularly as you update your code.

  5. Test in multiple languages: Verify that your UI works properly in all supported languages.

  6. Use placeholders correctly: Always use named placeholders in translatable strings to maintain flexibility for different language structures.

  7. 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:

css
/* 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
<html lang="{{ LANGUAGE_CODE }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>

Include RTL-specific CSS:

css
/* RTL-specific styles */
[dir="rtl"] .sidebar {
float: right;
}

Pluralization

Different languages have different pluralization rules. Django handles this with ngettext:

python
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:

html
{% 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:

  1. Configure your settings for internationalization
  2. Mark strings for translation in Python, templates, and JavaScript
  3. Generate translation files with makemessages
  4. Translate the strings in the .po files
  5. Compile the translations with compilemessages
  6. 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

Exercises

  1. Set up internationalization in a simple Django project and add support for at least two languages.
  2. Create a model with translatable fields and implement the admin interface for it.
  3. Build a language selector that remembers the user's language preference in a cookie.
  4. Implement translations for a form, including error messages and help text.
  5. 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! :)