diff --git a/readme.md b/readme.md --- a/readme.md +++ b/readme.md @@ -60,26 +60,26 @@ export class MyWidget extends djbase( ## DESCRIPTION -This package provides you with tools to glue your good-fellow dojo with modern -techniques of building the webapp. The core concept is built around widgets and -using .tsx to write it. Here some features: +This package provides you with the tools to glue your good-fellow dojo with modern +techniques of building the webapp. The core concept is to built around widgets and +using .tsx to write it. Here are some features: * `djbase()`, `@djaclass` - traits to declare your classes with `dojo/_base/declare` * `@implab/djx/tsx` - traits to build the rendering of your widgets with tsx * `DjxWidgetBase` - abstract class which supports tsx markup and `data-dojo-attach-*` attributes. -* `@bind(...)` - annotations provides an easy way of using standard dojo widget +* `@bind(...)` - annotations provide an easy way of using standard dojo widget attribute bindings. ### djbase, @djclass -These two traits provides convenient way of using `dojo/_base/declare` in Typescript +These two traits provide convenient way of using `dojo/_base/declare` in Typescript for declaring your classes. `djbase(...constructors)` - this method accepts a list of constructors in its parameters and returns the **fake** base type which then can be used to derive your own class. This allows you to provide the Typescript with the correct -information about the base type and even use `super`!. The only one caveat of +information about the base type and even use `super`!. The only caveat of this approach is that you **MUST** decorate your class with `@djclass` annotation. Consider the following example: @@ -150,11 +150,11 @@ you will get the following output: <- Baz ``` -Let's take a closer look to the `Baz` declaration it uses `djbase` to derive +Let's take a closer look at the `Baz` declaration it uses `djbase` to derive from three mixins and the class is decorated with `@djclass` to accomplish the declaration and make a real constructor. -To allow an access to the next sibling method (in terms of multiple inheritance) +To allow access to the next sibling method (in terms of multiple inheritance) Dojo provides `this.inherited(arguments)` method but this approach leads to the problem with 'strict' mode of ES5 and eliminates the type information about a calling method. This library solves the problem calling inherited/next method by @@ -162,9 +162,9 @@ utilizing `super` keyword. Under the hoo the prototype of the declared class which make calls to `this.inherited(...)` method. This technique is compatible with 'strict' mode. -Mixins are declared the similar, they are also may have the base types although +Mixins are declared similar, they also may have the base types although the most common case is declaring the mixin without any base classes. To allow -the mixin to access the next method you should declare the interface with +the mixin to access the next method declare the interface with desired methods and use the special form of `djbase()` without arguments. ### DjxWidgetBase diff --git a/src/main/ts/NlsBundle.ts b/src/main/ts/NlsBundle.ts --- a/src/main/ts/NlsBundle.ts +++ b/src/main/ts/NlsBundle.ts @@ -21,6 +21,10 @@ function isCallback(v: ResolveCallbac return typeof v === "function"; } +function defaultResolver(module: string) { + return import(module).then(x => x && x.default ? x.default : x); +} + function chainObjects(o1: T, o2: T) { if (!o1) return o2; @@ -31,51 +35,48 @@ function chainObjects( } export class NlsBundle { - _locales: MapOf | PromiseOrValue>; - default: T; + private _locales: MapOf | PromiseOrValue>; - _cache: MapOf>; + private _default: T; + + private _cache: MapOf>; constructor(defNls: T, locales?: MapOf) { - this.default = defNls; + this._default = defNls; this._locales = locales || {}; this._cache = {}; } - getLocale(locale: string) { - const _loc = locale || sysLocale; - - const locales = new Array(); + getLocale(locale?: string) { + const _loc = locale ?? sysLocale; - _loc.split("-").reduce((a, x) => { - a.push(x); - locales.unshift(a.join("-")); - return a; - }, new Array()); - + // 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; + return this._default; - const locale = locales.shift(); - + const locale = locales.pop(); if (!locale) - return this._resolveLocale(locales); + throw new Error("The locale can't be empty"); if (this._cache[locale]) return this._cache[locale]; - let data = this._locales[locale]; - if (isCallback(data)) - data = data(); - + 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; + } } diff --git a/src/main/ts/css.ts b/src/main/ts/css.ts --- a/src/main/ts/css.ts +++ b/src/main/ts/css.ts @@ -7,7 +7,7 @@ interface OnLoad { const plugin = { load: (id: string, require: Require, cb: OnLoad, config: { isBuild?: boolean }) => { - if (config.isBuild) { + if (config && config.isBuild) { cb(); } else { const url = require.toUrl(id); diff --git a/src/main/ts/i18n.ts b/src/main/ts/i18n.ts --- a/src/main/ts/i18n.ts +++ b/src/main/ts/i18n.ts @@ -11,7 +11,7 @@ export function bundle const nlsBundle = new NlsBundle(nls, locales); const fn = (locale?: string) => { - const result = locale ? nlsBundle.getLocale(locale) : nlsBundle.default; + const result = nlsBundle.getLocale(locale); if (isPromise(result)) throw new Error(`The bundle '${locale}' isn't loaded`); @@ -20,7 +20,6 @@ export function bundle }; fn.define = (pack: Partial) => pack; - fn.default = nlsBundle.default; fn.load = async (id: string, require: Require, cb: OnLoad, config: any) => { if (config && config.isBuild) { cb(); @@ -29,7 +28,8 @@ export function bundle await nlsBundle.getLocale(id); cb(); } catch (e) { - cb.error(e); + if(cb.error) + cb.error(e); } } }; diff --git a/src/test/ts/i18n/foo.ts b/src/test/ts/i18n/foo.ts new file mode 100644 --- /dev/null +++ b/src/test/ts/i18n/foo.ts @@ -0,0 +1,8 @@ +import { bundle } from "../i18n"; + +export default bundle({ + greeting: (name: string) => `Hello, ${name}!`, + goodbye: (name: string) => `Bye, ${name}!` +}, { + ru: () => import("./ru/foo") +}); diff --git a/src/test/ts/i18n/ru/foo.ts b/src/test/ts/i18n/ru/foo.ts new file mode 100644 --- /dev/null +++ b/src/test/ts/i18n/ru/foo.ts @@ -0,0 +1,6 @@ +import foo from "../foo"; + +export default foo.define({ + greeting: (name: string) => `Привет, ${name}`, + goodbye: (name: string) => `Пока, ${name}` +}); diff --git a/src/test/ts/i18nTests.ts b/src/test/ts/i18nTests.ts new file mode 100644