Skip to main content

Django Locale Middleware

Introduction

In our increasingly connected world, applications often need to cater to users from various linguistic backgrounds. Django's Locale Middleware makes it possible to build multilingual applications by managing language selection and translation preferences automatically. This middleware is a key component of Django's internationalization (i18n) framework.

In this tutorial, you'll learn how the LocaleMiddleware works, how to configure it, and how to leverage it to create applications that speak your users' languages.

What is Locale Middleware?

LocaleMiddleware is a built-in Django middleware that determines the user's preferred language based on various signals like browser preferences, URL parameters, cookies, or session settings. It then activates the appropriate language for the current request, ensuring that your application displays content in the user's preferred language.

How to Enable Locale Middleware

To use Django's Locale Middleware, you first need to add it to your project's MIDDLEWARE setting in settings.py:

python
MIDDLEWARE = [
# other middleware...
'django.middleware.locale.LocaleMiddleware',
# other middleware...
]

Important: The position of LocaleMiddleware in the list matters:

  • It should be placed after SessionMiddleware and CacheMiddleware (if used), as it might use session data
  • It should come before CommonMiddleware if you use APPEND_SLASH and PREPEND_WWW features

Configuring Internationalization Settings

Before using Locale Middleware, you need to configure Django's internationalization settings in your settings.py file:

python
# Internationalization settings
USE_I18N = True # Enable internationalization
USE_L10N = True # Enable localization
USE_TZ = True # Enable timezone support

# Available languages
from django.utils.translation import gettext_lazy as _
LANGUAGES = [
('en', _('English')),
('es', _('Spanish')),
('fr', _('French')),
# Add more languages as needed
]

# Default language code
LANGUAGE_CODE = 'en'

# Path where Django looks for translation files
LOCALE_PATHS = [
BASE_DIR / 'locale',
]

How Locale Middleware Determines the User's Language

The Locale Middleware uses the following order of preference to determine which language to activate for each request:

  1. Language prefix in the URL pattern (if you use i18n_patterns)
  2. Language from the language session parameter (if available)
  3. Language from a cookie (typically called django_language)
  4. Language from the Accept-Language HTTP header (browser preferences)
  5. The global LANGUAGE_CODE setting

Creating a Multilingual URL Configuration

Django provides the i18n_patterns function to create URL patterns that include the language code prefix:

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

urlpatterns = [
# URLs that don't need a language prefix
path('api/', include('myapp.api.urls')),
]

# URLs that will have language prefix, e.g., /en/about/, /es/about/, etc.
urlpatterns += i18n_patterns(
path('about/', views.about, name='about'),
path('contact/', views.contact, name='contact'),
# Add more URL patterns here
prefix_default_language=True # Set to False if you don't want prefix for the default language
)

Language Switching Example

One common function in multilingual sites is allowing users to switch languages. Here's a simple example of a language selection view:

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

def set_language(request):
lang_code = request.GET.get('lang', settings.LANGUAGE_CODE)

# Validate that the language code is supported
valid_languages = [code for code, name in settings.LANGUAGES]
if lang_code not in valid_languages:
lang_code = settings.LANGUAGE_CODE

# Set the language for this session
translation.activate(lang_code)
response = HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))

# Set the language cookie
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)

return response

And a simple template for language selection:

html
<!-- language_selector.html -->
<div class="language-selector">
<p>{% trans "Select language" %}:</p>
<ul>
{% for lang_code, lang_name in LANGUAGES %}
<li>
<a href="{% url 'set_language' %}?lang={{ lang_code }}">
{{ lang_name }}
</a>
</li>
{% endfor %}
</ul>
</div>

Translating Content

To make your content translatable, you'll need to:

  1. Mark strings for translation in your Python code and templates
  2. Generate message files
  3. Translate message files
  4. Compile message files

Here's a quick example of marking strings for translation:

python
# In Python code
from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy as _lazy

# For immediate translation
greeting = _("Hello, world!")

# For lazy translation (in models, forms definitions, etc.)
class MyModel(models.Model):
title = models.CharField(_lazy("Title"), max_length=100)

And in templates:

html
<!-- In templates -->
{% load i18n %}

<h1>{% trans "Welcome to our website" %}</h1>

{% blocktrans with username=user.username %}
Hello, {{ username }}! How are you today?
{% endblocktrans %}

Real-world Use Case: E-commerce Site with Multiple Languages

Let's look at a practical example of how you might implement a multilingual e-commerce product page:

python
# models.py
from django.db import models
from django.utils.translation import gettext_lazy as _

class Product(models.Model):
# Using TranslationProxy for translated fields
name = models.CharField(_('Product name'), max_length=100)
description = models.TextField(_('Product description'))
price = models.DecimalField(_('Price'), max_digits=10, decimal_places=2)

class Meta:
verbose_name = _('product')
verbose_name_plural = _('products')

# views.py
from django.views.generic import DetailView
from .models import Product

class ProductDetailView(DetailView):
model = Product
template_name = 'products/detail.html'
context_object_name = 'product'
html
<!-- templates/products/detail.html -->
{% load i18n %}

<div class="product">
<h1>{{ product.name }}</h1>

<div class="price">
{% blocktrans with price=product.price %}
Price: ${{ price }}
{% endblocktrans %}
</div>

<div class="description">
<h3>{% trans "Product Description" %}</h3>
<p>{{ product.description }}</p>
</div>

<button class="add-to-cart">
{% trans "Add to Cart" %}
</button>
</div>

{% include "includes/language_selector.html" %}

Handling Language-Specific Redirects

Sometimes you'll need to redirect users to language-specific URLs. Here's how you can do it:

python
from django.urls import reverse
from django.utils import translation

def homepage_view(request):
# Process homepage logic...

# Redirect to language-specific page
current_language = translation.get_language()
news_url = reverse('news:index')

# If you're using i18n_patterns, the URL will already include the language code
return redirect(news_url)

Common Issues and Solutions

Issue 1: Translations Not Showing Up

If your translations aren't appearing, check:

  1. That USE_I18N = True in settings
  2. That the LocaleMiddleware is correctly placed in the middleware list
  3. That you've compiled your translation files with django-admin compilemessages
  4. That the active language is what you expect (add {{ LANGUAGE_CODE }} to a template to check)

Issue 2: Performance Concerns

Translation lookups can impact performance. For better performance:

python
# settings.py
TEMPLATE_CONTEXT_PROCESSORS = [
# ...other processors...
'django.template.context_processors.i18n',
]

# For heavy text, consider caching
from django.core.cache import cache
from django.utils.translation import gettext as _

def get_expensive_translation(key):
cache_key = f"translation_{key}_{translation.get_language()}"
result = cache.get(cache_key)
if result is None:
result = _("Very long and expensive translation")
cache.set(cache_key, result, 3600) # Cache for 1 hour
return result

Summary

Django's Locale Middleware is a powerful tool that enables your application to adapt to different languages based on user preferences. In this tutorial, we've learned:

  • How to enable and configure LocaleMiddleware
  • How Django determines which language to use for each request
  • How to create language-specific URL patterns
  • How to implement language switching functionality
  • How to mark content for translation in both Python code and templates
  • Real-world application through a multilingual e-commerce example

By properly implementing internationalization with Django's Locale Middleware, you make your application accessible to a wider audience and improve user experience for international visitors.

Further Resources

Exercises

  1. Set up a basic Django project with LocaleMiddleware and add support for at least two languages.
  2. Create a language selection dropdown that allows users to switch between languages.
  3. Add translations for all static text in your templates using the trans template tag.
  4. Implement URL patterns with language prefixes using i18n_patterns.
  5. Create a middleware that logs which language selection method was used for each request (URL, session, cookie, browser header, or default).


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