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