Django Translation Strings
Introduction
When building web applications with Django that need to support multiple languages, translation strings are your primary tool for making text content translatable. Django's translation system is based on GNU gettext, providing a robust framework to mark strings for translation and then render them in the appropriate language based on the user's preference.
In this guide, we'll explore how Django handles translation strings, how to mark text for translation in your Python code and templates, and how to use these features to create a truly international web application.
Translation String Basics
What Are Translation Strings?
Translation strings are pieces of text in your Django application that are marked for translation. When a user accesses your site, Django renders these strings in their preferred language if a translation is available.
Setting Up Translations
Before we dive into translation strings, let's ensure our Django project is properly configured for internationalization:
# settings.py
MIDDLEWARE = [
# ...
'django.middleware.locale.LocaleMiddleware',
# ...
]
LANGUAGE_CODE = 'en-us' # Default language
USE_I18N = True # Enable internationalization
USE_L10N = True # Enable localization
LANGUAGES = [
('en', 'English'),
('fr', 'French'),
('es', 'Spanish'),
# Add more languages as needed
]
LOCALE_PATHS = [
os.path.join(BASE_DIR, 'locale'),
]
The LOCALE_PATHS
setting tells Django where to look for translation files. Make sure to create this directory structure.
Marking Strings for Translation in Python Code
Django provides several functions to mark strings for translation in your Python code.
The gettext
Function
The most common function is gettext()
, which is typically imported as an alias _
.
from django.utils.translation import gettext as _
def my_view(request):
output = _("Welcome to my site.")
return render(request, 'my_template.html', {'message': output})
When this view is processed, if the user's language is set to Spanish, they'll see "Bienvenido a mi sitio." (assuming you've provided this translation).
Lazy Translation
Sometimes you need to translate a string but don't want the translation to happen immediately, such as at module load time:
from django.utils.translation import gettext_lazy as _
class MyModel(models.Model):
name = models.CharField(_('name'), max_length=100)
description = models.TextField(_('description'), blank=True)
The gettext_lazy()
function marks these strings for translation but doesn't actually translate them until they're rendered to a string, which is perfect for model fields.
Handling Pluralization
For strings that need different forms based on a count, use ngettext()
:
from django.utils.translation import ngettext
def display_items(count):
message = ngettext(
'There is %(count)d item.',
'There are %(count)d items.',
count
) % {'count': count}
return message
Input:
print(display_items(1)) # With English selected
print(display_items(5)) # With English selected
Output:
There is 1 item.
There are 5 items.
Translation Strings in Templates
Django also allows you to mark strings for translation in your templates.
Using the {% translate %}
Template Tag
First, load the internationalization tags in your template:
{% load i18n %}
<h1>{% translate "Welcome to our website" %}</h1>
<p>{% translate "This content is translatable" %}</p>
Template Tags with Variables
You can include variables in translated strings using the blocktranslate
tag:
{% load i18n %}
{% blocktranslate with user_name=user.name %}
Hello, {{ user_name }}! Welcome to our website.
{% endblocktranslate %}
Handling Pluralization in Templates
Similar to Python code, you can handle pluralization in templates:
{% load i18n %}
{% blocktranslate count counter=list|length %}
There is {{ counter }} item in the list.
{% plural %}
There are {{ counter }} items in the list.
{% endblocktranslate %}
Context-Specific Translations
Sometimes the same word in English might translate differently in another language depending on context. Django handles this with the pgettext()
function:
from django.utils.translation import pgettext
month = pgettext("month name", "May")
verb = pgettext("verb", "May")
In templates:
{% load i18n %}
{% translate "May" context "month name" %}
{% translate "May" context "verb" %}
Creating Translation Files
After marking strings for translation, you need to create translation files:
- Run the makemessages command:
django-admin makemessages -l es # Create/update Spanish translation file
-
This creates/updates a
.po
file in your locale directory. Edit this file to add translations. -
Compile the translations:
django-admin compilemessages
Here's a sample .po
file entry:
#: models.py:10
msgid "Welcome to my site."
msgstr "Bienvenido a mi sitio."
Real-World Examples
Multi-language Blog Post
# 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'))
class Meta:
verbose_name = _('blog post')
verbose_name_plural = _('blog posts')
Localized Date Formatting
# views.py
from django.utils import timezone
from django.utils.formats import date_format
from django.utils.translation import get_language
def event_view(request):
event_date = timezone.now()
# Format date according to the current language
formatted_date = date_format(event_date, format='DATETIME_FORMAT', use_l10n=True)
return render(request, 'event.html', {'date': formatted_date})
Language Selector
<!-- language_selector.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 CURRENT_LANGUAGE %}
{% get_available_languages as LANGUAGES %}
{% for lang_code, lang_name in LANGUAGES %}
<option value="{{ lang_code }}" {% if lang_code == CURRENT_LANGUAGE %}selected{% endif %}>
{{ lang_name }}
</option>
{% endfor %}
</select>
</form>
Remember to include Django's built-in language selection view in your URLs:
# urls.py
from django.conf.urls.i18n import i18n_patterns
from django.urls import path, include
urlpatterns = [
path('i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
path('', include('myapp.urls')),
)
Best Practices
-
Mark All User-Facing Strings: Even if you only support one language now, marking strings makes future translations easier.
-
Use Context When Necessary: Different meanings of the same word require context markers.
-
Be Careful with Variables: Sentence structure varies between languages, so avoid constructing sentences from fragments.
-
Keep Translations Updated: Run
makemessages
regularly as you add new content. -
Use Lazy Translation: In models and anywhere that strings are evaluated during module import.
-
Test Your Translations: Verify how your site looks in each supported language.
Common Pitfalls
-
Forgetting Apostrophes: Strings like
_("Don't forget me")
need special handling due to the quote in "Don't". -
String Concatenation: Avoid
_("Hello") + " " + name
. Instead, use_("Hello %(name)s") % {'name': name}
. -
Translating Settings: Settings are loaded before the translation system, so they can't be translated directly.
Summary
Django's translation system provides powerful tools for internationalizing your web application. By properly marking strings for translation in both Python code and templates, you can create a site that offers a localized experience to users around the world.
The basic workflow is:
- Mark strings for translation using gettext functions
- Generate message files with
makemessages
- Translate the strings in
.po
files - Compile translations with
compilemessages
- Ensure proper language selection in your application
With these tools and techniques, you can make your Django application accessible to users regardless of their language preference.
Additional Resources
- Django's Official Translation Documentation
- GNU gettext Documentation
- Weblate - A web-based translation management system
Exercises
-
Create a simple Django application with at least three views, and mark all user-facing strings for translation.
-
Add support for at least two languages in your application.
-
Implement a language selector that allows users to switch between available languages.
-
Create a model with translatable fields and verbose names.
-
Practice handling pluralization in both Python code and templates.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)