i18n helper

The i18n package that uses the i18nHelper to expose an API to manage the internationalization of the application implemented by the @orion/i18n module.

It exposes a wrapper around i18next library.

Important: Don't use i18next library directly, you may have undesired side-effects in the application.

The framework is currently using the json-v3 syntax.

To store the translations in your plugin, you should create the following folder structure:

Essentials

Dates

The popular moment.js library is exposed by the framework. Use it to deal with dates.

Copy
import moment from 'moment';
const myFormattedDate = moment().format('DD MM YYYY');

Numbers

Javascript has a native API which is very complete. Use it to deal with numbers.

Copy
i18nHelper.formatNumber(123456.789, { style: 'currency', currency: 'EUR' });

// or

new Intl.NumberFormat(i18nHelper.getLanguage(), {
  style: 'currency',
  currency: 'EUR',
}).format(123456.789);

Overriding the namespace

By default the plugins will get the translations that themselves have exposed, but now we allow to override the default namespace and load the translations from other plugins while using this functions:

  • getI18nComponent

  • getNamespace

  • useTranslations

  • withTranslation

  • t

  • exists

  • loadNamespace

  • onLoaded

  • onFailedLoading

  • onMissingKey

  • onAdded

  • onRemoved

Let's suppose that we have two plugins plugin-translations-first and plugin-translations-second, each of them expose their own set of translations:

  • plugin-translations-first

    Copy
    File: en.json
    {
        "Hello": "Hi"
    }
  • plugin-translations-second

    Copy
    File: en.json
    {
      "Hello": "Hello World"
    }

So, if from the first plugin, we use the t function it would result like this:

Copy
const translatedValue = plugin.i18nHelper.t('hello', {});
console.log(translatedValue); // Logs "Hi"

But we now offer the option to load the translations from another plugin, so we are able to do the following:

Copy
const translatedValue = plugin.i18nHelper.t('hello', {}, 'plugin-translations-second');
console.log(translatedValue); // Logs "Hello World"

getI18nComponent

Gets the i18nComponent from an specified namespace (the current plugin by default).

Usage
Copy
getI18nComponent(overrideNamespace: String?): Component
  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • Component

    The Component.

getNamespace

Gets the namespace of the plugin.

Usage
Copy
getNamespace(pluginName: String?): String
  • pluginName? String

    The name of the plugin that added the translations that we want to use.

Returns
  • String

    The namespace.

useTranslation

We have ported i18next useTranslation hook to the framework. It does not supports useSuspense yet, as it is yet experimental in react, but we can use it. Just look this piece of example from the devkit.

Usage
Copy
useTranslation(): Object
Returns
  • Object

    An object with the translations properties.

    • t() Function

      Method to retrieve the translation.

    • ready Boolean

      Flag to check if the translation is loaded.

Example
Copy
import React from 'react';
import { useHooks } from './HooksContext';

export function TranslationsHooksUseTranslation() {
  const { useTranslation } = useHooks();
  const { t, ready } = useTranslation();

  if (!ready) return <div>Loading translations...</div>;

  return (
    <div>
      <div>{t('one')}</div>
      <div>{t('two')}</div>
      <div>{t('three')}</div>
    </div>
  );
}

withTranslation

Retrieves a function (HOC) which translates a Component.

The withTranslation hoc is responsible to pass the t function to your component which enables all the translation functionality.

About HOCs.

Usage
Copy
withTranslation(options: Object?, overrideNamespace: String?): Function
  • options? Object

    Available options

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • Function

    The Component translator

Example
Copy
const Hello = ({ t }) => <span>t('hello')</span>;
i18nHelper.withTranslation()(Hello);
Copy
const Hello = ({ t }) => <span>t('hello')</span>;

// Wait until translations are loaded to render the component
i18nHelper.withTranslation({ wait: true })(Hello);
Copy
// Translate from Component file:

// Hello.jsx
import react from 'react';

const Hello = ({ t }) => <span>t('hello')</span>;
const makeTranslatedHello = ({ i18nHelper }) => i18nHelper.withTranslation()(Hello);

export { makeTranslatedHello as default, Hello };
Copy
// Translate when putting the component from the Plugin:

// POSWebPluginHello.js
import makeHello from './components/makeHello';

export default class POSWebPluginHello implements Plugin {
  constructor({ diHelper }) {
    this._diHelper = diHelper;

    diHelper.useFactories({
      Hello: makeHello,
    });
  }

  onInit() {
    this._diHelper.invoke(this._putComponents);
  }

  _putComponents = ({ uiHelper, i18nHelper, Hello }) => {
    uiHelper.putComponent('Hello', i18nHelper.withTranslation({ wait: true })(Hello));
  };
}

i18nComponent

The i18n component passes t function to child function and triggers loading the translation files needed. Further it asserts the component gets rerendered on language change or changes to the translations themselves.

Example
Copy
<I18nComponent>
  {(t, { i18n, t, ready }) => (
    <div>
      <h1>{t('key')}</h1>
      <p>
        {t('anotherKey', {
          /* options t options */
        })}
      </p>
    </div>
  )}
</I18nComponent>

t

Translates the specified key/s, returning its value translated.

You can specify either one key as a String or multiple keys as an Array of String. The first one that resolves will be returned.

Please have a look at the translation functions like interpolation, formatting and plurals for more details on using it.

Usage
Copy
t(keys: String | [String], options?: Object, overrideNamespace: String?): String
  • keys String | [String]

    The key or multiple keys. The first one that resolves will be returned.

  • options? Object

    The options for the translation functions like interpolation, formatting and plurals.

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • String

    The translated value.

Example
Copy
const value = i18nHelper.t('key');

Using fallbacks:

Copy
const value = i18nHelper.t(['unknown.key', 'my.key']);

Note: Maybe, when you try to translate a key, if the resource is not loaded you will not get the desired value. For that reason you have two options here: ensure yourself to have the resource loaded or send an option to make the translation asynchronous.

Translate asynchronously:

Copy
async () => {
  try {
    const value = await i18nHelper.t('key', { wait: true });
  } catch (err) {
    // Handle error
  }
};

Ensure resource is loaded:

Copy
async () => {
  if (!i18nHelper.exists('key')) {
    await i18nHelper.loadNamespace();
  }

  i18nHelper.t('key');
};

formatNumber

Formats a number based on language.

Usage
Copy
formatNumber(number: (Number | String), options: Object, lng: String): Number
  • number Number | String

    Number to format.

  • options Object

    Intl.NumberFormat

  • lng? String

    Language is optional. By default, it uses the current language.

Returns
  • Number

    The formated number.

exists

Checks if a translation key exists.

Usage
Copy
exist(key: String, options: Object?, overrideNamespace: String?): Boolean
  • key String

    The key to check.

  • options Object

    Options to be sent

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • Boolean

    Returns true if a key exists.

changeLanguage

Changes the language. The callback will be called as soon translations were loaded or an error occurs while loading. More info

Usage
Copy
changeLanguage(lng: string, callback?: Function): void
  • lng String

    The language to change to.

  • callback? Function

    The callback called as soon translations were loaded or an error occurs while loading.

Example

Promise way:

Copy
async () => {
  try {
    const t = await i18next.changeLanguage('es');
    // resources have been loaded
  } catch (err) {
    // resources could not be loaded
  }
};

Callback way:

Copy
i18next.changeLanguage('es', (err, t) => {
  if (!err) {
    // resources have been loaded
  } else {
    // resources could not be loaded
  }
});

loadNamespace

Loads the plugin namespace. This means that it loads the translation resources needed by the plugin if they were not loaded previously.

Usage
Copy
loadNamespace(callback?: Function, overrideNamespace: String?): void
  • callback? Function

    The callback called as soon namespace was loaded or an error occurs while loading.

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Example

Promise way:

Copy
async () => {
  try {
    await i18next.loadNamespace();
    // resources have been loaded
  } catch (err) {
    // resources could not be loaded
  }
};

Callback way:

Copy
i18next.loadNamespace((err) => {
  if (!err) {
    // resources have been loaded
  } else {
    // resources could not be loaded
  }
});

loadLanguages

Loads additional languages not defined in init options (preload). More info

Usage
Copy
loadLanguages(lngs: (String | Array<String>), callback?: Function): void
  • lngs String

    Language/s to load.

  • callback? Function

    The callback called as soon translations were loaded or an error occurs while loading.

Example

Promise way:

Copy
async () => {
  try {
    await i18next.loadLanguages('es');
    // resources have been loaded
  } catch (err) {
    // resources could not be loaded
  }
};
Copy
async () => {
  try {
    await i18next.loadLanguages(['de', 'fr', 'es']);
    // resources have been loaded
  } catch (err) {
    // resources could not be loaded
  }
};

Callback way:

Copy
i18next.loadLanguages('es', (err) => {
  if (!err) {
    // resources have been loaded
  } else {
    // resources could not be loaded
  }
});
Copy
i18next.loadLanguages(['de', 'fr', 'es'], (err) => {
  if (!err) {
    // resources have been loaded
  } else {
    // resources could not be loaded
  }
});

getLanguage

Is set to the current detected or set language.

If you need the primary used language depending on your configuration (whilelist, load) you will prefer using i18next.languages[0]. More info

Usage
Copy
getLanguage(): string
Returns
  • String

    The current language.

getLanguages

Is set to an array of language-codes that will be used it order to lookup the translation value. More info

Usage
Copy
getLanguages(): Array<String>
Returns
  • Array<String>

    An array of languages loaded.

dir

Returns rtl or ltr depending on languages read direction. More info

Usage
Copy
dir(lng?: String): ("rtl" | "ltr")
  • lng? String

    The language to retrieve its direction.

Returns
  • "rtl" | "ltr"

    The language direction.

Example
Copy
// for current language
i18next.dir();
Copy
// for another language
i18next.dir('en-US'); // -> "ltr";
i18next.dir('ar'); // -> "rtl";

onInitialized

Gets fired after initialization. More info

Usage
Copy
onInitialized(callback: Function, only?: Boolean): Function
  • callback Function

    (options: Object) => void

  • only? Boolean

    true if the purpose of the handler is only to listen to the event invoked by the plugin.

Returns
  • Function

    A function to unregister the handler registered by the method.

onLoaded

Gets fired on loaded resources. More info

Usage
Copy
onLoaded(callback: Function, only?: Boolean, overrideNamespace: String?): Function
  • callback Function

    (loaded: boolean) => void

  • only? Boolean

    true if the purpose of the handler is only to listen to the event invoked by the plugin.

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • Function

    A function to unregister the handler registered by the method.

onFailedLoading

Gets fired if loading resources failed. More info

Usage
Copy
onFailedLoading(callback: Function, only?: Boolean, overrideNamespace: String?): Function
  • callback Function

    (lng: string, ns: string, msg: string) => void

  • only? Boolean

    true if the purpose of the handler is only to listen to the event invoked by the plugin.

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • Function

    A function to unregister the handler registered by the method.

onMissingKey

Gets fired on accessing a key not existing. More info

Usage
Copy
onMissingKey(callback: Function, only?: Boolean, overrideNamespace: String?): Function
  • callback Function

    (lngs: Array , namespace: string, key: string, res: string) => void

  • only? Boolean

    true if the purpose of the handler is only to listen to the event invoked by the plugin.

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • Function

    A function to unregister the handler registered by the method.

onAdded

Gets fired when resources got added. More info

Usage
Copy
onAdded(callback: Function, only?: Boolean, overrideNamespace: String?): Function
  • callback Function

    (lng: string, ns: string) => void

  • only? Boolean

    true if the purpose of the handler is only to listen to the event invoked by the plugin.

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • Function

    A function to unregister the handler registered by the method.

onRemoved

Gets fired when resources got removed. More info

Usage
Copy
onRemoved(callback: Function, only?: Boolean, overrideNamespace: String?): Function
  • callback Function

    (lng: string, ns: string) => void

  • only? Boolean

    true if the purpose of the handler is only to listen to the event invoked by the plugin.

  • overrideNamespace? String

    The new namespace that will be used (instead of the one of the current plugin).

Returns
  • Function

    A function to unregister the handler registered by the method.

onLanguageChanged

Gets fired when changeLanguage got called. More info

Usage
Copy
onLanguageChanged(callback: Function): void
  • callback Function

    (lng: string) => void