##// END OF EJS Templates
i18n corrected default locale selection, more verbose error reporting
cin -
r55:dd0d589acfbb v1.0.8 default
parent child
Show More
@@ -1,82 +1,81
1 import { MapOf } from "@implab/core-amd/interfaces";
2 import { isPromise, mixin } from "@implab/core-amd/safe";
3 import { locale as sysLocale } from "dojo/_base/kernel";
1 import { MapOf, PromiseOrValue } from "@implab/core-amd/interfaces";
2 import { argumentNotEmptyString, isPromise, mixin } from "@implab/core-amd/safe";
4 3 import { id as mid } from "module";
5 4 import { TraceSource } from "@implab/core-amd/log/TraceSource";
6 5
7 6 const trace = TraceSource.get(mid);
8 7
9 type PromiseOrValue<T> = PromiseLike<T> | T;
8 export type LocaleProvider<T> = () => PromiseOrValue<T | { default: T }>;
9
10 10 type ResolveCallback<T> = () => PromiseOrValue<T>;
11 11
12 trace.debug("Current sysLocale: {0}", sysLocale);
13
14 12 function when<T, T2>(value: PromiseOrValue<T>, cb: (v: T) => PromiseOrValue<T2>): PromiseOrValue<T2> {
15 13 return isPromise(value) ?
16 14 value.then(cb) :
17 15 cb(value);
18 16 }
19 17
20 18 function isCallback<T>(v: ResolveCallback<T> | PromiseOrValue<T>): v is ResolveCallback<T> {
21 19 return typeof v === "function";
22 20 }
23 21
24 22 function defaultResolver(module: string) {
25 23 return import(module).then(x => x && x.default ? x.default : x);
26 24 }
27 25
28 26 function chainObjects<T extends object>(o1: T, o2: T) {
29 27 if (!o1)
30 28 return o2;
31 29 if (!o2)
32 30 return o1;
33 31
34 32 return mixin(Object.create(o1) as T, o2);
35 33 }
36 34
37 35 export class NlsBundle<T extends object> {
38 private _locales: MapOf<ResolveCallback<T> | PromiseOrValue<T>>;
36 private _locales: MapOf<LocaleProvider<Partial<T>>>;
39 37
40 38 private _default: T;
41 39
42 40 private _cache: MapOf<PromiseOrValue<T>>;
43 41
44 constructor(defNls: T, locales?: MapOf<any>) {
42 constructor(defNls: T, locales?: MapOf<LocaleProvider<Partial<T>>>) {
45 43 this._default = defNls;
46 44 this._locales = locales || {};
47 45 this._cache = {};
48 46 }
49 47
50 getLocale(locale?: string) {
51 const _loc = locale ?? sysLocale;
48 getLocale(locale: string) {
49 argumentNotEmptyString(locale, "locale");
50 const _loc = locale;
52 51
53 52 // en-US => ["en", "en-US"]
54 53 const locales = _loc.split(/-|_/).map((x, i, a) => a.slice(0, i + 1).join("-"));
55 54 return this._resolveLocale(locales);
56 55 }
57 56
58 57 _resolveLocale(locales: string[]): PromiseOrValue<T> {
59 58 if (!locales.length)
60 59 return this._default;
61 60
62 61 const locale = locales.pop();
63 62 if (!locale)
64 63 throw new Error("The locale can't be empty");
65 64
66 65 if (this._cache[locale])
67 66 return this._cache[locale];
68 67
69 68 const data = this._loadPackage(this._locales[locale]);
70 69 const parent = this._resolveLocale(locales);
71 70
72 71 return this._cache[locale] = when(data, x => {
73 72 return when(parent, y => this._cache[locale] = chainObjects(y, x));
74 73 });
75 74 }
76 75
77 76 _loadPackage(localeData: any) {
78 77 if (isCallback(localeData))
79 78 return when(localeData(), data => data && "default" in data ? data.default : data);
80 79 return localeData;
81 80 }
82 81 }
@@ -1,38 +1,51
1 import { id as mid} from "module";
1 2 import { MapOf } from "@implab/core-amd/interfaces";
2 3 import { NlsBundle } from "./NlsBundle";
3 4 import { isPromise } from "@implab/core-amd/safe";
5 import { locale as sysLocale } from "dojo/_base/kernel";
6 import { TraceSource } from "@implab/core-amd/log/TraceSource";
7
8 const trace = TraceSource.get(mid);
9
10 trace.debug("Current sysLocale: {0}", sysLocale);
4 11
5 12 export interface OnLoad {
6 13 (result?: any): void;
7 14 error(err: any): void;
8 15 }
9 16
10 17 export function bundle<T extends object>(nls: T, locales?: MapOf<any>) {
11 18 const nlsBundle = new NlsBundle(nls, locales);
12 19
13 const fn = (locale?: string) => {
20 const fn = (_locale?: string) => {
21 const locale = _locale || sysLocale;
14 22 const result = nlsBundle.getLocale(locale);
15 23
16 24 if (isPromise(result))
17 25 throw new Error(`The bundle '${locale}' isn't loaded`);
18 26 else
19 27 return result;
20 28 };
21 29
22 30 fn.define = (pack: Partial<T>) => pack;
23 31 fn.load = async (id: string, require: Require, cb: OnLoad, config: any) => {
32 const locale = id || sysLocale;
24 33 if (config && config.isBuild) {
25 34 cb();
26 35 } else {
27 36 try {
28 await nlsBundle.getLocale(id);
37 await nlsBundle.getLocale(locale);
29 38 cb();
30 39 } catch (e) {
31 if(cb.error)
40 if(cb.error) {
32 41 cb.error(e);
42 } else {
43 // in case the loader doesn't support error reporting
44 trace.error("Error loading {0}: {1}", locale, e);
45 }
33 46 }
34 47 }
35 48 };
36 49
37 50 return fn;
38 51 }
@@ -1,8 +1,9
1 1 import { bundle } from "../i18n";
2 2
3 3 export default bundle({
4 4 greeting: (name: string) => `Hello, ${name}!`,
5 5 goodbye: (name: string) => `Bye, ${name}!`
6 6 }, {
7 7 ru: () => import("./ru/foo")
8 8 });
9
General Comments 0
You need to be logged in to leave comments. Login now