|  |  | import { MapOf, PromiseOrValue } from "@implab/core-amd/interfaces"; | 
                        
    
    
        |  |  | import { argumentNotEmptyString, isPromise, mixin } from "@implab/core-amd/safe"; | 
                        
    
    
        |  |  | import { id as mid } from "module"; | 
                        
    
    
        |  |  | import { TraceSource } from "@implab/core-amd/log/TraceSource"; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | const trace = TraceSource.get(mid); | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | export type LocaleProvider<T> = () => PromiseOrValue<T | { default: T }>; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | type ResolveCallback<T> = () => PromiseOrValue<T>; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | function when<T, T2>(value: PromiseOrValue<T>, cb: (v: T) => PromiseOrValue<T2>): PromiseOrValue<T2> { | 
                        
    
    
        |  |  | return isPromise(value) ? | 
                        
    
    
        |  |  | value.then(cb) : | 
                        
    
    
        |  |  | cb(value); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | function isCallback<T>(v: ResolveCallback<T> | PromiseOrValue<T>): v is ResolveCallback<T> { | 
                        
    
    
        |  |  | return typeof v === "function"; | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | function defaultResolver(module: string) { | 
                        
    
    
        |  |  | return import(module).then(x => x && x.default ? x.default : x); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | function chainObjects<T extends object>(o1: T, o2: T) { | 
                        
    
    
        |  |  | if (!o1) | 
                        
    
    
        |  |  | return o2; | 
                        
    
    
        |  |  | if (!o2) | 
                        
    
    
        |  |  | return o1; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | return mixin(Object.create(o1) as T, o2); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | export class NlsBundle<T extends object> { | 
                        
    
    
        |  |  | private _locales: MapOf<LocaleProvider<Partial<T>>>; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | private _default: T; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | private _cache: MapOf<PromiseOrValue<T>>; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | constructor(defNls: T, locales?: MapOf<LocaleProvider<Partial<T>>>) { | 
                        
    
    
        |  |  | 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<T> { | 
                        
    
    
        |  |  | 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 = this._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)); | 
                        
    
    
        |  |  | }); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | _loadPackage(localeData: any) { | 
                        
    
    
        |  |  | if (isCallback(localeData)) | 
                        
    
    
        |  |  | return when(localeData(), data => data && "default" in data ? data.default : data); | 
                        
    
    
        |  |  | return localeData; | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  |