Languages

Django Languages

The Django translation functionality is outlined here in the documentation and requires GNU gettext tools to flag the text that we wish to translate.

GNU Gettext

Download the precompiled binary installer to start. Ensure you download the correct version such as the 64 bit static and it should be installed to C:\Program Files\gettext-iconv.

In Your Views

Translation can be done on a view to view basis, however for complete usability, I ended up moving all of them to the core app context processor so that they are available on all pages.

from django.shortcuts import render
from django.conf import settings
# The general shorthand syntax is to us gettext as _
from django.utils.translation import gettext as _
from django.utils.translation import get_language, activate, gettext

def index(request):
    '''Return the homepage'''
    # Translations for the page using the translate function defined below
    trans = translate(language=get_language() or settings.LANGUAGE_CODE)
    context = {
        'MEDIA_URL': settings.MEDIA_URL,
        'DEBUG': settings.DEBUG,
	    # list the variables for the page defined in translation function below
        'hotel_name': trans['hotel_name'],
    }
    return render(
        request,
        'homepage/index.html',
        context,
    )

# Define a translate function that was called in the above request
def translate(language):
    '''Function to translate text'''
    # get the current language
    cur_language = get_language()
    translations = {}  # Ensure it is defined as an empty dictionary even if activation fails
    # Try to activate the language you pass as a parameter
    try:
        activate(language)
        # Select and define translations
        translations = {
	        #use _ to identify the strings, same as gettext() because we imported it as _
            'hotel_name': _('Hotel Name')
        }

    finally:
        # If you cannot activate, activate the current language
        activate(cur_language)
    # Return translations
    return translations

In the Template

At the top of the page have:

{% load i18n %} 

Then you can call the templating language translate to automatically translate something (not recommended).

<h1>{% translate "Hotel Name" %}</h1> 

Or just pass the variable you have defined.

<h1>{{ hotel_name }}</h1>

Update settings.py

Add the relevant imports to the top of the file.

# Import gettext_lazy at the top using the shorthand of _
from django.utils.translation import gettext_lazy as _

In the Internationalization section, add a LANGUAGES variable which will be a list of tuples. The tuples will be the language code as a string and the gettext_lazy of the language name. Then update your LANGUAGE_CODE variable to show the default language that you want for your website and add a LOCALE_PATHS to have the pathway of the stored location. We have not created this folder yet but the accepted name is 'locale'.

LANGUAGES = [
    ('en', _('English')),
    ('ka', _('Georgian')),
]

LANGUAGE_CODE = 'en'  

LOCALE_PATHS = [
    BASE_DIR / 'locale',  # Path where translation files will be stored
]

# Make the following True:
USE_I18N = True
USE_L10N = True
USE_TZ = True

Add locale middleware to middleware. It needs to go after sessions (.SessionMiddleware) because it will run in a session but above common (.CommonMiddleware) because common deals with the URL and we will set up the URLs depending on the language.

MIDDLEWARE = [
	…
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',  # Languages
    'django.middleware.common.CommonMiddleware',
	…
]

Make a Locale Folder

In the root directory create a locale folder. Inside it, create a folder for each language named after their language code e.g. locale/en.

Create Translation Files

With having trans variables in the templates you can run the translation tool to create translation files.

python manage.py makemessages --all -i requirements.txt 
  • This will ignore the requirements.txt file, which is not utf-8 and would cause errors
  • It creates .po files in the folder in locale for each language e.g. in locale/en
  • It works by looking for the translations from views

The .po files will be a list of the translations. They will have:

  • A comment of the location where the gettext translation was specified
  • An msgid which shows what the gettext function was called on
  • An msgstr which shows what string will be shown for that language
#: .\homepage\views.py:12
msgid "Hotel Name"
msgstr ""

You can now go through these files and update the msgstr strings to show what you want displayed. The benefit of doing it this way instead of automatic translation is that you can have paragraphs translated so that their message is still clear and the prose flows well rather than a disjointed word by word translation.

With all your translations written, you can then compile them.

python manage.py compilemessages

URLs

In your project level urls.py file you can create a function to redirect the language to the default language if none is selected.

def redirect_to_default_language(request):
    """Force redirect to default language unless another language is explicitly set."""
    language = get_language_from_request(request) or 'en'
    
    # Override browser preference and force default language if no language cookie exists
    if 'django_language' not in request.COOKIES:
        language = 'en'  # Force default language
    
    response = redirect(f'/{language}/')
    response.set_cookie('django_language', language)  # Store language preference
    return response

Then in your urlpatterns you can add in this redirect to the homepage so that the default language is selected when a user first comes to your website.

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', redirect_to_default_language),  # Redirect `/` to preferred or default language
]

You can then add your app urls to the urlpatterns by wrapping them in i18n_patterns() to automatically insert a language code at the start of the url.

urlpatterns += i18n_patterns(
    path('', include('homepage.urls')),
)

Language Dropdown

You will need a way for the user to decide which language they want to use. Here is a simple language dropdown menu.

<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
    {% get_current_language  as LANGUAGE_CODE %}
    {% get_available_languages  as LANGUAGES %}
    {% get_language_info_list for LANGUAGES as languages %}
    {% for lang in languages %}
        <li>
            <a class="dropdown-item" href="/{{ lang.code }}/">
                {{ lang.name_local }}
            </a>
        </li>
    {% endfor %}
</ul>

Adding a New Translation

Adding a new translation is simple.

  • In the view or context processor add a new translation
    • 'welcome_message': _('Welcome to the website!')
  • Add it to the .po files
    • python manage.py makemessages --all -i requirements.txt
  • Go to .po files and find "Welcome to the website!" and add translations
  • Compile the translations
    • python manage.py compilemessages
  • Add to template
    • {{ welcome_message }}

To change an existing translation, simply find it in your .po file, make the change and run python manage.py compilemessages