Flask Series: Internationalization

Internationalization (i18n) enables applications and services to support multiple languages and locales. Localization (L10n) adds support for a given language and locale.

The Flask-Babel extension adds support for i18n and L10n in a Flask application. It is built based on babel, pytz and speaklater.

Flask-Babel is easy to install and configure:

pip install Flask-Babel

bookshelf/config.py

SUPPORTED_LANGUAGES – dictionary stores information about the available languages, that are supported in the application.
BABEL_DEFAULT_LOCALE – default locale to use if no locale selector is registered, default is ‘en‘.
BABEL_DEFAULT_TIMEZONE – timezone to use for user facing dates, default is ‘UTC‘.

bookshelf/babel.cfg

The babel.cfg is a mapping file, intended to be used with the pybabel command line tool. It contains configuration data for Babel to tell where to look for texts – supported files, paths, etc.

Now that you have the Flask-Babel extensions installed and configured, you should provide the babel extension with locale and timezone information. It will call localeselector and timezoneselector functions to retrieve this information, if no data is returned (None) Flask-Babel will use the default settings from the configuration.

bookshelf/__init__.py

Several callback functions are used for managing the currently used language. The url_defaults() callback function set_language_code is used to inject values into a call for url_for() automatically.

bookshelf/__init__.py

The url_value_preprocessor() registers the get_lang_code() function, which obtains and sets the language code from the request on the application globals flask.g object.

bookshelf/__init__.py

The before_request ensure_lang_support function executes before each request and it is helpful to verify if the provided language is supported by the application.

bookshelf/__init__.py

Flask allows developers to register blueprints multiple times with different URLs, which can be used to add i18n support:

bookshelf/__init__.py

The next step is to mark all of the strings for translation, by wrapping them either in gettext() or in _() function calls:

Before

After

Once marked for translation, the texts should be extracted:

pybabel extract -F bookshelf/babel.cfg -o bookshelf/messages.pot bookshelf

To create a translation for a given language run the following command:

pybabel init -i bookshelf/messages.pot -d bookshelf/translations -l bg

where the pybabel init command writes a new (bg) language catalog in the bookshelf/translations directory for the extracted data from the bookshelf/messages.pot file. The command will create a new bookshelf/translations/bg/LC_MESSAGES folder and a new messages.po file inside. The messages.po file is used by the _() and gettext() function calls. You could use the poedit translation application to translate the strings accordingly.

When the translations are done, they should be compiled:

pybabel compile -d bookshelf/translations

The complete demo application, described in this blog post, can be found here.

In the next blog post I will describe how to deploy your Flask application.

  • Lipis

    As a next step you could also check my integration of Babel with gae-init: http://babel.gae-init.appspot.com/

  • Greg David

    Hello Damyan! For app localization projects, I suggest to evaluate an online localization tool like https://poeditor.com/ which equipped with useful features (API, translation memory, GitHub and Bitbucket integration, automatic translation) that can make things easier for users, allowing them a simpler way to manage the translation workflow.