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.
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.
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
CopyFile: en.json
{
"Hello": "Hi"
} -
plugin-translations-second
CopyFile: en.json
{
"Hello": "Hello World"
}
So, if from the first plugin, we use the t function it would result like this:
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:
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
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
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
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
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
withTranslation(options: Object?, overrideNamespace: String?): Function
-
options? Object
-
overrideNamespace? String
The new namespace that will be used (instead of the one of the current plugin).
Returns
-
Function
The Component translator
Example
const Hello = ({ t }) => <span>t('hello')</span>;
i18nHelper.withTranslation()(Hello);
const Hello = ({ t }) => <span>t('hello')</span>;
// Wait until translations are loaded to render the component
i18nHelper.withTranslation({ wait: true })(Hello);
// 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 };
// 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
<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
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
const value = i18nHelper.t('key');
Using fallbacks:
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:
async () => {
try {
const value = await i18nHelper.t('key', { wait: true });
} catch (err) {
// Handle error
}
};
Ensure resource is loaded:
async () => {
if (!i18nHelper.exists('key')) {
await i18nHelper.loadNamespace();
}
i18nHelper.t('key');
};
formatNumber
Formats a number based on language.
Usage
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
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
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:
async () => {
try {
const t = await i18next.changeLanguage('es');
// resources have been loaded
} catch (err) {
// resources could not be loaded
}
};
Callback way:
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
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:
async () => {
try {
await i18next.loadNamespace();
// resources have been loaded
} catch (err) {
// resources could not be loaded
}
};
Callback way:
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
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:
async () => {
try {
await i18next.loadLanguages('es');
// resources have been loaded
} catch (err) {
// resources could not be loaded
}
};
async () => {
try {
await i18next.loadLanguages(['de', 'fr', 'es']);
// resources have been loaded
} catch (err) {
// resources could not be loaded
}
};
Callback way:
i18next.loadLanguages('es', (err) => {
if (!err) {
// resources have been loaded
} else {
// resources could not be loaded
}
});
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
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
getLanguages(): Array<String>
Returns
-
Array<String>
An array of languages loaded.
dir
Returns rtl or ltr depending on languages read direction. More info
Usage
dir(lng?: String): ("rtl" | "ltr")
-
lng? String
The language to retrieve its direction.
Returns
-
"rtl" | "ltr"
The language direction.
Example
// for current language
i18next.dir();
// for another language
i18next.dir('en-US'); // -> "ltr";
i18next.dir('ar'); // -> "rtl";
onInitialized
Gets fired after initialization. More info
Usage
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
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
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
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
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
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
onLanguageChanged(callback: Function): void
-
callback Function
(lng: string) => void