Internationalize with subdomains | Django LiveView

Here you will learn how to create a multilingual website using Django LiveView.

We using subdomains to define the language (en.example.com, es.example.com...), instead of using prefixes in addresses (example.com/en/blog/, example.com/es/blog/). They simplify SEO, maintain consistency in the Sitemap and are easy to test.

We will use the following structure:

  • example.com and en.example.com for English.

  • es.example.com for Spanish.

1. Configure the subdomains

In your settings.py file, add all domains that will be used.

ALLOWED_HOSTS = ["example.com", "en.example.com", "es.example.com"]

2. Configure the languages

And add or modify the following settings in the same file (settings.py).

# Languages

# Enable internationalization
USE_I18N = True

# Default language
LANGUAGE_CODE = "en"

# Available languages
LANGUAGES = [
    ("en", _("English")),
    ("es", _("Spanish")),
]

# Locale paths
LOCALE_PATHS = (BASE_DIR / "locale/",)

3. Redirection with Middleware

Create a middleware that redirects the user to the correct subdomain and sets the language. If the user enters en.example.com or example.com, English language will be activated. If the user enters es.example.com, Spanish language will be activated. And if the user enters en.example.com, it will be redirected to example.com.

Create a file called middlewares.py in your project folder and add the following code.

from django.utils import translation
from django.conf import settings
from django.utils.translation import get_language
from django.http import HttpResponseRedirect

def language_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        # Set the language based on the domain
        # Example:
        # "example.com" and "en.example.com" -> en
        # "es.example.com" -> es

        # Get the domain from the request
        domain = request.META["HTTP_HOST"]
        # Get the subdomain
        domain_list = domain.split(".")
        subdomain = domain_list[0] if len(domain_list) == 3 else None
        # Set the language
        if get_language() != subdomain:
            translation.activate(subdomain)

        # Redirect default language to main domain
        # Example: "en.example.com" -> "example.com"
        if subdomain == settings.LANGUAGE_CODE:
            return HttpResponseRedirect("http://example.com")

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware

Now, add the middleware to the MIDDLEWARE list in settings.py.

MIDDLEWARE = [
    ...
    "middlewares.language_middleware",
]

4. Set multilingual texts

In any of your HTML templates, you can use translation tags to display multilingual texts.

{% load i18n %}

<h1>{% trans "Hello" %}</h1>

<p>{% blocktrans %}This is a multilingual website.{% endblocktrans %}</p>

For titles and descriptions, you can use the meta dictionary in the action with _("text") to translate the texts.

from liveview.context_processors import get_global_context
from django.conf import settings
from liveview.utils import (
    get_html,
    update_active_nav,
    enable_lang,
    loading,
)
from django.utils.translation import gettext as _
from django.templatetags.static import static
from django.urls import reverse

...
context.update(
    {
        "url": settings.DOMAIN_URL + reverse("home"),
        "title": _("Home") + " | Home",
        "meta": {
            "description": _("Home page of the website"),
        },
    }
)
...

For the url of the page, you can edit the urls.py file to include the language.

from django.urls import path
from django.utils.translation import gettext as _
from .views import home

urlpatterns = [
    path(_("home") + "/", home, name="home"),
    path(_("about") + "/", about, name="about"),
]

5. Make messages

Create the locale folder in the root of your project and run the following commands.

./manage.py makemessages -l en
./manage.py makemessages -l es

The files locale/en/LC_MESSAGES/django.po and locale/es/LC_MESSAGES/django.po will be created. You can edit them with a text editor or use a translation tool like Poedit.

6. Compile messages

After translating the texts, compile the messages.

./manage.py compilemessages

Your multilingual website is ready. You can test it by entering example.com, en.example.com and es.example.com.

7. Selector of languages

You can create a selector of languages in the header of your website.

{% load i18n %}
{% get_current_language as CURRENT_LANGUAGE %}
{% get_available_languages as AVAILABLE_LANGUAGES %}
<ul>
    {# Display the current language #}
    <li>
            <a href="#" disabled>{{ CURRENT_LANGUAGE }}</a>
    </li>
    {# Display the other languages #}
    {% for language in AVAILABLE_LANGUAGES %}
    {% if language.0 != CURRENT_LANGUAGE %}
    <li>
        <a href="http{% if request.is_secure %}s{% endif %}://{{ language.0 }}.{{ DOMAIN }}">
            {{ language.0 }}
        </a>
    </li>
    {% endif %}
    {% endfor %}
</ul>

The above code will create a list of languages with the current language disabled.

Or also simple links with the subdomain.

<a href="http://en.example.com">
    English
</a>

<a href="http://es.example.com">
    Español
</a>
{% endfor %}