Localization

Localization

The Fliplet.Locale JS API and Fliplet’s localization framework allow you to customize your component to different languages and regions.

There are 3 key aspects of a component that can be localized to the device or browser language/region settings.

  • String translation
  • Date format
  • Number format

String translation

Components can now define a translation.json file in their root to list out all keys and default English translation value.

  • Keys can be nested
  • Plurals and placeholders are expected to use the i18n notation
{
  "widgets": {
    "form": {
      "submitButton": {
        "label": "Submit"
      },
      "required": {
        "label": "apple"
      },
      "errors": {
        "required": "There are  fields that need to be filled in",
        "offline": "You need to be online to submit this form."
      },
      "success": {
        "message": ""
      }
    }
  }
}

A new JS API and global functions wrapping i18next will be made available to JavaScript and client-side Handlebars.

JS API

Fliplet.Locale.translate("widgets.form.required.label");
Fliplet.Locale.translate("widgets.form.errors.required", { n: 3 });

// Use the T() shorthand function instead
T("widgets.form.success.message", { msg: "<img..>" });

Handlebars

{{ T "widgets.form.success.message" }}

Please note that the T function is only available after the Fliplet() promise has resolved, so you may need to wrap your code as necessary to make use of translations:

Fliplet().then(function () {
  // Compile Handlebars templates only when translations have been initialized
  const myTemplate = Handlebars.compile(Fliplet.Widget.Templates['templates.foo']());

  Fliplet.Widget.instance('my-component', function(data) {
    // Use the "T" function only when translations have been initialized
    const translatedText = T('widgets.myComponent.pleaseWait');
    const translatedTemplate = myTemplate({ foo: 'bar' });
  });
});

Localization helper libraries and frameworks

jQuery

Components can use $(this).translate() (e.g. in Fliplet.Widget.instance()) after having initialized their template to automatically bind data-translate="key" properties in the target element.

When a DOM element is added to the page with translation keys assigned using data-translate, the translations are not automatically applied. $.fn.translate() must be applied on the rendered DOM to apply the translations.

Please note that the $(this).translate() function is only available after the Fliplet() promise has resolved, so you may need to wrap your code as necessary to make use of translations:

Fliplet().then(function () {
  $('form').translate();
});

More docs on https://github.com/i18next/jquery-i18next.

Handlebars

Client-side Handlebars templates can use the {{ T }} helper to print translations.

Handlebars.compile('{{ T "widgets.form.errors.required" n=3 }}')()

More docs on https://github.com/UUDigitalHumanitieslab/handlebars-i18next

Vue.js

Vue can optionally bind the i18n helper for Vue (returned by Fliplet.Locale.plugins.vue()) on initialization:

var $form = new Vue({ i18n: Fliplet.Locale.plugins.vue() });

Then, strings can be translated using the $t helper in vue templates in build.html or Vue templates in general:

{{ $t("widgets.form.required.label") }}

Please note that the Fliplet.Locale.plugins.vue() function is only available after the Fliplet() promise has resolved, so you may need to wrap your code as necessary to make use of translations:

Fliplet().then(function () {
  Fliplet.Widget.instance('my-component', function(data) {
    var $form = new Vue({ i18n: Fliplet.Locale.plugins.vue() });
  });
});

If you need to configure the plugin before translations inizialization, you can refer to it via the window.VueI18Next variable:

var $form = new Vue({ i18n: window.VueI18Next });

Fliplet().then(function () {
  // some other code
});

More docs on https://panter.github.io/vue-i18next/guide/component-interpolation.html

Date format

Powered by Moment.js, the number localization API can help you localize numbers to the language/regional preference.

JS API

Fliplet.Locale.date(value, options)
TD(value, options)

Handlebars helpers

{{ TD value [options] }}

Parameters

  • value {*} The date or time value to be used for formatting. The input type can be a Moment object, Date object or a string. Strings must be formatted as YYYY-MM-DD for dates and HH:mm (24-hour time) for times.
  • options {Object} A map of options
  • options.format {String} The formatting to be used. You can use one of the supported formats in the table below, e.g. LL for long form localized dates or LT for localized time without seconds, or one of the following options for relative time: fromNow, from, toNow and to.
  • options.from {*} (Optional) If options.format is from, use this parameter to set the reference date.
  • options.to {*} (Optional) If options.format is to, use this parameter to set the reference date.
  • options.locale {String} (Optional) Use a specific locale for the formatting. Default: device/browser language settings or en when that’s not found or valid.

Supported formats

Description Format Example
Time LT 8:30 PM
Time with seconds LTS 8:30:25 PM
Month numeral, day of month, year L 09/04/1986
  l 9/4/1986
Month name, day of month, year LL September 4, 1986
  ll Sep 4, 1986
Month name, day of month, year, time LLL September 4, 1986 8:30 PM
  lll Sep 4, 1986 8:30 PM
Month name, day of month, day of week, year, time LLLL Thursday, September 4, 1986 8:30 PM
  llll Thu, Sep 4, 1986 8:30 PM

Examples

Fliplet.Locale.date('2022-03-04', { format: 'LL' }) // 4 March 2022 (UK) 4 marzo 2022 (IT) or 4 mars 2022 (FR)
Fliplet.Locale.date('2022-03-04', { format: 'LL', locale: 'en-US' }) // March 4, 2022
Fliplet.Locale.date('14:23', { format: 'LT' }) // 14:23 (UK) 2:23 PM (US) 下午2點23分 (ZH-TW)
Fliplet.Locale.date('14:23', { format: 'LT', locale: 'en-US' }) // 2:23 PM

Handlebars.compile('{{ TD foo format="LL" }}')({ foo: '2022-03-04' }) // 4 March 2022 (UK) 4 marzo 2022 (IT) or 4 mars 2022 (FR)
Handlebars.compile('{{ TD foo format="LL" locale="en-US" }}')({ foo: '2022-03-04' }) // March 4, 2022
Handlebars.compile('{{ TD foo format="LT" }}')({ foo: '14:23' }) // 14:23 (UK) 2:23 PM (US) 下午2點23分 (ZH-TW)
Handlebars.compile('{{ TD foo format="LT" locale="en-US" }}')({ foo: '14:23' }) // 2:23 PM

// For US locale

Fliplet.Locale.date('2022-01-03', { format: 'fromNow' }) // 9 months ago as of October 2022
Fliplet.Locale.date('2022-01-03', { format: 'from', from: '2022-01-05' }) // 2 days ago

Handlebars.compile('{{ TD foo format="fromNow" }}')({ foo: '2022-01-03' }) // 9 months ago as of October 2022
Handlebars.compile('{{ TD foo format="from" from="2022-01-05" }}')({ foo: '2022-01-03' }) // 2 days ago

Number format

Powered by Intl.NumberFormat(), the number localization API can help you localize numbers to the language/regional preference.

JS API

Fliplet.Locale.number(value, options)
TN(value, options)

Handlebars helpers

{{ TN value [options] }}

Parameters

  • value {*} The value to be used for formatting. Numbers are preferred. Other types of input will be parsed to determine its numerical value.
  • options {Object} A map of options. See Intl.NumberFormat() documentation for the supported options.

Long decimal places: by default, numbers are localized and rendered with a minimum and maximum of 0–3 decimal places. This is due to the JavaScript's precision issues with floating points. If your data contains more decimal places, see documentation for Intl.NumberFormat() to learn how to display more decimal places.

Large numbers: if you have large numbers that you want to display, you may want to consider using the notation and compactDisplay parameters as supported by Intl.NumberFormat() to display large numbers. Also, numbers in JavaScript by default start to lose precision beyond positive or negative 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER) and cannot go beyond the value of Number.MAX_VALUE, which is around 10308 and would be displayed as "∞" where appropriate.

Examples

Fliplet.Locale.number(1234) // 1,234 (UK) 1.234 (IT) or 1 234 (FR)
Fliplet.Locale.number(1234, { locale: 'en-US' }) // 1,234
Fliplet.Locale.number(1234, { minimumFractionDigits: 2 }) // 1,234.00 (UK) 1.234,00 (IT) or 1 234,00 (FR)
Fliplet.Locale.number(1234, { minimumFractionDigits: 2, useGrouping: false }) // 1234.00 (UK) 1234,00 (IT) or 1234,00 (FR)
Fliplet.Locale.number(1234000000, { notation: 'compact', compactDisplay: 'long' }) // 1.2 billion (UK) 1,2 miliardi (IT) 1,2 milliard (FR)

Handlebars.compile('{{ TN foo }}')({ foo: 1234 }) // 1,234 (UK) 1.234 (IT) or 1 234 (FR)
Handlebars.compile('{{ TN foo locale="en-US" }}')({ foo: 1234 }) // 1,234
Handlebars.compile('{{ TN foo minimumFractionDigits=2 }}')({ foo: 1234 }) // 1,234.00 (UK) 1.234,00 (IT) or 1 234,00 (FR)
Handlebars.compile('{{ TN foo minimumFractionDigits=2 useGrouping=false }}')({ foo: 1234 }) // 1234.00 (UK) 1234,00 (IT) or 1234,00 (FR)
Handlebars.compile('{{ TN foo notation="compact" compactDisplay="long" }}')({ foo: 1234000000 }) // 1.2 billion (UK) 1,2 miliardi (IT) 1,2 milliard (FR)

Back to API documentation