Django uses the LocaleMiddleware to discover language preference for individual users. The LocaleMiddleware enables language selection through the request context.
- If we want to let each user specify their preferred language we need to use
LocaleMiddleware. LocaleMiddleware determines a user's language
preferences through the request context. It is activated by adding it to
MIDDLEWARE in your settings (tola/settings/base.py) as one of the topmost
classes, before CommonMiddleware, but after SessionMiddleware.
MIDDLEWARE_CLASSES = ( ... 'django.middleware.locale.LocaleMiddleware', ... )
After first looking for a language prefix in the requested url, LocaleMiddleware will look for the LANGUAGE_SESSION_KEY in current user's session to determine language. (Failing that, it will look for a cookie, then at the Accept-Language HTTP header and finally in the global LANGUAGE_CODE setting. For further information about Django's algorithm to determine language preference see https://docs.djangoproject.com/en/1.11/topics/i18n/translation/)
- In order for a user to select a preferred language with a button, the Django
documentation recommends the LANGUAGE_SESSION_KEY option. In order for this
to be successful, the LANGUAGE_SESSION_KEY has to be set in
django.utils.translation. Django comes with a view,
django.views.i18n.set_language()
, that sets a user’s language preference and redirects to a given URL or, by default, back to the previous page. Activate this view by adding the following line to your URLconf:
url(r'^i18n/', include('django.conf.urls.i18n'))
(Source code: https://docs.djangoproject.com/en/1.11/_modules/django/conf/urls/i18n/, https://docs.djangoproject.com/en/1.11/_modules/django/views/i18n/)
- In order to enable user to choose a language, include an html form in base.html. The Django documentation provides a sample html template code: https://docs.djangoproject.com/en/1.11/topics/i18n/translation/
In order for strings to be translated by Django, you have to add hooks, called translation strings to your templates and Python code. Django then extracts the translation strings into a message file where the translators will provide the equivalent strings in the target languages. Django looks for a locale directory listed in the LOCALE_PATH to create, compile and load message files with translation strings.
-
Create locale directory in tola project directory to save translation files. In this directory Django will create
locale_code_for_each_languages/LC_MESSAGES
directories for each language specified and within each a django.po file with the translation strings. -
Specify the LOCALE_PATHS in tola/settings/base.py like so:
LOCALE_PATHS = [ join(DJANGO_ROOT, 'locale'), ]
This is where Django will create and look for translation files. -
In tola/settings/base.py import ugettext_lazy function
from django.utils.translation import ugettext_lazy as _
The u prefix represents unicode strings in Python 2. In Python 3 gettext() and ugettext() can be used interchangeably. The ugettext_lazy function is used here to mark the language names for translation. Different from the ugettext function which translate the string immediately, ugetttext_lazy stores a lazy reference to the string and translates the string when it is used in context, such as rendering a template. -
Add list of languages available for selection.
LANGUAGES = [ ('fr', _('French')), ('es', _('Spanish')), ('ar', _('Arabic')), ('en', _('English')), ]
-
Make sure USE_I18N is set to True.
Django uses two template tags for string translations in templates. The {% trans %} translates either a constant string or a variable content. The {% blocktrans %} {% endblocktrans %} tags enclose complex sentences consisting of variables and literals. In order to access these tags {% load i18n %} must be places toward the top of the template.
-
In views import ugettext() as
_
, since they are callables which return a response every time a request is issued. (No need to store translation as a reference like it is done on models, forms and apps. Here the code is only executed once at startup.) -
In models, forms and apps import ugettext_lazy() as
_
, because the code is exexuted at startup and the lazy version holds the reference to the translation string in case the user changes the languages.
-
Before the creation of the messagefile make sure GNU gettext() is installed. [If deploying locally on MacOs, you either have to force link gettext() with
brew link gettext --force
(unlink it withbrew unlink gettext
after your translation is done) because it is not symlinked or, if using virtualenvwrapper, set a new PATH variable for your virtual environment. More information here: https://stackoverflow.com/questions/27220052/django-i18n-make-sure-you-have-gnu-gettext-tools/35579852] -
To create or update a messagefile after tags have been added, run
python manage.py makemessages -l fr
(to make a messagefile in French). This will create a PO file. Django uses UTF-8 endcoding a default when generating these files. DO NOT CHANGE! Fill in translation strings and runpython manage.py compilemessages -l fr
. To reexamine all source code and templates for new translation strings and update all message files for all languages, runpython manage.py makemessages -a
.