When building a multilingual Django application, choosing the right language for your users can make or break their experience. Instead of asking users to select a language every time, we can auto-detect it using domain names or subdomain prefixes.
In this article, you'll learn how to:
- Configure your Django app to support multiple languages.
- Set language based on domain (
example.pl
,example.com
) or subdomain (pl.example.com
,en.example.com
). - Keep everything clean and declarative — no messy
if/else
logic.
This is a beginner-friendly guide. Let’s dive in.
📁 1. Project Setup and Language Configuration
Start by enabling multiple languages in your settings.py
:
LANGUAGE_CODE = "en"
LANGUAGES = [
("en", "English"),
("pl", "Polish"),
]
You also need to add a fallback configuration:
USE_I18N = True
USE_L10N = True
USE_TZ = True
🌐 2. Define Your Language Rules in settings.py
We'll store language-to-domain mappings in a declarative way:
LANGUAGE_BY_DOMAIN = {
"whathappensnext.online": "en",
"cobylodalej.online": "pl",
}
LANGUAGE_SUBDOMAIN_PREFIXES = {
"en": "en",
"pl": "pl",
}
USE_SUBDOMAIN_LANGUAGE = True # Enable subdomain-based resolution
This way, you don’t need any if
statements — all the logic is in settings.
⚖️ 3. Create the Language Detection Middleware
Now, let's build the middleware to read the host and determine the language:
from django.utils import translation
from django.conf import settings
def get_language_from_domain(host: str, fallback: str) -> str:
domain = ".".join(host.lower().split(".")[-2:])
return settings.LANGUAGE_BY_DOMAIN.get(domain, fallback)
def get_language_from_subdomain(host: str, fallback: str) -> str:
parts = host.lower().split(".")
if len(parts) < 3:
return fallback
return settings.LANGUAGE_SUBDOMAIN_PREFIXES.get(parts[0], fallback)
LANGUAGE_RESOLVERS = (
get_language_from_domain,
get_language_from_subdomain,
)
class SmartLanguageMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.fallback_language = getattr(settings, "LANGUAGE_CODE", "en")
def __call__(self, request):
host = request.get_host().split(":")[0]
use_subdomain = getattr(settings, "USE_SUBDOMAIN_LANGUAGE", False)
resolver = LANGUAGE_RESOLVERS[use_subdomain]
lang = resolver(host, self.fallback_language)
translation.activate(lang)
request.LANGUAGE_CODE = lang
response = self.get_response(request)
translation.deactivate()
return response
➕ 4. Register the Middleware
In your settings.py
, add your new middleware before Django’s default locale middleware:
MIDDLEWARE = [
"your_project.middleware.SmartLanguageMiddleware",
"django.middleware.locale.LocaleMiddleware",
...
]
🪡 5. Example Use Cases
With this setup, users visiting:
-
https://przykladowyserwis.com
will see Polish. -
https://someservice.com
will see English. -
https://pl.someservice.com
will see Polish (ifUSE_SUBDOMAIN_LANGUAGE = True
). -
https://en.someservice.com
will see English.
You can always extend or modify the resolver logic to suit your needs.
🚀 6. Summary
By using a smart, declarative middleware, you:
- Detect languages based on host or subdomain automatically.
- Avoid hard-coded logic.
- Keep things clean and scalable.
This technique is great for multilingual SaaS apps or platforms where each region or market has its domain.