Staś Małolepszy

Refactored l10n.js landed in Gaia

The l10n.js refactor which landed today in Gaia is the first step of a long-term goal of improving the localization technology available in Firefox OS.

Today Zibi and I landed the refactored code of shared/js/l10n.js in Gaia master. A culmination of months of hard work, the refactor is also a first step of a larger initiative to innovate in the area of mobile localization and eventually, to implement L20n in Gaia.

Firefox OS faces a number of challenges related to localization. Growing the locale coverage beyond 20 supported locales; adapting to multiple screen sizes and form factors; ensuring the performance and memory consumption is good when the DOM is localized on the fly. In order to respond to these needs and many more that we will encounter in the future, we need a flexible and modular codebase, with a thought-out API designed to perform well in asynchronous scenarios.

We decided to re-write Gaia's l10n.js drawing from our experiences from developing L20n. The underlying concepts are similar: the code is organized into useful abstractions like the localization Context managing the fallback chain of Locale objects, or the Entity class which represents a single translation unit.

It's not L20n just yet. The library still uses the .properties file format.
There are no custom macros or arbitrary dicts which allow localizers greater flexibility in creating translations. The language fallback is limited to two locales. It still is a good first step towards empowering developers and localizers alike.

To minimize the risk of regressions, the refactored code was almost a drop-in replacement for the old l10n.js library. We decided to keep the exact same API of the navigator.mozL10n object. Everything should just work as it did before. We feel that there's room for improvement in the API design, and we'll soon start suggesting changes to it (e.g. bug 993188 has made many developers implement workarounds in their apps, which would break if we fixed it right away in our refactored drop-in patch).

Notable changes

  • Modular code which encapsulates main concepts of localization with a clean OOP approach.

  • Better security thanks to the lazy compilation step.

  • Better error reporting, especially on build time:

    /build_stage/browser/index.html: [l10n] [ar]: 3 missing in the visible 
      DOM: enter-search-or-address, top-sites-startPage, 
    /build_stage/browser/index.html: [l10n] [ar]: 10 missing compared to 
      en-US: brandShortName, browserBrandShortName, browserBrandFullName, 
      enter-search-or-address, top-sites-startPage, top-sites-tab, 
      search-engines, default-search-engine, edit-bookmark, 
  • The internal API (currently hidden behind the navigator.mozL10n wrapper) is ready to fully support asynchronous parsing, compilation and fetching of translations, which we think will be important when implementing language packages for Firefox OS.

  • You can now freely nest placeables, meaning that this will work:

    foo = Foo
    foobar = {{ foo }} Bar
    foobarbaz = {{ foobar }} Baz
  • Good test coverage, both in our source repo and as part of the Gallery app test suite.

Feedback and bugs

The top priority fot this refactor was to be 100% compatible with the old l10n.js library. We made sure all tests pass on Travis and on TBPL and put a lot of effort into writing additional tests. We will be monitoring the tree for any regressions. If you notice something weird going on with your device or your app, for instance related to language switching, please let us know.
File bugs in the newly created Gaia::L10n component in Bugzilla or find us in #gaia and #l20n.

Next steps

The list of tasks on our to-do list is long, but we couldn't be more exited about them. Ranging from UX improvements to developer-friendly APIs, to giving localizes more control over their translations, next months are going to be great for localization and Firefox OS. A sneak peek, in no particular order:

  • Revisit the build time optimizations currently used in production Firefox OS builds, which we suspect cripple the performance of builds with more than 20 locales installed.

  • Implement responsive localization tools, such as the @formFactor macro which makes it possible to define different translations for tablets and phones.

  • Clean up the app startup API; implement mozL10n.ready() and mozL10n.once() as separate methods (bug 993188) and move away from listening to the 'localized' events.

  • Improve app launch performance by delaying localization when possible.

  • Research the use of Mutation Observers to automatically localize new DOM nodes when they are inserted into the existing DOM.

  • Research langpacks, possibly using the DataStores API.

  • Implement better language negotiation and language fallback via the ECMAScript Internationalization API and the navigator.languages API.

Published on 08.04.2014

Staś Małolepszy

Thoughts about the Internet, the information society, Mozilla and human-computer interactions.

Latest notes