Dart:Scalable Application Development
上QQ阅读APP看书,第一时间看更新

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.

Tip

The next section of this chapter deals with the task of running tools from the command line. Ensure that the Dart SDK bin folder is on the executable path for your system so that pub and other Dart tools can be executed from anywhere on the command line.

Running commands with Dart pub

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.

Obtaining 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.

Obtaining translations

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:

Obtaining translations

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.

Adding a language combo box

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.

Adding a language combo box

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