From 88db8cb6868512df210e39431274a7e20466cd71 Mon Sep 17 00:00:00 2001 From: wxzhang Date: Sun, 9 Apr 2023 14:49:57 +0800 Subject: [PATCH] update for typescript --- packages/runtime/src/__tests__/index.test.ts | 116 ++++++++++++---- packages/runtime/src/formatterRegistry.ts | 54 ++++---- packages/runtime/src/formatters/index.ts | 6 +- packages/runtime/src/interpolate.ts | 10 +- packages/runtime/src/manager.ts | 3 +- packages/runtime/src/scope.ts | 132 ++++++++++--------- packages/runtime/src/translate.ts | 4 +- 7 files changed, 206 insertions(+), 119 deletions(-) diff --git a/packages/runtime/src/__tests__/index.test.ts b/packages/runtime/src/__tests__/index.test.ts index e16680e..2ed102c 100644 --- a/packages/runtime/src/__tests__/index.test.ts +++ b/packages/runtime/src/__tests__/index.test.ts @@ -6,13 +6,21 @@ import zhFormatters from '../formatters/zh'; import enFormatters from '../formatters/en'; import { VoerkaI18nManager } from '../manager'; import { VoerkaI18nFormatterRegistry } from '../formatterRegistry'; -import { VoerkaI18nLanguageMessages } from '../types'; - +import { VoerkaI18nLanguageMessages, VoerkaI18nFormatterConfigs } from '../types'; +import { deepMerge } from 'flex-tools/object/deepMerge'; +import { isPlainObject } from 'flex-tools/typecheck/isPlainObject'; +import { default as inlineFormatters } from '../formatters'; +function mergeFormattersConfigs(configSources:any[]){ + return configSources.reduce((finalConfig, curConfig)=>{ + if(isPlainObject(curConfig)) deepMerge(finalConfig,curConfig,{newObject:false,array:'replace'}) + return finalConfig + },{}) +} const zhMessages:VoerkaI18nLanguageMessages = { $config:{ - x:{a:1}, - y:{b:1} + add:{a:1}, + dec:{b:1} }, "1": "你好", "2": "你好,{name}", @@ -42,19 +50,51 @@ const languages = [ { name: "en"} ] +Object.assign(zhFormatters.$config,{ + x:{x1:1,x2:2}, + y:{y1:1,y2:2} +}) +Object.assign(enFormatters.$config,{ + x:{x1:11,x2:22}, + y:{y1:11,y2:22}, + z:{z1:11,z2:22} +}) + const formatters ={ - zh:zhFormatters, - en:enFormatters, + "*":{ + $config:{ + x:{g:1}, + y:{g:1}, + g:{g1:1,g2:2} + }, + add:(value:any,args?:any[],$config?:VoerkaI18nFormatterConfigs)=>'*'+ value+1, + }, + zh:{ + first:(value:any)=>'ZH'+value[0], + ...zhFormatters + }, + en:{ + first:(value:any)=>'EN'+value[0], + ...enFormatters, + }, jp:()=>{} } -describe("VoerkaI18nScope", () => { - let scope = new VoerkaI18nScope({ - id: "test", - languages, - idMap, - messages, - formatters +describe("VoerkaI18nScope", () => { + let scope:VoerkaI18nScope; + beforeAll(async ()=>{ + return new Promise((resolve)=>{ + scope = new VoerkaI18nScope({ + id: "test", + languages, + idMap, + messages, + formatters, + callback:()=>{ + resolve() + } + }) + }) }) test("成功创建实例", () => { expect(scope).toBeInstanceOf(VoerkaI18nScope) @@ -63,20 +103,50 @@ describe("VoerkaI18nScope", () => { expect(scope.messages).toEqual(messages) expect(scope.default).toEqual(zhMessages) expect(scope.current).toEqual(zhMessages) - expect(scope.idMap).toEqual(idMap) - // 格式化器配置 - expect(scope.formatters).toBeInstanceOf(VoerkaI18nFormatterRegistry) - expect(scope.formatters.language).toBe("zh") - expect(scope.formatters.formatters).toEqual(formatters) - expect(scope.formatters.config).toBe(zhFormatters.$config) - expect(scope.formatters.types).toBe(zhFormatters.$types) - - + expect(scope.idMap).toEqual(idMap) // 全局管理器 expect(scope.global).toBeInstanceOf(VoerkaI18nManager) }) - + test("格式化器配置", async () => { + expect(scope.formatters).toBeInstanceOf(VoerkaI18nFormatterRegistry) + expect(scope.formatters.activeLanguage).toBe("zh") + expect(scope.formatters.formatters).toEqual(formatters) + expect(scope.formatters.config).toBe(zhFormatters.$config) + expect(scope.formatters.types).toBe(zhFormatters.$types) + }) + test("查找格式化器", async () => { + expect(scope.formatters.get("add")).toBe(formatters['*'].add) + expect(scope.formatters.get("first")).toBe(formatters.zh.first) + await scope.change("en") + expect(scope.formatters.get("first")).toBe(formatters.en.first) + }) + test("格式化器配置", async () => { + let fallbackLanguage = scope.getLanguage(scope.activeLanguage)?.fallback + const globalFormatters = inlineFormatters + let scopeConfig = mergeFormattersConfigs([ + globalFormatters['*'].$config, + (fallbackLanguage! in globalFormatters) ? (globalFormatters as any)?.[fallbackLanguage!].$config:{}, + globalFormatters.zh.$config, + formatters['*'].$config, + (fallbackLanguage! in formatters) ? (formatters as any)?.[fallbackLanguage!]?.$config:{}, + formatters.zh.$config + ]) + expect(scope.formatters.config).toEqual(scopeConfig) + // + await scope.change("en") + fallbackLanguage = scope.getLanguage(scope.activeLanguage)?.fallback + scopeConfig = mergeFormattersConfigs([ + globalFormatters['*'].$config, + (fallbackLanguage! in globalFormatters) ? (globalFormatters as any)?.[fallbackLanguage!].$config:{}, + // globalFormatters.zh.$config, + formatters['*'].$config, + (fallbackLanguage! in formatters) ? (formatters as any)?.[fallbackLanguage!]?.$config:{}, + formatters.en.$config + ]) + expect(scope.formatters.config).toEqual(scopeConfig) + + }) }) test('translate', () => {}) diff --git a/packages/runtime/src/formatterRegistry.ts b/packages/runtime/src/formatterRegistry.ts index a7e9f35..8d46053 100644 --- a/packages/runtime/src/formatterRegistry.ts +++ b/packages/runtime/src/formatterRegistry.ts @@ -6,13 +6,19 @@ */ import { isPlainObject } from 'flex-tools/typecheck/isPlainObject'; import type { VoerkaI18nScope } from './scope'; -import { VoerkaI18nFormatter, VoerkaI18nFormatters, VoerkaI18nFormattersLoader, VoerkaI18nLanguageFormatters, SupportedDateTypes, VoerkaI18nFormatterConfigs, VoerkaI18nTypesFormatters } from './types'; import { DataTypes } from './utils'; import { get as getByPath } from "flex-tools/object/get" import { isFunction } from 'flex-tools/typecheck/isFunction'; import { deepMerge } from 'flex-tools/object/deepMerge'; import { assignObject } from 'flex-tools/object/assignObject'; - +import { VoerkaI18nFormatter, + VoerkaI18nFormatters, + VoerkaI18nFormattersLoader, + VoerkaI18nLanguageFormatters, + SupportedDateTypes, + VoerkaI18nFormatterConfigs, + VoerkaI18nTypesFormatters +} from './types'; export interface VoerkaI18nScopeCache{ activeLanguage :string | null, @@ -46,14 +52,15 @@ export class VoerkaI18nFormatterRegistry{ #activeFormatters:VoerkaI18nFormatters = {} #activeFormattersConfigs :VoerkaI18nFormatterConfigs = {} #scope?:VoerkaI18nScope - #language:string // 当前语言 + #language?:string // 当前语言 #formatterCache:VoerkaI18nScopeFormatterCache = {typedFormatters:{},formatters:{}} constructor(scope?:VoerkaI18nScope){ - this.#scope = scope - this.#language = scope?.activeLanguage || "zh" + this.#scope = scope } - get activeLanguage(){ return this.#language } // 当前语言 - get activeFormatters(){ return this.#activeFormatters } // 当前语言的格式化器集合 + get activeLanguage(){ + if(!this.#language) this.#language = this.#scope?.activeLanguage || "zh" + return this.#language + } // 当前语言 get scope(){ return this.#scope } /** * 当切换语言时,切换当前语言的格式化器 @@ -62,7 +69,7 @@ export class VoerkaI18nFormatterRegistry{ */ async change(language:string){ try { - if (language in this.formatters) { + if (language in this. formatters) { this.#language = language const formatters = this.formatters[language] if(isFunction(formatters)){ @@ -81,19 +88,19 @@ export class VoerkaI18nFormatterRegistry{ if (this.scope?.debug) console.error(`Error loading ${language} formatters: ${e.message}`); } } - private async generateFormattersConfigs(language:string){ + private generateFormattersConfigs(language:string){ try{ const configSources = [ ] - const fallbackLanguage = this.scope?.getLanguage(language)?.fallback || 'en'; + const fallbackLanguage = this.scope?.getLanguage(language)?.fallback ; if(this.scope){ // 从全局Scope读取 configSources.push(this.scope.global.formatters.getConfig('*')) - configSources.push(this.scope.global.formatters.getConfig(fallbackLanguage)) - configSources.push(this.scope.global.formatters.config) + if(fallbackLanguage) configSources.push(this.scope.global.formatters.getConfig(fallbackLanguage)) + configSources.push(this.scope.global.formatters.getConfig(language)) } // 从当前Scope读取 configSources.push(this.getConfig('*')) - configSources.push(this.getConfig(fallbackLanguage)) - configSources.push(this.config) + if(fallbackLanguage) configSources.push(this.getConfig(fallbackLanguage)) + configSources.push(this.getConfig(language)) // 合并当前语言的格式化器配置参数 this.#activeFormattersConfigs = configSources.reduce((finalConfig, curConfig)=>{ if(isPlainObject(curConfig)) deepMerge(finalConfig,curConfig,{newObject:false,array:'replace'}) @@ -182,11 +189,12 @@ export class VoerkaI18nFormatterRegistry{ //****************** 以下方法和属性只作用于当前语言 *********************** */ get formatters(){ return this.#formatters } // 所有语言的格式化器集合 + get activeFormatters(){ return this.#activeFormatters } // 当前语言的格式化器集合 /** * 当前语言的格式化器配置 */ get config(){ - return (this.#activeFormatters as VoerkaI18nFormatters).$config as VoerkaI18nFormatterConfigs + return this.#activeFormattersConfigs } get types(){ return (this.#activeFormatters as VoerkaI18nFormatters).$types as VoerkaI18nFormatterConfigs @@ -213,28 +221,28 @@ export class VoerkaI18nFormatterRegistry{ if(on=="types" && name in this.#formatterCache.typedFormatters) return this.#formatterCache.typedFormatters[name as SupportedDateTypes] if(on=="scope" && name in this.#formatterCache.formatters) return this.#formatterCache.formatters[name] - const fallbackLanguage = this.scope?.getLanguage(this.activeLanguage)?.fallback || 'en'; + const fallbackLanguage = this.scope?.getLanguage(this.activeLanguage)?.fallback // 先在当前作用域中查找,再在全局查找 const targets =[] if(on=="types"){ targets.push(this.types) - targets.push(this.getTypes(fallbackLanguage)) + if(fallbackLanguage) targets.push(this.getTypes(fallbackLanguage)) targets.push(this.getTypes("*")) if(inGlobal){ targets.push(this.scope?.global.formatters.types) - targets.push(this.scope?.global.formatters.getTypes(fallbackLanguage)) + if(fallbackLanguage) targets.push(this.scope?.global.formatters.getTypes(fallbackLanguage)) targets.push(this.scope?.global.formatters.getTypes("*")) } }else if(on=='scope'){ - targets.push(this.formatters) - targets.push(this.getFormatters(fallbackLanguage)) + targets.push(this.#activeFormatters) + if(fallbackLanguage) targets.push(this.getFormatters(fallbackLanguage)) targets.push(this.getFormatters("*")) if(inGlobal){ - targets.push(this.scope?.global.formatters.types) - targets.push(this.scope?.global.formatters.getTypes(fallbackLanguage)) - targets.push(this.scope?.global.formatters.getTypes("*")) + targets.push(this.scope?.global.formatters.activeFormatters) + if(fallbackLanguage) targets.push(this.scope?.global.formatters.getFormatters(fallbackLanguage)) + targets.push(this.scope?.global.formatters.getFormatters("*")) } } // 查找指定名称的格式化器 diff --git a/packages/runtime/src/formatters/index.ts b/packages/runtime/src/formatters/index.ts index cdb6c3c..13230bd 100644 --- a/packages/runtime/src/formatters/index.ts +++ b/packages/runtime/src/formatters/index.ts @@ -8,9 +8,7 @@ import zhFormatters from "./zh" import defaultFormatters from "./default" export default { - "*":{ - ...enFormatters, - ...defaultFormatters - }, + "*":defaultFormatters, + en:enFormatters, zh:zhFormatters } diff --git a/packages/runtime/src/interpolate.ts b/packages/runtime/src/interpolate.ts index 8ffc559..5cc55ce 100644 --- a/packages/runtime/src/interpolate.ts +++ b/packages/runtime/src/interpolate.ts @@ -118,7 +118,7 @@ function executeChecker(checker:FormatterChecker, value:any,scope:VoerkaI18nScop let result = { value, next: "skip" }; if (!isFunction(checker)) return result; try { - const r = checker(value,scope.activeFormatterConfig); + const r = checker(value,scope.formatters.config); if (isPlainObject(r) && ("next" in r) && ("value" in r)) { Object.assign(result, r); } else { @@ -174,7 +174,7 @@ function executeFormatter(value:any, formatters:VoerkaI18nFormatter[], scope:Voe // 3. 分别执行格式化器函数 for (let formatter of formatters) { try { - result = formatter(result, [result],scope.activeFormatterConfig); + result = formatter(result, [result],scope.formatters.config); } catch (e:any) { e.formatter = (formatter as any).$name; if (scope.debug) @@ -234,7 +234,9 @@ function wrapperFormatters(scope:VoerkaI18nScope, activeLanguage:string, formatt let fn = scope.formatters.get(name,{on:'scope'}) let formatter; if (isFunction(fn)) { - formatter = (value:any, args?:any[],config?:VoerkaI18nFormatterConfigs) =>fn.call(scope.activeFormatterConfig, value, args, config); + formatter = (value:any, args?:any[],config?:VoerkaI18nFormatterConfigs) =>{ + return (fn as Function).call(scope.formatters.config, value, args, config); + } } else { // 格式化器无效或者没有定义时,查看当前值是否具有同名的原型方法,如果有则执行调用 // 比如padStart格式化器是String的原型方法,不需要配置就可以直接作为格式化器调用 @@ -264,7 +266,7 @@ function wrapperFormatters(scope:VoerkaI18nScope, activeLanguage:string, formatt function getFormattedValue(scope:VoerkaI18nScope, activeLanguage:string, formatters:FormatterDefineChain, value:any, template:string) { // 1. 取得格式化器函数列表,然后经过包装以传入当前格式化器的配置参数 const formatterFuncs = wrapperFormatters(scope, activeLanguage, formatters); - // 3. 执行格式化器 + // 2. 执行格式化器 // EMPTY和ERROR是默认两个格式化器,如果只有两个则说明在t(...)中没有指定格式化器 if (formatterFuncs.length == 2) { // 当没有格式化器时,查询是否指定了默认数据类型的格式化器,如果有则执行 diff --git a/packages/runtime/src/manager.ts b/packages/runtime/src/manager.ts index b78928b..1f51f54 100644 --- a/packages/runtime/src/manager.ts +++ b/packages/runtime/src/manager.ts @@ -4,8 +4,7 @@ import { EventEmitter } from "./eventemitter" import inlineFormatters from "./formatters" import type { VoerkaI18nScope } from "./scope" import type { VoerkaI18nLanguageDefine, VoerkaI18nLanguageFormatters, VoerkaI18nDefaultMessageLoader, VoerkaI18nFormatter, VoerkaI18nTypesFormatters } from "./types" -import { VoerkaI18nFormatterRegistry } from "./formatterRegistry" -import { DataTypes } from "./utils" +import { VoerkaI18nFormatterRegistry } from "./formatterRegistry" // 默认语言配置 const defaultLanguageSettings = { diff --git a/packages/runtime/src/scope.ts b/packages/runtime/src/scope.ts index 322fe71..657104e 100644 --- a/packages/runtime/src/scope.ts +++ b/packages/runtime/src/scope.ts @@ -4,7 +4,6 @@ import { translate } from "./translate" import { assignObject } from "flex-tools/object/assignObject" import {VoerkaI18nManager } from "./manager" import type { - VoerkaI18nFormatterConfigs, VoerkaI18nDefaultMessageLoader, VoerkaI18nFormatter, VoerkaI18nLanguageFormatters, @@ -12,27 +11,26 @@ import type { VoerkaI18nLanguageDefine, VoerkaI18nLanguageMessages, VoerkaI18nLanguagePack, - VoerkaI18nTranslate, - VoerkaI18nMessageLoaders, - VoerkaI18nTypesFormatters, - VoerkaI18nFormatters, + VoerkaI18nTranslate, VoerkaI18nDynamicLanguageMessages, -VoerkaI18nLanguageMessagePack, -VoerkaI18nMessageLoader, + VoerkaI18nLanguageMessagePack, + VoerkaI18nMessageLoader, } from "./types" import { VoerkaI18nFormatterRegistry } from './formatterRegistry'; import { InvalidLanguageError } from "./errors" import { randomId } from "./utils" +import { DefaultLanguageSettings, DefaultFallbackLanguage } from './consts'; export interface VoerkaI18nScopeOptions { id?: string debug?: boolean - languages: VoerkaI18nLanguageDefine[] // 当前作用域支持的语言列表 - defaultLanguage?: string // 默认语言名称 - activeLanguage?: string // 当前语言名称 - messages: VoerkaI18nLanguageMessagePack // 当前语言包 - idMap: Voerkai18nIdMap // 消息id映射列表 + languages: VoerkaI18nLanguageDefine[] // 当前作用域支持的语言列表 + defaultLanguage?: string // 默认语言名称 + activeLanguage?: string // 当前语言名称 + messages: VoerkaI18nLanguageMessagePack // 当前语言包 + idMap: Voerkai18nIdMap // 消息id映射列表 formatters: VoerkaI18nLanguageFormatters // 当前作用域的格式化函数列表{: {$types,$config,[格式化器名称]: () => {},[格式化器名称]: () => {}}} + callback?:(e?:Error)=>void // 当注册到全局管理器后的回调函数 } export class VoerkaI18nScope { @@ -40,14 +38,17 @@ export class VoerkaI18nScope { #global:VoerkaI18nManager // 引用全局VoerkaI18nManager配置,注册后自动引用 #refreshing:boolean = false #t:VoerkaI18nTranslate - #activeFormatters:VoerkaI18nFormatters = {} - #activeFormatterConfig: VoerkaI18nFormatterConfigs={} - #formatterRegistry:VoerkaI18nFormatterRegistry + #formatterRegistry?:VoerkaI18nFormatterRegistry #defaultLanguage:string ='zh' #activeLanguage:string='zh' #currentMessages:VoerkaI18nLanguageMessages = {} // 当前语言包 #patchedMessages:VoerkaI18nLanguagePack = {} // 补丁语言包 - constructor(options:VoerkaI18nScopeOptions, callback?:(e?:Error)=>void) { + /** + * + * @param options + * @param callback 当前作用域初始化完成后的回调函数 + */ + constructor(options:VoerkaI18nScopeOptions) { this.#options = assignObject({ id : randomId(), // 作用域唯一id debug : false, @@ -56,62 +57,51 @@ export class VoerkaI18nScope { idMap : {}, // 消息id映射列表 formatters : {}, // 当前作用域的格式化函数列表{: {$types,$config,[格式化器名称]: () => {},[格式化器名称]: () => {}}} },options) as Required - this.#formatterRegistry= new VoerkaI18nFormatterRegistry(this) // 初始化 this.init() // 将当前实例注册到全局单例VoerkaI18nManager中 - this.#global = this.registerToManager(callback) - // 从本地缓存中读取并合并补丁语言包 - this._mergePatchedMessages(); - // 延后执行补丁命令,该命令会向远程下载补丁包 - this._patch(this.#currentMessages, this.activeLanguage); + this.#global = this.registerToManager() this.#t = translate.bind(this) } - get id() {return this.#options.id;} // 作用域唯一id - get debug() {return this.#options.debug;} // 调试开关 - get defaultLanguage() {return this.#global.defaultLanguage;} // 默认语言名称 - get activeLanguage() {return this.#global.activeLanguage;} // 默认语言名称 + get id() {return this.#options.id;} // 作用域唯一id + get debug() {return this.#options.debug;} // 调试开关 + get defaultLanguage() {return this.#global.defaultLanguage;} // 默认语言名称 + get activeLanguage() {return this.#global.activeLanguage;} // 默认语言名称 // 默认语言包,只能静态语言包,不能是动态语言包 get default() {return this.#options.messages[this.#defaultLanguage] as VoerkaI18nLanguageMessages;} - get current() {return this.#currentMessages;} // 当前语言包 - get messages() {return this.#options.messages; } // 所有语言包 - get idMap() {return this.#options.idMap;} // 消息id映射列表 - get languages() {return this.#options.languages;} // 当前作用域支持的语言列表[{name,title,fallback}] - get global() { return this.#global;} // 引用全局VoerkaI18n配置,注册后自动引用 - get formatters() { return this.#formatterRegistry;} // 当前作用域的所有格式化器定义 {<语言名称>: {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () => {}}} - get activeFormatters() {return this.#formatterRegistry.formatters} // 当前作用域激活的格式化器定义 {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () = >{}} - get activeFormatterConfig(){return this.#activeFormatterConfig} // 当前格式化器合并后的配置参数,参数已经合并了全局格式化器中的参数 - get translate(){return this.#t} + get current() {return this.#currentMessages;} // 当前语言包 + get messages() {return this.#options.messages; } // 所有语言包 + get idMap() {return this.#options.idMap;} // 消息id映射列表 + get languages() {return this.#options.languages;} // 当前作用域支持的语言列表[{name,title,fallback}] + get global() { return this.#global;} // 引用全局VoerkaI18n配置,注册后自动引用 + get formatters() { return this.#formatterRegistry!;} // 当前作用域的所有格式化器定义 {<语言名称>: {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () => {}}} + get activeFormatters() {return this.#formatterRegistry!.formatters} // 当前作用域激活的格式化器定义 {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () = >{}} get t(){return this.#t} - /** * 对输入的语言配置进行处理 * - 将en配置为默认回退语言 * - 确保提供了有效的默认语言和活动语言 */ private init(){ + // 1. 检测语言配置列表是否有效 if(!Array.isArray(this.languages)){ console.warn("[VoerkaI18n] invalid languages config,use default languages config instead.") - this.#options.languages = [ - {name: "zh",title: "中文",default:true,active:true}, - {name: "en",title: "英文"} - ] + this.#options.languages =Object.assign([],DefaultLanguageSettings) + }else{ + if(this.languages.length==0){ + throw new Error("[VoerkaI18n] invalid languages config, languages must not be empty.") + } } + // 2.为语言配置默认回退语言,并且提取默认语言和活动语言 this.languages.forEach(language=>{ - if(!language.fallback) language.fallback = "en" + if(!language.fallback) language.fallback = DefaultFallbackLanguage if(language.default) this.#defaultLanguage = language.name if(language.active) this.#activeLanguage = language.name }) - // 确保提供了有效的默认语言和活动语言 + // 3. 确保提供了有效的默认语言和活动语言 const lanMessages = this.#options.messages - if(!(this.#defaultLanguage in lanMessages)) { - this.#defaultLanguage = Object.keys(lanMessages)[0] - } - - if(!(this.#activeLanguage in lanMessages)){ - this.#activeLanguage = this.#defaultLanguage - } - + if(!(this.#defaultLanguage in lanMessages)) this.#defaultLanguage = Object.keys(lanMessages)[0] + if(!(this.#activeLanguage in lanMessages)) this.#activeLanguage = this.#defaultLanguage if(!(this.#defaultLanguage in lanMessages)){ throw new Error("[VoerkaI18n] invalid config, messages not specified.") } @@ -141,9 +131,31 @@ export class VoerkaI18nScope { } this.#global = globalThis.VoerkaI18n as unknown as VoerkaI18nManager; if (!isFunction(callback)) callback = () => {}; - this.#global.register(this).then(()=>(callback as any)()).catch((e)=>(callback as any)(e)); + this.#global.register(this) + .then(this.onRegisterSuccess.bind(this)) + .catch(this.onRegisterFail.bind(this)) return this.#global } + /** + * 当注册到Manager后,执行注册后的操作 + */ + private onRegisterSuccess(){ + if(typeof(this.#options.callback)=='function'){ + this.#options.callback.call(this) + } + // 从本地缓存中读取并合并补丁语言包 + this._mergePatchedMessages(); + // 延后执行补丁命令,该命令会向远程下载补丁包 + this._patch(this.#currentMessages, this.activeLanguage); + } + /** + * 当注册到Manager失败时,执行注册失败后的操作 + */ + private onRegisterFail(e:any){ + if(typeof(this.#options.callback)=='function'){ + this.#options.callback.call(this,e) + } + } /** * 注册格式化器 * @@ -165,7 +177,7 @@ export class VoerkaI18nScope { if(asGlobal){ this.global.registerFormatter(name, formatter, {language}); }else{ - this.#formatterRegistry.register(name, formatter, {language}); + this.formatters!.register(name, formatter, {language}); } } // /** @@ -195,11 +207,10 @@ export class VoerkaI18nScope { * ... * } */ - private loadInitialFormatters(){ + private loadInitialFormatters(){ + this.#formatterRegistry= new VoerkaI18nFormatterRegistry(this) // 初始化格式化器 this.formatters.loadInitials(this.#options.formatters) - // 切换到当前语言的格式化器上下文 - this.formatters.change(this.activeLanguage) // 保存到Registry中,就可以从options中删除了 delete (this.#options as any).formatters } @@ -230,9 +241,9 @@ export class VoerkaI18nScope { /** * 回退到默认语言 */ - private _fallback() { + private fallbackToDefault() { this.#currentMessages = this.default; - this.#activeLanguage = this.defaultLanguage; + this.#activeLanguage = this.#defaultLanguage; } /** * @@ -240,8 +251,7 @@ export class VoerkaI18nScope { * * - 简单的对象{} * - 或者是一个返回Promise的异步函数 - * - 或者是全局的默认加载器 - * + * - 或者是全局的默认加载器 * * @param language 语言名称 * @returns @@ -302,11 +312,11 @@ export class VoerkaI18nScope { // 切换到对应语言的格式化器 await this.formatters.change(newLanguage); }else{ - this._fallback(); + this.fallbackToDefault(); } }catch(e:any){ if (this.debug) console.warn(`Error while loading language <${newLanguage}> on i18nScope(${this.id}): ${e.message}`); - this._fallback(); + this.fallbackToDefault(); } finally { this.#refreshing = false; } diff --git a/packages/runtime/src/translate.ts b/packages/runtime/src/translate.ts index b240b1f..0c55f11 100644 --- a/packages/runtime/src/translate.ts +++ b/packages/runtime/src/translate.ts @@ -119,13 +119,13 @@ export function translate(this:VoerkaI18nScope,message:string,...args:any[]):str // 当源文件运用了babel插件后会将原始文本内容转换为msgId // 如果是msgId则从scope.default中读取,scope.default=默认语言包={:} if(isMessageId(result)){ - result = scope.default[result] || message + result = (scope.default as any)[result] || message } }else{ // 2.2 从当前语言包中取得翻译文本模板字符串 // 如果没有启用babel插件将源文本转换为msgId,需要先将文本内容转换为msgId let msgId = isMessageId(result) ? result : scope.idMap[result] - result = scope.current[msgId] || result + result = (scope.current as any)[msgId] || result } // 2. 处理复数 // 经过上面的处理,content可能是字符串或者数组