6 months, 1 week

Internationalization and Localization with Django

Django offers full internationalization and localization support. It allows you to translate your application into multiple languages and it handles locale-specific formatting for dates, times, numbers, and timezones. Internationalization (frequently abbreviated to i18n) is the process of adapting software for the potential use of different languages and locales so that it isn't hardwired to a specific language or locale. Localization (abbreviated to l10n) is the process of actually translating the software and adapting it to a particular locale. Django itself is translated into more than 50 languages using its internationalization framework.

The internationalization framework allows you to easily mark strings for translation, both in Python code and in your templates. It relies on the GNU gettext toolset to generate and manage message files. A message file is a plain text file that represents a language. It contains a part, or all, of the translation strings found in your application and their respective translations for a single language. Message files have the .po extension. Once the translation is done, message files are compiled to offer rapid access to translated strings. The compiled translation files have the .mo extension.

Django provides several settings for internationalization. The following settings  are the most relevant ones:

USE_I18N: A Boolean that specifies whether Django's translation system is enabled. This is True by default.

• USE_L10N: A Boolean indicating whether localized formatting is enabled.  When active, localized formats are used to represent dates and numbers. 
This is False by default.

• USE_TZ: A Boolean that specifies whether datetimes are timezone-aware. When you create a project with the startproject command, this is set 
to True.

• LANGUAGE_CODE: The default language code for the project. This is in standard language ID format, for example, 'en-us' for American English, 
or 'en-gb' for British English. This setting requires USE_I18N to be set to True in order to take effect. You can find a list of valid language IDs 
at http://www.i18nguy.com/unicode/language-identifiers.html.

• LANGUAGES: A tuple that contains available languages for the project. They come in two tuples of a language code and language name. You can see the 
list of available languages at django.conf.global_settings. When you choose which languages your site will be available in, you set LANGUAGES
to a subset of that list.

• LOCALE_PATHS: A list of directories where Django looks for message files containing translations for the project.

• TIME_ZONE: A string that represents the timezone for the project. This is set to 'UTC' when you create a new project using the startproject command. 
You can set it to any other timezone, such as 'Europe/Berlin'.


These are some of the internationalization and localization settings available. You can find the full list at Globalization (i18n/l10n).

Internationalization management commands
Django includes the following management commands to manage translations:
• makemessages: This runs over the source tree to find all strings marked for translation and creates or updates the .po message files in the locale
directory. A single .po file is created for each language.                     
• compilemessages: This compiles the existing .po message files to .mo files that are used to retrieve translations.
You will need the gettext toolkit to be able to create, update, and compile message files. Most Linux distributions include the gettext toolkit. If you are using                                                      
macOS, probably the simplest way to install it is via Homebrew, at https://brew.sh/, with the command brew install gettext. You might also need to 
force link it with the command brew link --force gettext. For Windows, follow the steps at https://docs.djangoproject.com/en/3.0/topics/i18n/

How to add translations to a Django project

1. Mark strings for translation in your Python code and your templates.

2. Run the makemessages command to create or update message files that include all translation strings from your code.

3. Translate the strings contained in the message files and compile them using the compilemessages management command.

Django comes with a middleware that determines the current language based on the request data. This is the LocaleMiddleware middleware that resides in django. middleware.locale.LocaleMiddleware performs the following tasks:

1. If you are using i18n_patterns, that is, you are using translated URL patterns, it looks for a language prefix in the requested URL to determine the current language.

2. If no language prefix is found, it looks for an existing LANGUAGE_SESSION_ KEY in the current user's session.

3. If the language is not set in the session, it looks for an existing cookie with the current language. A custom name for this cookie can be provided in the LANGUAGE_COOKIE_NAME setting. By default, the name for this cookie is django_language.

4. If no cookie is found, it looks for the Accept-Language HTTP header of the request.

5. If the Accept-Language header does not specify a language, Django uses the language defined in the LANGUAGE_CODE setting.

Edit the settings.py file of your project and add the following LANGUAGES setting to it. Place it next to the LANGUAGE_ CODE setting:

from django.utils.translation import gettext_lazy as _

LANGUAGES = (('de', _('German')),      
               ('en', _('English')),)    

You use the gettext_lazy() function instead of gettext() to avoid a circular import, thus translating the languages' names when they are accessed.

Add 'django.middleware.locale.LocaleMiddleware' to the MIDDLEWARE setting. Make sure that this middleware comes after SessionMiddleware because LocaleMiddleware needs to use session data. It also has to be placed before CommonMiddleware because the latter needs an active language to resolve the requested URL. The MIDDLEWARE setting should now look as follows:

MIDDLEWARE_CLASSES = ('django.contrib.sessions.middleware.SessionMiddleware', 


                                                  'django.middleware.common.CommonMiddleware',    )  

The order of middleware classes is very important because each middleware can depend on data set by other middleware executed previously. Middleware is applied for requests in order of appearance in MIDDLEWARE, and in reverse order for responses.

The locale directory is the place where message files for your application will reside. Edit the settings.py file again and add the following setting to it: LOCALE_PATHS = ( os.path.join(BASE_DIR, 'locale/'), )

The LOCALE_PATHS setting specifies the directories where Django has to look for translation files. Locale paths that appear first have the highest precedence. When you use the makemessages command from your project directory, message files will be generated in the locale/ path you created. However, for applications that contain a locale/ directory, message files will be generated in that directory.

To translate literals in your Python code, you can mark strings for translation using the gettext() function included in django.utils.translation. This function translates the message and returns a string. The convention is to import this function as a shorter alias named _ (underscore character). You can find all the documentation about translations at translation.

Standard translations The following code shows how to mark a string for translation:

from django.utils.translation import gettext as _         

output = _('Text to be translated.')                              

Django includes lazy versions for all of its translation functions, which have the suffix _lazy(). When using the lazy functions, strings are translated when the value is accessed, rather than when the function is called. Using gettext_lazy() instead of gettext() means that strings are translated when the value is accessed. Django offers a lazy version for all translation functions.

Open the shell and run the following command from your project directory: 

django-admin makemessages --all                                        

You should see the following output:

 processing locale de                      processing locale en             

Each translation string is preceded by a comment showing details about the file and the line where it was found. Each translation includes two strings:

• msgid: The translation string as it appears in the source code.

• msgstr: The language translation, which is empty by default. This is where you have to enter the actual translation for the given string.

Save the modified message file, open the shell, and run the following command:

django-admin compilemessages

If everything goes well, you should see an output like the following: processing file

django.po in yourproject/locale/en/LC_MESSAGES

processing file django.po in yourproject/locale/de/LC_MESSAGES

You have translated the language names themselves. Now, let's translate the model field names that are displayed in the site. Edit the models.py file of the yourapp  and add names marked for translation for the AppModel model fields as follows:

from django.utils.translation import gettext_lazy as _                          

class AppModel(models.Model):                                                          

username = models.CharField(_('username'), max_length=50)         

Translating templates

Django offers the {% trans %} and {% blocktrans %} template tags to translate strings in templates. In order to use the translation template tags, you have to add {% load i18n %} at the top of your template to load them. 

The {% trans %} template tag allows you to mark a literal for translation. Internally, Django executes gettext() on the given text. This is how to mark a string for translation in a template: {% trans "Text to be translated" %}.

The {% blocktrans %} template tag allows you to mark content that includes literals and variable content using placeholders.

{% blocktrans %}Hello {{ username }}!{% endblocktrans %}

You can use with to include template expressions, such as accessing object attributes or applying template filters to variables.

{% blocktrans with name=user.name|capfirst %} Hello {{ username }}! {% endblocktrans %}



Rosetta is a third-party application that allows you to edit translations using the same interface as the Django administration site. Rosetta makes it easy to edit .po files and it updates compiled translation files.

Install Rosetta via pip using this command: pip install django-rosetta

INSTALLED_APPS = [ # ... 'rosetta', ]                                           

Edit the main urls.py file of your project and add the following URL pattern to it:

urlpatterns = [ # ... path('rosetta/', include('rosetta.urls')), ]            


Fuzzy translations                                             

If the fuzzy flag is active for a translation, it will not be included in the compiled message files. This flag marks translation strings that need to be reviewed by a translator.

Django offers internationalization capabilities for URLs. It includes two main features for internationalized URLs:

• Language prefix in URL patterns: Adding a language prefix to URLs to serve each language version under a different base URL

• Translated URL patterns: Translating URL patterns so that every URL is different for each language A reason for translating URLs is to optimize your site for search engines.

Django allows you to add a language prefix to your URL patterns. To use languages in URL patterns, you have to use the LocaleMiddleware provided by Django. The framework will use it to identify the current language from the requested URL.

from django.conf.urls.i18n import i18n_patterns                         

urlpatterns = i18n_patterns( path('admin/', admin.site.urls),       

path('rosetta/', include('rosetta.urls')), )                                       


You can combine non-translatable standard URL patterns and patterns under i18n_patterns so that some patterns include a language prefix and others don't. However, it's better to use translated URLs only to avoid the possibility that a carelessly translated URL matches a non-translated URL pattern.

Django supports translated strings in URL patterns. You can use a different translation for each language for a single URL pattern. You can mark URL patterns for translation in the same way as you would with literals, using the gettext_ lazy() function.

from django.utils.translation import gettext_lazy as _     

urlpatterns = i18n_patterns(                                            

path(_('admin/'), admin.site.urls),                                     

path('rosetta/', include('rosetta.urls')), )                           

Translating models with django-parler

There are several third-party applications that allow you to translate model fields. Each of them takes a different approach to storing and accessing translations. One of these applications is django-parler. This module offers a very effective way to translate models and it integrates smoothly with Django's administration site.

Install django-parler via pip using the following command: pip install django-parler

INSTALLED_APPS = [ # ... 'parler', ]                         

add the following code to your settings:

PARLER_LANGUAGES = { None: ( {'code': 'en'}, {'code': 'de'}, ),    

'default': { 'fallback': 'en', 'hide_untranslated': False, } }                    

You can find more information.