Navigation

You have a project that uses Obviel for its user interface, and now
you want it to work in multiple languages. For this you need to adjust
your application to support multiple languages, a process known as
“internationalization”, or “i18n” for short (as “internationalisation”
has 18 letters between the ‘i’ and the ‘n’).

How do you go about this?

The idea is that you mark up all translatable texts in your project’s
code (.js and .obvt files) in a special way. Then when your
application runs for the marked up pieces of text a translations
registry is consulted. If a translation is found for a marked up piece
of text, it is used instead of the original text.

A special extraction tool can be used to extract the marked up pieces
of text from .js and .obvt files, so that they can be given to
human translators for translation.

This application has been written with one language in mind, in
this case English. But if the application runs with another language,
for instance French, we’d like to see the popup in that language (for
instance “Bonjour monde!”) instead of in English.

You can make this happen using jsgettext. This uses the gettext
approach, which is very often used for i18n for a variety of projects
and programming languages. Include jsgettext like this:

<script type="text/javascript" src="/path/to/Gettext.js"></script>

We now need to make a translation available for our Helloworld!
message. This is what that looks like:

The exact structure of json_locale_data object is not something to
worry about, as later in this document we’ll introduce a tool to generate
this automatically for you. We just wanted to provide for the purposes
of a demo.

We are now ready to create a Gettext object for your project that
knows about the translations available:

We know how to mark up our JavaScript code so it can be translated
now. We now need a tool that can extract all pieces of marked up text
so that we can give it all to a translator.

We recommend the use of the Babel i18n tool with code that uses
Obviel. While Babel primarily written to support i18n of Python
applications, it also supports JavaScript applications.

why babelextract and not xgettext?

xgettext is the standard GNU gettext tool to extract message ids
from JavaScript code. Unfortunately this tool still does not have
native support for JavaScript. The C extractor comes pretty
close, but JavaScript code needs some preprocessing (into fake C
code) before it’s safe to use this.

There is a tool for this based on the same code as used in the
Django web framework, called jslex. When you install it you’ll have
a script available called jslex_prepare that can be used to
preprocess .js to make them safe for xgettext. This is
pretty cumbersome, so just use Babel instead if you can.

Plus you’ll get to use the plugin for Babel to extract translatable
content from .obvt files too!

We do use the standard GNU gettext msginit and msgmerge
however.

If you’re on Linux, Babel may be available in your Linux
distribution. You can also install it manually using one of the Python
tools used for this (pip, easy_install, or
buildout). After you do this a pybabel commandline tool will
be available.

To make Babel work with .js files we first need to configure
it. Create a .cfg file with the following content:

[javascript: **.js]
extract_messages = _

Now you can use it on your project’s directory that contains all the
.js files:

$ pybabel extract -F myconfig.cfg project_directory > myproject.pot

You will now have a .pot (PO template) file that will be the
source of all your actual translation files for your application, the
.po files. For example, if you had applied this to the demo
described above, you would get a .pot file like this (skipping
some metadata boilerplate):

#: src/demo/i18n-js-demo.js:15
msgid "Hello world!"
msgstr ""

In the comment line it points out where in the code the text to
translate was found; this is sometimes useful context for translators.

For each language our project has translations for, we now need to
create a .po file from our .pot file. You can do this with the
GNU gettext tool suite, using the msginit tool (details about msginit):

$ msginit -l fr_FR -i myproject.pot -o myproject-fr_FR.po

Why msginit and not pybabel?

The pybabelinit command does much the same as msginit from
the GNU gettext tools, but unfortunately it has various assumptions
built in concerning a standard gettext directory structure that are
not used when internationalizing a JavaScript application, and it
seems to be difficult to turn these assumptions off. msginit
does let us do what we want. (if you can figure out how to use
pybabelinit for this purpose, let us know!)

This command says we want to create a specific .po`filefortheFrenchlanguagelocale(``fr_FR). This is what the generated .po
file looks like:

In practice, you would likely give this file to someone else: the
person translating the application to French. They can then edit it
directly to add or update the translations, or use some GUI tool that
can work with .po files. When they are done, they would give the
file back to you.

When your project evolves, you will likely add new texts to translate,
or change or remove existing ones. You can use the babelextract
tool as usual to extract a new .pot file containing all the
current translation texts. You can then use the GNU gettext
msgmerge tool (details) to update your existing .po files so that the
new translatable texts become available to your translators:

We now have a .po file with the right translations. While
jsgettext offers a way to load up such .po files directly, it is
recommended you use an optimized JavaScript file for this instead. We
can do this using the pojson tool (installable using one of the
Python methods such as pip, easy_install or buildout).

We’ve now demonstrated the procedure for a .js file, but what
about Obviel Template .obvt files? We provide a plugin to Babel
called babel-obviel that knows how to extract translatable text
from .obvt files. You install it using the standard Python
installation tools (make sure it is installed in the same Python as
Babel is, so that Babel can pick up on it).

Now you could have a template like this, marked up for translation:

<p data-trans="">Hello world!</p>

We need to teach pybabelextract about .obvt files in the
.cfg file we created before:

[javascript: **.js]
extract_messages = _
[obvt: **.obvt]

When you now run pybabelextract on your project, it will extract
translatable texts not only from .js files but from .obvt
files as well. You can translate these in the same way.