import { MapOf, PromiseOrValue } from "@implab/core-amd/interfaces"; import { argumentNotEmptyString, isPromise, mixin } from "@implab/core-amd/safe"; export type LocaleProvider = () => PromiseOrValue; function when(value: PromiseOrValue, cb: (v: T) => PromiseOrValue): PromiseOrValue { return isPromise(value) ? value.then(cb) : cb(value); } const loadPackage = (localeData: LocaleProvider> | undefined) => localeData ? when(localeData(), data => data && "default" in data ? data.default : data) : undefined; const chainObjects = (o1: T, o2: Partial | undefined): T => o2 ? mixin(Object.create(o1) as T, o2) : o1; export class NlsBundle { private readonly _locales: MapOf>>; private readonly _default: T; private _cache: MapOf>; constructor(defNls: T, locales?: MapOf>>) { this._default = defNls; this._locales = locales || {}; this._cache = {}; } getLocale(locale: string) { argumentNotEmptyString(locale, "locale"); const _loc = locale; // en-US => ["en", "en-US"] const locales = _loc.split(/-|_/).map((x, i, a) => a.slice(0, i + 1).join("-")); return this._resolveLocale(locales); } _resolveLocale(locales: string[]): PromiseOrValue { if (!locales.length) return this._default; const locale = locales.pop(); if (!locale) throw new Error("The locale can't be empty"); if (this._cache[locale]) return this._cache[locale]; const data = loadPackage(this._locales[locale]); const parent = this._resolveLocale(locales); return this._cache[locale] = when(data, x => { return when(parent, y => this._cache[locale] = chainObjects(y, x)); }); } }