
Exploring the intl package
The intl
package provides functionality for internationalization and localization of Dart applications. This not only includes the important aspect of translating interface text into other languages but also includes the formatting of text (not every language is formatted from left to right), dates and numbers.
Locating strings to translate
The interface of an application largely consists of buttons, with a few other labels and controls. A phrasebook of the application's interface language can be created using Intl.message
and stored as static functions in the PhraseBook
class, which can be found in the interfacetrans.dart
file. This organizes all the strings that are to be set on the interface elements at runtime using the value
or text
properties:
class PhraseBook { // Navigation controls. static String btnFirstSlide() => Intl.message("First", name: "btnFirstSlide", desc: "Button label - go to the first slide."); static String btnPrevSlide() => Intl.message("Prev", name: "btnPrevSlide", desc: "Button label - go to the previous slide."); …
The functions are static so no instance of the class is required to call the function, so, for example, PhraseBook.btnFirstSlide()
will return the string for the first slide. Intl.message
has a series of named parameters. The name
parameter needs to match the function name for the string extraction tools, which are covered in the next section. The desc
(description) field provides context of where the string is used on the program. This is useful when the translator does not have access to the software that may not even be written yet.
Intl.message
has extensive features, such as modifying a phrase due to it being plural or referring to a different gender. Plus, it can store more meta information such as example usages of the string to give the translator more context. Refer to the SDK documentation for more details.
Extracting the strings
The English strings for the application are now organized in a class file. Next, we need to extract the strings so that they can be sent out for translation. The intl
package contains an extraction tool that can be run from the command line.
Pub
is a tool with many uses in Dart, and one interesting feature of it is to run command-line tools that are part of Dart packages:
pub run packagename:programname
When this command is issued, pub
will look for programname.dart
in the packages bin
folder:
pub run intl:extract_to_arb --output-dir=c:\transarb web\lib\interfacetrans.dart
Note
Refer to https://www.dartlang.org/tools/pub/package-layout.html for more information on the package structure.
Ensure that the target directory already exists. The final parameter is the source file containing the functions with the translation strings.
Tip
The Application Resource Bundle (ARB) is a JSON-based format that is extensible and directly usable by applications.
You can find out more about the format of the project at https://code.google.com/p/arb/.
The JSON format ARB files contain much of the information from the Phrasebook
class translated into a dictionary declaration:
{ "btnFirstSlide":"First", "@btnFirstSlide": {"description":"Button label - go to the first slide.", "type":"text", ...
This easy-to-read and portable file format can be used by a range of applications to produce usable translations.
Google Translator Toolkit (https://translate.google.com/toolkit/) is a powerful online tool that accepts .arb
files, among other formats. This is free to use and requires a Google account to login.

One useful feature of Toolkit is that it is tied to Google Translate so that a computer translation of the text is made available. This is the method that is used for the presentation string resources—it does not give perfect translations but is useful for initial testing and the layout of the interface.
Tip
Managing translations for even a small project can be a sizeable amount of work. Every new button means new strings, new translations, and more testing!
One alternative to Google Translator Tooklit is the open source project Pootle, which can be found at http://pootle.translatehouse.org/.
From my experience I can tell you that translators come from a range of backgrounds, are not always technically minded, and you have to deal with significant time differences. Time to use those important people-focused soft skills!
Each language can be translated separately and the tool allows progress to be tracked of the translation process. The translation file can be shared with other users and translations can be crowd-sourced if desired.
Once the translation is complete for the language, they can be downloaded as .arb
files. Let's have a look at the following screenshot:

Integrating the translations text
Now that the translations are safely stored as strings, it is time to bring them back into the Dart project by transforming theses files into Dart source code files.
Notice the naming of the ARB files with _es
and _fr
that allow the intl:generate_from_arb
tool to determine which language is in play. In this case, the Dart files are being put directly into the project in the lib
folder:
pub run intl:generate_from_arb --output-dir=web/lib web/lib/interfacetrans.dart web/lang/messages_es.arb web/lang/messages_fr.arb
The files created include the central messages_all.dart
message, which is the main import Dart file. There is also a supporting file created for each language that is being used, messages_es.dart
and messages_es.dart
.
Changing the language of the user interface
To make use of the translations, the messages_all.dart
file needs to be imported into interfacetrans.dart
. The intl
package needs to be told which language we want to use, and behind the scenes, it deals with loading the correct resources. The setInterfaceLang
function in interfacetrans.dart
carries out this task and is called by the SlideShowApp
constructor:
setInterfaceLang(String langID){ initializeMessages(langID).then((_) { Intl.defaultLocale = langID; addInterfaceText(); }); }
Best of all, the addInterfaceText
method does not need to change, no matter how many new languages are added.
Adding a language combo box
For users and developers, it is useful to change the language of the interface anytime. We will add a combo box with a handler for the onChange
event to allow the user to select a language from the list:
<select id="interfaceLang"> <option>en</option> <option>fr</option> <option>es</option> </select>
All the initialization for the interface has been wrapped in the setInterfaceLang
method, so the only parameter that is to be passed is the value from the combo box (SelectElement
):
setInterfaceLang("en"); qs("#interfaceLang").onChange.listen((e) { var lang = qs("#interfaceLang").value; setInterfaceLang(lang); langInterface = lang; ...
This is set up with the other listeners in the SlideShowApp
constructor and triggers the change of the interface requested by the user. The language can be switched to a French user interface with a single click at runtime, and the change occurs almost instantly.

The length of strings can vary wildly from language to language - the button layout allows expansion. Note the differences in button between the Spanish and French translations.
This is a factor to consider when planning the interface layout of your multilingual applications. It is probably best to assume that other languages will be longer and allow some room for expansion.

Advanced as the application is, I am afraid that it is left to the user to translate the demo coconut presentation material!