Introduction

Let’s face it: internationalization is inevitable! As the importance of dynamic, client-side rendered web components increases, so does the need for a client-side i18n solution. In this article a simple component is introduced which asynchronously loads a translation file (in JSON) and provides other components with an I18N behavior to be used for computed bindings or simply directly in code.

tl;dr

Grab the code on gitlab or install it using Bower:

bower install https://gitlab.com/quaintous-polymer/quaintous-i18n.git

now you can start using it in a custom element:

<link rel="import" href="../../components/polymer/polymer.html">

<dom-module is="localized-tag">
  <template><span>[[__(myProperty)]]</span></template>
  <script>
  Polymer({
    is: 'localized-tag',

    properties: {
      myProperty: String
    },

    behaviors: [I18N]
  });
  </script>
</dom-module>

note the behaviors: [I18N] line. Now this:

<quaintous-i18n locales-path="/locales/fa.json"></quaintous-i18n>
<localized-tag my-property="hello"></localized-tag>

renders to:

<span>سلام</span>

Considerations

The previous example assumes that fetching the translation file (i.e. fa.json) is succeeded before the localized-tag is ready and attached, otherwise myProperty cannot be bound (i.e. translated) correctly when the element is rendered. This can be solved using conditional templates as shown bellow:

<template is="dom-bind">
  <quaintous-i18n locales-path="/locales/fa.json" loading=""></quaintous-i18n>
  <template is="dom-if" if="">
    <localized-tag my-property="hello"></localized-tag>
  </template>
</template>

The Element

Why create an element at all when a simple behavior (which is a simple JS object) suffies? Well, I just wanted to comply with Polymer’s motto “there’s an element for that”. After all I believe that an element is the more elegant and readable way to do this task.

Our element depends on iron-ajax and exposes a simple API with two properties locales-path, denoting the translation file URL, and loading which is true while the AJAX request is on the fly.

When the element is imported it registers I18N object in the global context (i.e. window) which is to be used by other Polymer elements as a behavior. After the element is loaded and attached, the iron-ajax loads the translations files and on success it saves the received data also in the global context in __i18n__ variable. From now on I18N.__(key) can be used.

Conclusion

There are a number of other approaches all with the goal of providing internationalization for Polymer components. This approach follows Polymer’s “there’s an element for that” motto and introduces an element which loads translation files asynchronously and provides other elements with a behavior which can be used for translation.