How did all that work?

As I promised at the start of the previous section, after seeing Django translations in action, we will now take a deeper look into all the steps we followed to get to this point and what each of these steps did.

The first thing that we did was load the i18n template tags library, which provides us with a variety of template tags to translate content in the template. The most important, and probably the one that you will use the most, is the trans tag. The trans tag accepts a string argument and, depending on the language that is active, outputs the correct translation for that string. If the translation cannot be found, the original string is output instead.

Almost any string that you write in your templates will end up being wrapped by the trans tag and then later translated to the various languages that your web application is available in. There are certain situations in which the trans tag is not usable. For instance, if you have to add the value of some context variable to the translated string, the trans tag can't do this. For these cases, we need to use the block translation tag, blocktrans. We won't be needing it in our application, but you can read about it in the Django documentation at https://docs.djangoproject.com/es/stable/topics/i18n/translation/#blocktrans-template-tag.

Our next step was to run the make messages command. Our first attempt didn't succeed, so we had to create a locale directory in our application folder. Having done that, we ran the command and it created a message file with the .po extension. What the command does is it goes over every file in your project and extracts strings that you have marked for translation. One way to mark a string is to use the trans tag to wrap it. There are other ways as well that we will look at later.

After the make messages command has extracted the strings, it needs to create files and store the extracted strings in these files. There is a set of rules that Django follows when figuring out which file each extracted string goes to. For strings extracted from the files of an app, Django first tries to find a locale directory in the folder for that app. If it finds the folder, it creates the appropriate hierarchy underneath it (the fr/LC_MESSAGES directories) and places the messages file there.

If the locale folder is not found, Django looks at the value of the LOCALE_PATHS settings variable. This should be a list of directory locations. Django selects the first directory from this list of paths and puts the messages file there. In our case, we didn't have the LOCALE_PATHS setup, which is why Django raised an error, not finding a locale directory in our main application folder.

Let's talk a bit about the format of the messages file. Here is what our messages file looks like right now:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION
"
"Report-Msgid-Bugs-To: 
"
"POT-Creation-Date: 2016-02-15 21:25+0000
"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>
"
"Language-Team: LANGUAGE <[email protected]>
"
"Language: 
"
"MIME-Version: 1.0
"
"Content-Type: text/plain; charset=UTF-8
"
"Content-Transfer-Encoding: 8bit
"
"Plural-Forms: nplurals=2; plural=(n > 1);
"

#: main/templates/movies_list.html:6
msgid "Movies List"
msgstr "Liste des films"

#: main/templates/movies_list.html:10
msgid "Stars"
msgstr "Étoile"

Lines starting with # are comments. Then, there is an empty pair of msgid and msgstr. This is followed by some metadata about this messages file. After that, we get the main part of the time. A messages file, ignoring the metadata and first pair (the one preceded by the fuzzy comment), is just a list of msgid and msgstr pairs. The msgid pairs is the string that you have marked for translation, and msgstr is the translation for that string. The usual method of translating an app is by first marking all the strings for translation, then generating the messages file, and finally providing it to the translator. The translator then returns the file to you with the translations filled in. The benefit of using a simple text file is that the translator doesn't need to use any special software. If he has access to a simple text editor, he can translate the messages file.

Once we have translated the strings in the messages file, we need to run the compile messages command before Django is able to use the translations. The compile command, as mentioned earlier, converts the text messages file to a binary file. The binary file format is much quicker to read from for Django, and in projects with hundreds or thousands of translatable strings, these performance benefits add up very quickly. The output of the compile messages file is a .mo file in the same folder as the .po file.

Once we have our translations done and compiled, we need to set up a few Django configurations. The first thing we do is add LocaleMiddleware to the list of middlewares that our application uses. The job of LocaleMiddleware is to allow users to select the language of the site based on a couple of request parameters. You can read the details of how the language is determined in the documentation at https://docs.djangoproject.com/es/stable/topics/i18n/translation/#how-django-discovers-language-preference. We will come back to it in a bit, discussing how it determines the language with an example.

We then needed to defined two settings variables, LANGUAGES and LANGUAGE. LANGUAGE was already defined in the code pack, so we only set the LANGUAGES variable. LANGUAGES is a list of language choices that Django can provide translations for the site in. By default, this is a huge list that includes all languages that Django can be translated into. However, for most projects, you want the user limited to a few languages to use the site in. By providing our own value for the LANGUAGES list, we ensure that Django doesn't serve pages for any languages other than the ones defined.

The LANGAUGE variable defines the default language to use. If you remember, when we opened the home page without any language code (http://127.0.0.1:8000/), the English language was selected by default. The LANGUAGE variable decides what the default language for the site is.

The next part of making the app translatable was to modify the url.py file. In place of the simple list of URL configuration elements, we wrapped our URL configurations inside of an i18n_patterns function. This function allows us to match URLs that have a language code prepended to them. For every request that comes in, this function tries to match the patterns that we wrapped in it after removing the language code from the URL path. It's a bit complicated to explain, so let's look at an example.

Let's say that we have the following URL pattern:

url(r'^example/$', View.as_view(), name='example')

This would match DOMAIN.COM/example/, but if we tried DOMAIN.com/en/example/, the pattern would not result in a match as the /en/ part is not part of the regex. However, once we wrap it in i18n_patterns, it will match the second example. This is because the i18n_patterns function removes the language code and then tries to match the patterns that we wrapped in it.

In some applications, you don't want to have all the URLs matching with language prefixes. Some URLs, such as an API endpoint, don't change based on the language. In these cases, you can add together i18n_patterns and the normal list of URL patterns:

urlpatterns = i18n_patterns(url(r'^example/$', ExampleView.as_view(), name='example')) + [url(r'^api/$', ApiView.as_view(), name='api')]

This way, you can create applications that are a mix of translated and non-translated views.

Having added i18n_urlpatterns, we are done with all the configuration that Django needs for basic internationalization, and we can visit the pages that we have in the French language and see the translated versions.

The last thing that I have left to explain is LocaleMiddleware. The locale middleware is the part of Django that allows users to use the language code in the url to decide which language to use. Thus, even though it's i18n_patterns that matches patterns based on language codes, it's the middleware that activates the correct language for each request. Other than using the language prefix in the URL path, LocaleMiddleware provides you with a few other ways to select the language as well:

  • A session variable
  • A cookie value
  • The Accept-Language header that the user's browser sends
  • If all else fails, the default language from the LANGUAGE setting variable is used

This is an overview of how we adapted our application to be translatable. However, we're not done yet.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.65.65