Internationalization and Localization

This guild will help you to understand internationalization and localisation support provided by KalaPy framework.

Overview

KalaPy has full support for internationalization of text in code and templates, and format localization of dates and numbers. The terms internationalization and localization are generally abbreviated as i18n and L10n respectively. Internationalization and localization is a process of adapting a computer software to different languages and regional differences. For more information on the topic, see Wikipedia.

The general workflow of the process is like this:

  • Application authors have to specify which part of their application should be translatable.
  • Application authors or integrators should provide translation catalogs for different locale.
  • KalaPy will translate web applications for users according to their language preferences.

KalaPy provides internationalization and localization support using Babel and pytz.

Internationalization

The general goal of internationalization is to allow a single web application to offer it’s contents in multiple languages.

KalaPy provides a way to specify which part of the application should be translated. The developers have to mark translatable strings using several gettext functions; and only those strings will be translated.

Standard Translations

You can specify a translation with function kalapy.i18n.gettext() which is aliased to _() for convention. The alias _() is installed as a __builtins__ so that you can directly use _() in your code without importing it in your module.

Here is an example of translating a python module:

from kalapy import web
from kalapy.web import request

@web.route('/')
def index():
    return _('Hello World!')

@web.route('/hello/<msg>')
def hello(msg):
    return _('Hello %(msg)s', msg=msg)

And here is an example of translating Jinja2 template:

<title>{{ gettext('Hello World!') }}</title>
<title>{{ gettext(title) }}</title>
<title>{{ _('Hello World!') }}</title>

For more information, see Jinja2 documentation.

Pluralization

You can specify pluralized messages with function kalapy.i18n.ngettext().

This function does a plural-forms lookup of a given string depending on the num parameter and uses plural instead of string if num represents plural in the current locale.

For example:

from kalapy.i18n import ngettext

from foo.models import Apple

@web.route('/')
def index():
    apples = Apple.all().fetch(-1)
    return ngettext('%(num)d Apple', '%(num)d Apples!', num=len(apples))

In this example, if number of apples represents plural in current locale, the second string will be return. For example, if num is 2 it returns '2 Apples!' but if num is either 0 or 1, it returns '1 Apple'.

Translating templates

Translating templates is a real pain, especially when the strings contains some dynamically generated markup. For example, consider the following template:

Click <a href="{{ url_for('some.endpoint') }}">here</a> for more information.

As the embedded url markup is dynamically generated, it is hard to translate the entire sentence. Also, translating the sentence into pieces might result in wrong translation in some languages. However, KalaPy provides special gettext and ngettext functions for templates to solve this:

{% macro here_link(val) %}
    <a href="{{ url_for('some.endpoint') }}">{{ val }}</a>
{% endmacro %}

{{ _('Click :here_link:`here` for more information.', here_link=here_link)|safe }}

You can see, rst like construct has been embedded into the string. Now, the translator can correctly translate the sentence without loosing the context.

The gettext function _() will then apply the macro to the translated string resulting correct translation.

Translating JavaScript

TODO

Using translations with JavaScript

TODO

Localization

Localization of an application is a process of adapting regional deferences. This can be achieved by creating region specific language files and formatting numbers and dates accordingly.

Working with Catalogs

Once the strings in the application are marked to be translatable, next step is to create message catalogs for a particular language. A message catalog is a plain text file with extension .po, representing a single language, containing all the translatable strings and how they should be represented in particular language.

KalaPy uses Babel command line interface to generate message files. The files when translated should be compiled in .mo format in order to use the new translations.

This can be done with the admin.py script. Type following command on your terminal to see help on catalog related commands:

$ ./admin.py babel -h
Usage: admin.py babel <action> [options] [package [package [...]]]

Perform i18n message catalog related actions.

options:

  -l --locale  locale (e.g. en_US, fr_FR)
  -d --domain  message catalog domain
  -v --verbose enable verbose output
  -h --help    display help and exit

available actions:

  compile  Compile message catalogs to MO files.
  extract  Extract messages from source files and generate a POT file.
  init     Create new message catalogs from generated POT file.
  update   Update existing message catalogs from the generated POT file.

This actions provided by admin.py babel command is identical to the pybabel script that comes with Babel.

Extracting messages

The first step is to extract translatable strings into a message catalog template file. This can be done with admin.py babel extract command:

$ ./admin.py babel extract

This command will generate catalog templates for all the available packages in current project. If you want to extract strings for only a particular package, do this:

$ ./admin.py babel extract foo bar

Where, foo and bar are packages of current project. A locale/messages.pot file will be created under every specified packages.

Creating message catalogs

The next step is to create message catalogs for a new file. If you already have created message catalog for the language, head over to next section on how to update existing catalogs. Creating new catalogs is as easy as:

$ ./admin.py babel init -l fr_FR foo

Where, foo is a package of current project, if omitted, catalogs will be created for all the available packages.

A catalog file locale/fr_FR/LC_MESSAGES/messages.po will be created under all the specified packages.

Note

Catalogs will be only created if it doesn’t exit.

Updating message catalogs

If message catalog is already created and you have changed your code and think that the translatable strings have been changed, you should consider updating existing catalogs. This can be done like this:

$ ./admin.py babel update -l fr_FR foo

If you omit package name, it will perform update on all the available packages. Even if you omit the locale option it will perform update for all the existing languages for a package.

Compiling message catalogs

Once you have created/updated message catalog for a particular language. You have to translate the catalogs and then compile it to .mo format so that the translations can be used by the system. This can be done like this:

$ ./admin.py babel compile -l fr_FR foo

If you omit package name, it will compile catalogs of the given language for all the available packages. Even if you omit the locale option it will compile all the available catalogs.

Catalogs for JavaScript

Message catalogs for JavaScript falls under javascript domain. Perform all the above actions with option -d javascript to create message catalogs for javascript.

Formatting

KalaPy provides several functions to format numbers, decimals and date values to locale specific formats. It also provides few functions to parse localized numbers, decimal and date values.

See Internationalization and Localization for more information.