Skip to main content

Django Language Settings

Introduction

When building web applications that need to reach users across different regions and languages, implementing proper internationalization (i18n) is crucial. Django provides robust support for creating multilingual websites through its language settings system.

In this tutorial, we'll explore how Django handles language preferences, how to configure supported languages, and how to implement language switching in your applications. By the end, you'll understand how to make your Django site accessible to users regardless of their language preference.

Understanding Django's Language Settings

Django uses a few key settings in your settings.py file to determine which languages your application supports and which language to use for each request.

Core Language Settings

Let's start by looking at the essential settings that control language behavior:

python
# settings.py

# The default language code for your site
LANGUAGE_CODE = 'en-us'

# Whether to enable Django's translation system
USE_I18N = True

# Whether to enable localized formatting of data
USE_L10N = True

# Available languages for your site
LANGUAGES = [
('en', 'English'),
('es', 'Spanish'),
('fr', 'French'),
('de', 'German'),
]

# Location where Django should look for translation files
LOCALE_PATHS = [
BASE_DIR / 'locale',
]

Let's break down what each setting does:

  • LANGUAGE_CODE: Sets the default language for the site. If Django can't determine which language to use for a request, it falls back to this.
  • USE_I18N: When set to True, enables Django's translation system.
  • USE_L10N: When set to True, enables localized formatting of dates, numbers, etc.
  • LANGUAGES: Defines all languages your site supports. Each tuple contains a language code and its display name.
  • LOCALE_PATHS: Tells Django where to find your translation files (.po and .mo files).

Determining the Active Language

Django uses a specific algorithm to determine which language to use for each request. Understanding this process is key to properly implementing language switching.

The Language Resolution Process

Django follows these steps to decide which language to use:

  1. It checks for a language prefix in the URL (if using i18n_patterns)
  2. It looks for a language code in the session
  3. It checks for a cookie named django_language
  4. It examines the Accept-Language HTTP header
  5. It falls back to the LANGUAGE_CODE setting

Let's set up our project to use these mechanisms.

Setting Up URL-based Language Switching

One of the most common approaches is to include the language code in the URL, like /en/about/ and /es/about/.

1. Configure URL Patterns

First, modify your root URLconf to use i18n_patterns:

python
# urls.py
from django.conf.urls.i18n import i18n_patterns
from django.urls import path, include

from . import views

urlpatterns = [
# URLs that don't need internationalization
path('admin/', admin.site.urls),
]

# URLs that should be translated
urlpatterns += i18n_patterns(
path('', views.homepage, name='home'),
path('about/', views.about, name='about'),
prefix_default_language=True, # Show prefix for default language too
)

The prefix_default_language parameter determines whether to include the prefix for the default language. If set to False, the default language won't have a prefix in the URL.

2. Add Language Selector

Let's create a simple language selector that users can use to switch languages:

html
<!-- In your template -->
<div class="language-selector">
<p>{% trans "Select your language" %}:</p>
<ul>
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}

{% for language in languages %}
<li>
<a href="{% url 'set_language' %}" data-language="{{ language.code }}" class="language-link">
{{ language.name_local }}
</a>
</li>
{% endfor %}
</ul>
</div>

<script>
document.querySelectorAll('.language-link').forEach(function(link) {
link.addEventListener('click', function(e) {
e.preventDefault();

const form = document.createElement('form');
form.action = this.getAttribute('href');
form.method = 'post';

const input = document.createElement('input');
input.type = 'hidden';
input.name = 'language';
input.value = this.dataset.language;

const csrfInput = document.createElement('input');
csrfInput.type = 'hidden';
csrfInput.name = 'csrfmiddlewaretoken';
csrfInput.value = document.querySelector('[name=csrfmiddlewaretoken]').value;

form.appendChild(input);
form.appendChild(csrfInput);
document.body.appendChild(form);
form.submit();
});
});
</script>

3. Include Django's Language Views

Make sure to include Django's built-in language views in your URLs:

python
# urls.py
from django.conf.urls.i18n import i18n_patterns

urlpatterns = [
# ... other URL patterns ...
path('i18n/', include('django.conf.urls.i18n')),
]

If you prefer not to use URL-based language selection, you can store the language preference in the session or a cookie.

Session-based Language

Add the LocaleMiddleware to your middleware list:

python
# settings.py
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware', # Must come before LocaleMiddleware
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
# ... other middleware ...
]

Then create a view to set the language:

python
# views.py
from django.http import HttpResponseRedirect
from django.utils.translation import activate

def set_language_view(request):
if request.method == 'POST':
language = request.POST.get('language', 'en')
activate(language)
request.session['django_language'] = language
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

Django's built-in set_language view can set a cookie with the user's language preference:

html
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.path }}">
<select name="language" onchange="this.form.submit()">
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}

{% for language in languages %}
<option value="{{ language.code }}"
{% if language.code == LANGUAGE_CODE %}selected{% endif %}>
{{ language.name_local }}
</option>
{% endfor %}
</select>
</form>

Real-world Example: Multi-language Blog

Let's tie everything together with a simple blog application that supports multiple languages:

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'))
created_at = models.DateTimeField(_('Created at'), auto_now_add=True)

class Meta:
verbose_name = _('Blog Post')
verbose_name_plural = _('Blog Posts')

def __str__(self):
return self.title
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()
return render(request, 'blog/list.html', {
'title': _('Blog Posts'),
'posts': posts
})
html
<!-- templates/blog/list.html -->
{% extends "base.html" %}
{% load i18n %}

{% block content %}
<h1>{% trans "Blog Posts" %}</h1>

<!-- Language selector -->
<div class="language-selector">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.path }}">
<select name="language" onchange="this.form.submit()">
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}

{% for language in languages %}
<option value="{{ language.code }}"
{% if language.code == LANGUAGE_CODE %}selected{% endif %}>
{{ language.name_local }}
</option>
{% endfor %}
</select>
</form>
</div>

<!-- Blog posts -->
<div class="blog-list">
{% for post in posts %}
<article class="post">
<h2>{{ post.title }}</h2>
<div class="meta">
{% blocktrans with date=post.created_at %}
Published on {{ date }}
{% endblocktrans %}
</div>
<div class="content">
{{ post.content }}
</div>
</article>
{% empty %}
<p>{% trans "No posts found." %}</p>
{% endfor %}
</div>
{% endblock %}

After setting this up, you'll need to create translation files for each language using Django's makemessages and compilemessages commands.

Common Pitfalls and Solutions

1. Middleware Order

Make sure the middleware order is correct. LocaleMiddleware should come after SessionMiddleware but before CommonMiddleware.

2. Missing Translation Files

If translations aren't showing up, ensure you've:

  • Created translation files with python manage.py makemessages -l es (for Spanish, for example)
  • Edited the .po files with translations
  • Compiled them with python manage.py compilemessages

3. Forgetting to Mark Strings for Translation

Only strings wrapped in gettext(), gettext_lazy(), or template tags like {% trans %} will be translated.

Best Practices

  1. Use gettext_lazy for model fields: This defers translation until the value is actually accessed.
  2. Create context for ambiguous translations: Use pgettext() when the same word might translate differently based on context.
  3. Use blocktrans for complex phrases: When you need variables within translated text, use the {% blocktrans %} template tag.
  4. Keep translations up to date: Run makemessages regularly as you add new translatable strings.

Summary

Django's language settings provide a flexible system for creating multilingual applications. In this tutorial, we've covered:

  • Core language settings in settings.py
  • How Django determines which language to use
  • URL-based language switching with i18n_patterns
  • Session and cookie-based language preferences
  • Creating a language selector for your users
  • A real-world example with a multilingual blog

By implementing these techniques, you can make your Django application accessible to users around the world in their preferred languages.

Additional Resources

Exercises

  1. Create a Django project with at least two supported languages (e.g., English and Spanish).
  2. Implement URL-based language switching with i18n_patterns.
  3. Add a dropdown language selector to your site's header.
  4. Create a model with translatable fields and generate the translation files.
  5. Challenge: Implement a user preference system that remembers each user's language preference.

By mastering Django's language settings, you'll be able to reach a global audience with your web applications!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)