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 (if USE_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.