Share
Explore

icon picker
Django Translation/Localization RFC

Standardizing Translation and Localization for Dynamic and Scalable Web Applications with Django

Document sections

The following is a summary of the key points in the document sections.

🎬 Introduction

⚠️ Problem

✔️ Solution

🔧 Setup

🖊️ Implementation

🔎 Testing

🏁 Conclusion



🎬 Introduction

As we ‘Huspy’ grows and expands to new markets, the need for supporting multiple languages arises.
In order to effectively reach and engage our target audiences, it is important to support multiple languages within our Django application. For instance, in Dubai the primary language is English, in Abu Dhabi preferably Arabic, and in Madrid it is Spanish. And there will be many more countries/languages to support soon hopefully. Therefore, to ensure that our application is accessible and usable by these audiences, we must implement Django's translation framework.


⚠️ Problem

Having a Django application that is only in English can limit its reach and accessibility to a global audience. For example, our users in Spain, and local users in Abu-dhabi. The following are some of the potential problems that may arise when limiting the application to only one language:
Inadequate user experience: Non-English speaking users may have difficulty using the application, leading to frustration and potential loss of users.
Limited market reach: By limiting the application to only English-speaking users, the potential market for the application is greatly reduced.
Cultural barriers: Using only English may cause cultural barriers for users who are more comfortable with their native language.
Legal implications: In some countries, it may be a legal requirement to provide applications in the local language. (Like in Spain for instance)
By not supporting multiple languages, the application may miss out on opportunities for growth, both in terms of user base and market reach. Implementing a translation framework can help address these issues and ensure that the application is accessible and usable by a wider audience.


✔️ Solution

Simply, adding Django Translation or in other words Internationalization or Localization to our Monolith repo ;).
megaphone
WHAT IS Django translation?
In order to make a Django project support multiple languages, you need to add translation hooks, known as "translation strings", to your Python code and templates. These hooks inform Django which text should be translated for the end-user's preferred language, if available. It is your responsibility to mark these translatable strings, as the system can only translate what it is aware of.
Django then provides tools to gather these translation strings into a message file, which serves as a platform for translators to provide the equivalent text in the target language. After the message file is completed, it must be compiled using the GNU gettext toolset.
Once the translation process is complete, Django will handle the dynamic translation of the web application in each available language, based on the user's language preferences.


🔧 Setup

1- The first step is to make sure that we enabled internationalization in settings.py. To do this there are some keys we need to enter:
a. Django's LocaleMiddleware
MIDDLEWARE = [
.......
"django.middleware.locale.LocaleMiddleware",
.......
]
Django's LocaleMiddleware is a middleware component that is used to handle language-specific user preferences. It determines the user's preferred language and sets the locale for the current request accordingly. This locale is then used to translate the application into the user's preferred language, if a translation is available.
The LocaleMiddleware is added to the MIDDLEWARE setting in a Django project to enable localization. It works by looking at the Accept-Language header in the request, which specifies the preferred language(s) of the user. The middleware then sets the django.utils.translation.get_language() to the preferred language, and this language is used by the translation framework to translate the application accordingly.

b. Internationalization flags
USE_I18N = True
USE_L10N = True
USE_TZ = True
USE_I18N, USE_L10N, and USE_TZ are settings in Django that control various aspects of internationalization and localization in a Django application.
USE_I18N: If True, the Django application will use internationalization (i18n) framework to handle translation of text and other content.
USE_L10N: If True, the Django application will use localization (l10n) framework to handle formatting of dates, times, numbers, etc. based on the user's preferred locale.
USE_TZ: If True, the Django application will use time zone support to handle time-sensitive data such as dates and times in a time zone-aware manner.
By setting these settings to True, a Django application can provide a more localized and user-friendly experience by supporting multiple languages and locales.

c. Languages and defaults
LANGUAGE_CODE = 'en'
TIME_ZONE = 'Asia/Dubai'

LANGUAGES = (
("ar", "Arabic"),
("en", "English"),
("es", "Spanish"),
)
We need to specify the supported languages. Currently, we only support three languages: "ar", "en", and "es". We can accomplish this by adding the LANGUAGES setting to our settings.py file and listing our desired supported languages.
We must also set the LANGUAGE_CODE to define the default language for our application, which in our case is "en".
Lastly, we can set the default time zone for our app by adding the TIME_ZONE field in the settings.py file. In this scenario, the default time zone will be "Asia/Dubai" as it represents the primary location of Huspy.

2- The second step in the setup process is to modify the urls to accept and understand the header Accept-Language. This should be done in the base urls file.
from django.conf.urls.i18n import i18n_patterns

.........
url_patterns = [
........................
........................
]

urlpatterns += i18n_patterns(path('backend/api/v2/', include('apps.api.v2.urls')))
This defines the url which we expect to accept the header Accept-Language and translate the content of the request and response accordingly.
i18n_patterns is a function in Django's i18n module that allows you to specify which URLs in your Django application should be translated and localized.

3- The final step in the setup process is to define the path of the translations file.
a. LOCALE_PATHS
LOCALE_PATHS = (str(ROOT_DIR.path("locale")),)
LOCALE_PATHSis a setting in Django that defines the location of the translation files for an application.
When using internationalization and localization in Django, you need to store the translated strings in specific files for each language. These files are typically located in a locale directory within your application and have the .po extension.

b. Defining file structure for the translation files
> apps /

> build /

> HuspyBackendService /
|..... settings /
|.... base.py
|.... production.py
|.... local.py
|.... .......
|.... .......
|..... locale /
|.... ar /
|... LC_MESSAGES
|.... django.po
|.... en /
|... LC_MESSAGES
|.... django.po
|.... es /
|... LC_MESSAGES
|.... django.po
...............
...............
...............
The locale directory should be located within the HuspyBackendService application and contain a separate folder for each language specified in the LANGUAGES setting. Inside each language folder, there will be django.po files where you can place your translations for each word used in the application. Django will process these translations and compile them, resulting in a fully translated app.
In the implementation section we will see how to write translations inside django.po files and compile them accordingly.

You can check the setup process and implementation in the following github PR: ​


🖊️ Implementation

And now that we are done with the setup. Let’s see how can we
introduce translations in django.po
compile translations into django.mo
use those translations to translate some keys and words in the application

Introduce translations in django.po
Assume that we have a simple Hello world example that we need to return it to the user depends on his/her preferred language: We need to introduce the word “hello world” in all three languages that we have each in the respective django.po file as follows:
huspy-backend-service/HuspyBackendService/locale/ar/LC_MESSAGES/django.po
msgid "hello_world"
msgstr "مرحبآ بالعالم"
Here inside the arabic django.po file we will introduce the msgid hello_world and the Arabic translation for it in the msgstr value. And we will do the same for the Spanish and English files as follow.
huspy-backend-service/HuspyBackendService/locale/en/LC_MESSAGES/django.po
msgid "hello_world"
msgstr "Hello World"
huspy-backend-service/HuspyBackendService/locale/es/LC_MESSAGES/django.po
msgid "hello_world"
msgstr "Hola Mundo"

Compile translations into django.mo
After adding all your keys with specific translation in all languages respective folders we have to compile those messages before running our server. Compiling translations are done by the following command
python3 manage.py compilemessages
After compiling messages successfully you should expect a new 3 files created under each language folder names django.mo And you will observe a new folder structure for the locale folder as follow: ​> apps /
> HuspyBackendService /
|..... settings /
|..... locale /
|.... ar /
|... LC_MESSAGES
|.... django.mo
|.... django.po
|.... en /
|... LC_MESSAGES
|.... django.mo
|.... django.po
|.... es /
|... LC_MESSAGES
|.... django.mo
|.... django.po
...............
django.mo is a compiled binary file format used to store translations in Django. The "compilemessages" command is used to compile translation files, which are typically stored in *.po format, into this binary format. The resulting django.mo file can then be used by Django to serve translations to your users based on their language preference.

Use those translations to translate some keys and words in the application
You can add the following piece of code snippet to translate your desired word depending on the user’s favorite language
from django.utils.translation import gettext as _

def test_hello_world_translation(self, request, *args, **kwargs):
message_id = "hello_world"
message_str = _(message_id)
return Response(message_str)
from django.utils.translation import gettext as _ is an import statement in Django to access the gettext function for translating text into different languages. The alias _ is a common convention in Django to provide a shortcut for the gettext function, allowing you to write code such as _(text_to_translate) instead of gettext(text_to_translate).
As you see in our example we used hello_world id that we defined in the django.po files and the _ alias to tell django to lookup this id in the translation files depends on the users preferred language defined by Accept-Language header.


You can check the implementation process in the following github PRs: ​


🔎 Testing

Continuing our example of hello world program. I will show you how to request and receive a response with the desired language.
Screen Shot 2023-02-05 at 5.11.25 PM.png

This is an example of the request that should be sent using postman. It is a simple GET request to get the hello world word with a specific language. As you can see we added Accept-Language header to the request. And django expects one of the supported languages that we provided earlier in the settings.py of our project. In our case we are supporting values “en”, “es”, and “ar”. The following pictures are the response of the api of the three supported languages:
Screen Shot 2023-02-05 at 5.14.32 PM.png

Screen Shot 2023-02-05 at 5.14.59 PM.png

Screen Shot 2023-02-05 at 5.15.21 PM.png


🏁 Conclusion

To sum-up, Django translation/localization is a powerful tool that enables our app to scale more and expand to different markets easily and provide more accessibility.
Django's internationalization (i18n) framework provides a powerful and flexible solution for translating your application into multiple languages. The use of the gettext function, combined with translation files in .po format, makes it easy to manage translations and ensure that your application can be adapted to different languages and regions. The compilemessages command provides a convenient way to compile your translation files into binary .mo files, which can be used by Django to serve the correct translations to your users. By utilizing the tools and techniques described in this document, you can ensure that your Django application can be enjoyed by a global audience.

Lastly, going forward, all contributors to the monolith repository can effortlessly add their translations to the .po files and then compile them using the compilemessages command. They can then use either gettext or its shortcut alias _ to translate any text within the project. For more information, refer to the implementation section.

Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.