Extension Locales

In TAO, a Locale is the definition of all messages to be translated for a given TAO Extension. Indeed, the internationalization process applies to each TAO Extension. Any translation description files are located in the /locales directory of the Extension to be translated. In this /locales folder you will find a directory dedicated to each language. The directory name for a language contained in the /locales directory is actually is a combination of the language code and a region code (e.g. fr-LU for French as used in Luxembourg) and will be used as a unique identifier for this locale across extensions.

Locale Structure

An Extension Locale is composed of several translation files. For instance, the French Locale for the Extension taoGroups is located in the /[tao_installation_path]/taoGroups/locales/fr-FR directory and contains the following files:

  • messages.po: contains the translations of the Graphical User Interface. This is the file you must edit if you want to change the translation of a message displayed in the taoGroups Extension. These files are using the well-known PO format of GNU gettext.
  • messages.lang.php: contains a PHP compiled version (as an associative array) of messages.po used at runtime on the server-side. It also includes translations of messages contained in extensions on which the extension you translate depends on for better performance. This file must not be edited manually.
  • messages_po.js: contains a JSON (JavaScript Object Natation) compiled version of messages.po used at runtime on the client side. Like messages.lang.php, it contains the translations of messages contained in extensions which the translated extension depends on.
  • taogroup.rdf: contains the translations of the Data Model of your extension. It uses the RDF-XML standard to describe the rdfs:labels and rdfs:comment properties values of the resources of a given Data Model. In this example, the taogroup.rdf file located in /taoGroups/locales/fr-FR contains references to all rdfs:label and rdfs:comment properties of the Classes, Properties and Instances contained in the taogroup.rdf XML-RDF Data Model which can be found in the /taoGroups/models/ontology directory.
  • other .rdf files: translations of various Data Models of your extensions that are not mandatory.

Please note that an exception arises regarding the tao Meta-Extension. Indeed, it contains an additional file named lang.rdf which contains the description of the locale to insert in the Database to make it available to end-users.

Internationalized Source Code

To make sure that messages contained in the source code will be included in message.po files, you can use the __() method. For instance, if you have to display the message "Hello World" in your PHP Source code, simply write:

echo __('Hello World');

Even without any messages.po files set up, this will appear in your output as Hello World (in all languages).

A messages.po file is generated or updated when the taoTranslate.php script is run (see section below). This can be done manually from the command line.

When, for example, locales/fr-FR/messages.po is generated by parsing the source code of TAO, looking up for __() calls, the following message to be translated will appear in it:

msgid "Hello World"
msgstr ""

There is now only to translate "Hello World" into the correct language:

msgid "Hello World"
msgstr "Bonjour le monde"

The same technique to define messages can be applied to JavaScript source code as well, still using the __() method. Within handlebars templates, text to be translated is formatted like this: {{__ 'Hello World'}}

PO Files

PO File Format

TAO implements the gettext PO file format to provide a fast and easy way to translate messages in its source code.

Here is a minimal PO file as it is found in TAO for a French locale:

msgid ""
msgstr ""
"Project-Id-Version: TAO 3.3.0-sprint88\n"
"PO-Revision-Date: 2018-11-02T08:06:53\n"
"Last-Translator: TAO Translation Team <translation@tao.lu>\n"
"MIME-Version: 1.0\n"
"Language: fr-FR\n"
"sourceLanguage: en-US\n"
"targetLanguage: fr-FR\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "Hello World"
msgstr "Bonjour le monde"

In TAO PO files, the first message is always a meta-message. Such a message has an empty msgid but its msgstr contains information about the file. In this sample file, we can find the following information:

  • Project-Id-Version: The project the PO file belongs to.
  • PO-Revision-Date: Corresponds to the last time the file was updated with new messages extracted from the source code.
  • Last-Translator: The last translator that translated messages in the file.
  • MIME-Version: The PO format version in use.
  • Language: The target language of the PO file. In other words, the language in which messages have to be translated.
  • Content-type: The type of the content in this file.
  • Content-Transfer-Encoding: How the file is encoded during a transfer.

Right after this meta-information comes the first message of the file, made up of two components which are msgid and msgstr.

msgid "Hello World"
msgstr "Bonjour le monde"

The msgid component corresponds to the initial message extracted from the source code. The translator will take its value, put between double quotes (") to create its translation. In this example, the value of msgid is Hello World.

The msgstr component contains the translation of msgid, that will be displayed to the end user that selects the related locale. When extracted from the source code, the msgstr component will appear empty. The translator will have to enter its value.

How to Edit PO Files

Because PO files are just plain text files, you can use your favorite editor to modify them. In this case, please make sure that the encoding is UTF-8. Alternatively, you can use a specialized gettext editor that will display messages to be translated in a more friendly way. We recommend the use of POEdit, a free and multi-platform gettext editor.

PO files Compilation

When messages contained in a PO File are updated (e.g. correction of an existing translation) or are simply added, it has to be compiled. Indeed, only compiled translations are available to the end-users (for better performance). TAO is packaged with translation tools making you able to compile PO files on your own. To do so, please refer to the tao_scripts_translate|TAO Translate Script Documentation.

RDF Translation Models

Because TAO uses Ontologies in the Resource Description Framework (RDF), its Data Models are totally translatable. Any Class, Class Property or Resource in TAO has two properties, rdfs:label and rdfs:comments that can be translated for each language your TAO platform supports.

Here is an example of RDF Model Translation (RMT) shipped with the standard Open Source release of TAO, that describes how to translate the Data Model of the taoGroups extension in the French locale, located in /taoGroups/locales/FR/taogroup.rdf.

<?xml version="1.0" encoding="UTF-8"?>
    @sourceLanguage EN
    @targetLanguage FR
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xml:base="http://www.tao.lu/Ontologies/TAOGroup.rdf">
  <rdf:Description rdf:about="http://www.tao.lu/Ontologies/TAOGroup.rdf#Group">
    @sourceLanguage EN
    @targetLanguage FR
    @source Group
    @subject http://www.tao.lu/Ontologies/TAOGroup.rdf#Group
    @predicate http://www.w3.org/2000/01/rdf-schema#label
    <rdfs:label xml:lang="FR"><![CDATA[Groupe]]></rdfs:label>
    @sourceLanguage EN
    @targetLanguage FR
    @source Group
    @subject http://www.tao.lu/Ontologies/TAOGroup.rdf#Group
    @predicate http://www.w3.org/2000/01/rdf-schema#comment
    <rdfs:comment xml:lang="FR"><![CDATA[La Classe Groupe. Un aggrégat de Sujets.]]></rdfs:comment>

The most important thing to understand in this RMT is that the label and comments translations are located within the <rdfs:label> and <rdfs:comment> tags. In this example, <rdfs:label xml:lang="FR"><![CDATA[Groupe]]></rdfs:label> represents the label of the Group Class translated in French. On the other hand <rdfs:comment xml:lang="FR"><![CDATA[La Classe Groupe. Un aggrégat de Sujets.]]></rdfs:comment> depicts the textual description of the Group Class.

Dealing with your own locales

The TAO Platform comes with dedicated tools that help you to create and maintain your own locales. It takes the form of a command line script that can be accessed through PHP CLI. These dedicated tools will enable you to create and update your own locales in TAO.

Create a locale

Creating a new locale is as easy as a single command. Open your favourite command line interface and go into the /path_to_your_install/tao/scripts directory. In the following example, we will create a new locale called es-MX (Mexican Spanish) for each extension delivered in the Open Source release of TAO.

cd /path_to_your_install/tao/scripts
php taoTranslate.php -v -a=create -l=es-MX -ll="Mexican Spanish" \

As a result, you will get a new locale directory named es-MX for each extension in TAO. Each locale folder contains PO Files and RTMs ready to be translated.

How to choose your language tag

TAO uses IETF BCP 47 language codes. If you need to choose a language tag, please refer to:

Other sources include:

Examples (You are not forced to used region tags. The only requirement is a first language tag, and at least one sub tag after the dash).

Locale Language Tag Region or language tag
nl-NL nl (Dutch) NL (Netherlands, region)
fr-BE fr (French) BE (Belgium, region)
zh-SG zh (Chinese) SG (Singapore, region)
ar-arb ar (Arabic) arb (Standard Arabic, language)

How to update or add translations

Scan the source files for __() enclosed strings

// Syntax
// php tao/scripts/taoTranslate.php -v -a=create|update -e=[extension] -l=[locale]

php tao/scripts/taoTranslate.php -v -a=create -e=taoQtiTest -l=fr-FR

// Example for an update
php tao/scripts/taoTranslate.php -v -a=update -e=taoQtiTest -l=fr-FR

This will generate the following files in taoQtiTest/locales/fr-FR:

  • messages.po
  • messages_po.js
  • numerous .rdf.po Files
  • lang.rdf (if you are in the tao meta-extension)

Fill the generated messages.po file with your translations.

TIP Adding the -f (--force) flag to taoTranslate.php -a=create will overwrite any existing translations in the PO files of the specified locale; effectively a reset to a blank state.

Compile the file into PHP and JavaScript

php tao/scripts/taoTranslate.php -v -a=compile -e=taoDelivery -l=fr-FR

This will generate messages_po.js and a number of non-essential .rdf files in your locale, which is now almost ready to be used in TAO.

Update TAO

After compilation, run the TAO update script:

php tao/scripts/taoUpdate.php
// ...
// ..."Successfully updated 26 client translation bundles"

Other Tools

In cases where translations will be done externally and extensive use of the command line is not desired, there is a separate web-based translation tool.

On this platform it's possible to import, work on, and export .po files for each version of TAO and all the languages it supports.

Adding a new system language

How to add a locale generated by the taoTranslate.php script as a system language of TAO? The key file you need is /tao/locales/xx-XX/lang.rdf. It contains some pieces of data you can see in the following example.

  • label - the English name of the language
  • value - the locale code
  • ...#LanguageUsageGUI line - enables this as a GUI language
  • ...#LanguageUsageData line - enables this as a Data language
  • ...#OrientationLeftToRight line
<rdf:Description rdf:about="http://www.tao.lu/Ontologies/TAO.rdf#Langde-DE">
  <rdf:type rdf:resource="http://www.tao.lu/Ontologies/TAO.rdf#Languages"/>
  <rdfs:label xml:lang="en-US"><![CDATA[German]]></rdfs:label>
  <tao:LanguageUsages rdf:resource="http://www.tao.lu/Ontologies/TAO.rdf#LanguageUsageGUI"/>
  <tao:LanguageUsages rdf:resource="http://www.tao.lu/Ontologies/TAO.rdf#LanguageUsageData"/>
  <tao:LanguageOrientation rdf:resource="http://www.tao.lu/Ontologies/TAO.rdf#OrientationLeftToRight"/>

GUI or Data? Normally you will want both. Omit the GUI line if the language is only desired for Data (for example you want to enable text-to-speech for Items, but there are not enough UI strings to offer it as a GUI language). Omit the Data line if you want to have the TAO interface in that language but don't care about your items.

Before it appears in the TAO back office, this RDF data needs to be imported to the ontology. The Updater.php of the tao extension could follow the pattern shown below:


$iterator = new FileIterator(__DIR__ . '/../../locales/de-DE/lang.rdf');
$rdf = ModelManager::getModel()->getRdfInterface();

/* @var \core_kernel_classes_Triple $triple */
foreach ($iterator as $triple) {

You do not need anything special in manifest.php, as all available languages will be detected and activated during a TAO install.