i18n-js
Version:
A small library to provide I18n on JavaScript.
149 lines (129 loc) • 3.74 kB
text/typescript
import uniq from "lodash/uniq";
import { Dict, LocaleResolver } from "./typing";
import { I18n } from "./I18n";
/**
* The default locale resolver.
*
* This resolver will add `options.locale` if provided (this function receives
* it inlined). In case nothing is set, then `i18n.locale` will be used.
* Additionally, adds the default locale to the list if `i18n.enableFallback` is
* set.
*
* Every locale added to the list will then be split apart; if `pt-BR` is the
* locale, then the list will be returned as `["pt-BR", "pt"]`.
*
* The default in case nothing is defined is `["en"]`.
*
* @type {LocaleResolver}
*
* @param {I18n} i18n The I18n instance.
*
* @param {string} locale The locale that being analysed.
*
* @returns {string[]} The resolved locales.
*/
export const defaultLocaleResolver: LocaleResolver = (
i18n: I18n,
locale: string,
): string[] => {
const locales = [];
const list: string[] = [];
// Handle the inline locale option that can be provided to
// the `I18n.t` options.
locales.push(locale);
// Add the current locale to the list.
if (!locale) {
locales.push(i18n.locale);
}
// Add the default locale if fallback strategy is enabled.
if (i18n.enableFallback) {
locales.push(i18n.defaultLocale);
}
// Compute each locale with its country code.
// So this will return an array containing both
// `de-DE` and `de` locales.
//
// We also need to support locales with region code (e.g. zh-Hant-TW).
// In that case, the list should be `["zh-hant-tw", "zh-hant", "zh"]`.
locales
.filter(Boolean)
.map((entry) => entry.toString())
.forEach(function (currentLocale: string) {
if (!list.includes(currentLocale)) {
list.push(currentLocale);
}
if (!i18n.enableFallback) {
return;
}
const codes = currentLocale.split("-");
if (codes.length === 3) {
list.push(`${codes[0]}-${codes[1]}`);
}
list.push(codes[0]);
});
return uniq(list);
};
export class Locales {
private i18n: I18n;
private registry: Dict;
constructor(i18n: I18n) {
this.i18n = i18n;
this.registry = {};
this.register("default", defaultLocaleResolver);
}
/**
* You can define custom rules for any locale. Just make sure you return an
* array containing all locales.
*
* ```js
* // Default the Wookie locale to English.
* i18n.locales.register("wk", (_i18n, locale) => {
* return ["en"];
* });
* ```
*
* @param {string} locale The locale's name.
*
* @param {LocaleResolver|string|string[]} localeResolver The locale resolver
* strategy.
*
* @returns {void}
*/
public register(
locale: string,
localeResolver: LocaleResolver | string | string[],
): void {
if (typeof localeResolver !== "function") {
const result = localeResolver;
localeResolver = (() => result) as LocaleResolver;
}
this.registry[locale] = localeResolver;
}
/**
* Return a list of all locales that must be tried before returning the
* missing translation message. By default, this will consider the inline
* option, current locale and fallback locale.
*
* ```js
* i18n.locales.get("de-DE");
* // ["de-DE", "de", "en"]
* ```
*
* @param {string} locale The locale query.
*
* @returns {string[]} The list of locales.
*/
public get(locale: string): string[] {
let locales =
this.registry[locale] ||
this.registry[this.i18n.locale] ||
this.registry.default;
if (typeof locales === "function") {
locales = locales(this.i18n, locale);
}
if (!(locales instanceof Array)) {
locales = [locales];
}
return locales;
}
}