update formatters

This commit is contained in:
wxzhang 2022-08-11 22:06:31 +08:00
parent ab9e150470
commit 3c31d3fb67
3 changed files with 388 additions and 308 deletions

View File

@ -250,48 +250,39 @@ function getDataTypeDefaultFormatter(scope,activeLanguage,dataType){
} }
} }
/** /**
* 获取指定名称的格式化器函数 * 获取指定名称的格式化器函数
* *
* 查找逻辑 * 查找逻辑
* - 在当前作用域中查找 * - 在当前作用域中查找
*
* - 在全局作用域中查找 * - 在全局作用域中查找
* *
* 全局作用域的格式化器优先
*
* @param {*} scope * @param {*} scope
* @param {*} activeLanguage 当前激活语言名称 * @param {*} activeLanguage 当前激活语言名称
* @param {*} name 格式化器名称 * @param {*} name 格式化器名称
* @returns {Function} 格式化函数 * @returns {Function} 格式化函数
*/ */
function getFormatter(scope,activeLanguage,name){ function getFormatter(scope,activeLanguage,name){
// 缓存格式化器引用,避免重复检索 // 1. 从缓存中直接读取: 缓存格式化器引用,避免重复检索
if(!scope.$cache) resetScopeCache(scope) if(!scope.$cache) resetScopeCache(scope)
if(scope.$cache.activeLanguage === activeLanguage) { if(scope.$cache.activeLanguage === activeLanguage) {
if(name in scope.$cache.formatters) return scope.$cache.formatters[name] if(name in scope.$cache.formatters) return scope.$cache.formatters[name]
}else{// 当语言切换时清空缓存 }else{// 当语言切换时清空缓存
resetScopeCache(scope,activeLanguage) resetScopeCache(scope,activeLanguage)
} }
// 先在当前作用域中查找,再在全局查找 const fallbackLanguage = scope.getLanguage(activeLanguage).fallback
const targets = [scope.global.formatters,scope.formatters] // 2. 先在当前作用域中查找,再在全局查找 formatters={$types,$options,[格式化器名称]:()=>{},[格式化器名称]:()=>{}}
for(const target of targets){ const range = [
// 1. 优先在当前语言查找 scope.activeFormatters,
if(activeLanguage in target){ scope.formatters[fallbackLanguage], // 如果指定了回退语言时,也在该回退语言中查找
let formatters = target[activeLanguage] || {} scope.global.formatters[activeLanguage], // 适用于activeLanguage全局格式化器
if((name in formatters) && isFunction(formatters[name])) { scope.global.formatters["*"], // 适用于所有语言的格式化器
return scope.$cache.formatters[name] = formatters[name] ]
}else{ // 如果语言指定了fallback,则在其回退语言中查找 for(const formatters of range){
let fallbackLangName = scope.getFallbackLanguage(activeLanguage) if(!formatters) continue
if((fallbackLangName in formatters) && isFunction(formatters[fallbackLangName])) { if(isFunction(formatters[name])) {
return scope.$cache.formatters[name] = formatters[fallbackLangName] return scope.$cache.formatters[name] = formatters[name]
} }
}
}
// 2. 全局作用域中查找
let formatters = target["*"] || {}
if((name in formatters) && isFunction(formatters[name])) return scope.$cache.formatters[name] = formatters[name]
} }
} }
@ -317,8 +308,6 @@ function executeFormatter(value,formatters,scope){
return result return result
} }
/** /**
*
*
* *
* [[格式化器名称,[参数,参数,...]][格式化器名称,[参数,参数,...]]]格式化器转化为 * [[格式化器名称,[参数,参数,...]][格式化器名称,[参数,参数,...]]]格式化器转化为
* 格式化器的调用函数链 * 格式化器的调用函数链
@ -328,7 +317,6 @@ function executeFormatter(value,formatters,scope){
* @param {*} formatters * @param {*} formatters
* @returns {Array} [(v)=>{...},(v)=>{...},(v)=>{...}] * @returns {Array} [(v)=>{...},(v)=>{...},(v)=>{...}]
* *
*
*/ */
function buildFormatters(scope,activeLanguage,formatters){ function buildFormatters(scope,activeLanguage,formatters){
let results = [] let results = []
@ -356,7 +344,7 @@ function buildFormatters(scope,activeLanguage,formatters){
} }
/** /**
* 将value经过格式化器处理后返回 * 将value经过格式化器处理后返回的结果
* @param {*} scope * @param {*} scope
* @param {*} activeLanguage * @param {*} activeLanguage
* @param {*} formatters * @param {*} formatters
@ -578,9 +566,8 @@ function translate(message) {
} }
I18nManager.instance = this; I18nManager.instance = this;
this._settings = deepMerge(defaultLanguageSettings,settings) this._settings = deepMerge(defaultLanguageSettings,settings)
this._scopes=[] this._scopes=[] // 保存i18nScope实例
this._defaultMessageLoader = null // 默认文本加载器 this._defaultMessageLoader = null // 默认文本加载器
return I18nManager.instance;
} }
get settings(){ return this._settings } get settings(){ return this._settings }
get scopes(){ return this._scopes } get scopes(){ return this._scopes }
@ -692,7 +679,9 @@ function translate(message) {
}else{ }else{
await Promise.all(requests) await Promise.all(requests)
} }
}catch{} }catch(e){
if(this._debug) console.error(`Error while refresh voerkai18n scopes:${e.message}`)
}
} }
} }

View File

@ -1,78 +1,114 @@
const { isPlainObject,isFunction } = require("./utils") const { isPlainObject, isFunction, getByPath, deepMixin } = require("./utils");
const DataTypes = ["String","Number","Boolean","Object","Array","Function","Null","Undefined","Symbol","Date","RegExp","Error"]; const DataTypes = [
"String",
"Number",
"Boolean",
"Object",
"Array",
"Function",
"Null",
"Undefined",
"Symbol",
"Date",
"RegExp",
"Error",
];
module.exports = class i18nScope { module.exports = class i18nScope {
constructor(options={},callback){ constructor(options = {}, callback) {
this._id = options.id || (new Date().getTime().toString()+parseInt(Math.random()*1000)) this._id = options.id || Date.now().toString() + parseInt(Math.random() * 1000);
this._debug = options.debug // 当出错时是否在控制台台输出错误信息 // 当出错时是否在控制台台输出错误信息
this._languages = options.languages // 当前作用域的语言列表 this._debug = options.debug == undefined ? process && process.env && process.env.NODE_ENV === "development" : options.debug;
this._defaultLanguage = options.defaultLanguage || "zh" // 默认语言名称 this._languages = options.languages; // 当前作用域的语言列表
this._activeLanguage = options.activeLanguage // 当前语言名称 this._defaultLanguage = options.defaultLanguage || "zh"; // 默认语言名称
this._default = options.default // 默认语言包 this._activeLanguage = options.activeLanguage; // 当前语言名称
this._messages = options.messages // 当前语言包 this._default = options.default; // 默认语言包
this._idMap = options.idMap // 消息id映射列表 this._messages = options.messages; // 当前语言包
this._formatters = options.formatters // 当前作用域的格式化函数列表{<lang>:{$types,$options,[格式化器名称]:()=>{},[格式化器名称]:()=>{}}} this._idMap = options.idMap; // 消息id映射列表
this._loaders = options.loaders // 异步加载语言文件的函数列表 this._formatters = options.formatters; // 当前作用域的格式化函数列表{<lang>:{$types,$options,[格式化器名称]:()=>{},[格式化器名称]:()=>{}}}
this._global = null // 引用全局VoerkaI18n配置注册后自动引用 this._loaders = options.loaders; // 异步加载语言文件的函数列表
this._activeFormatters= options.formatters[options.activeLanguage] // 激活使用的格式化器,查找格式化器时在此查找 this._global = null; // 引用全局VoerkaI18n配置注册后自动引用
this._patchMessages = {} // 语言包补丁信息 {<language>:{....},<language>:{....}} this._activeFormatters = options.formatters[options.activeLanguage]; // 激活使用的格式化器,查找格式化器时在此查找
// 用来缓存格式化器的引用,当使用格式化器时可以直接引用,减少检索遍历 this._patchMessages = {}; // 语言包补丁信息 {<language>:{....},<language>:{....}}
this.$cache={ // 用来缓存格式化器的引用,当使用格式化器时可以直接引用,减少检索遍历
activeLanguage : null, this.$cache = {
typedFormatters: {}, activeLanguage: null,
formatters : {}, typedFormatters: {},
} formatters: {},
// 如果不存在全局VoerkaI18n实例说明当前Scope是唯一或第一个加载的作用域则自动创建全局VoerkaI18n实例 };
if(!globalThis.VoerkaI18n){ // 如果不存在全局VoerkaI18n实例说明当前Scope是唯一或第一个加载的作用域则自动创建全局VoerkaI18n实例
const { I18nManager } = require("./") if (!globalThis.VoerkaI18n) {
globalThis.VoerkaI18n = new I18nManager({ const { I18nManager } = require("./");
debug : this._debug, globalThis.VoerkaI18n = new I18nManager({
defaultLanguage: this.defaultLanguage, debug: this._debug,
activeLanguage : this.activeLanguage, defaultLanguage: this.defaultLanguage,
languages : options.languages, activeLanguage: this.activeLanguage,
}) languages: options.languages,
} });
this._global = globalThis.VoerkaI18n }
// 合并补丁语言包 this._global = globalThis.VoerkaI18n;
this._mergePatchedMessages() // 合并补丁语言包
this._patch(this._messages,this.activeLanguage) this._mergePatchedMessages();
// 正在加载语言包标识 this._patch(this._messages, this.activeLanguage);
this._refreshing=false // 正在加载语言包标识
// 在全局注册作用域 this._refreshing = false;
this.register(callback) // 在全局注册作用域
} this.register(callback);
// 作用域 }
get id(){return this._id} // 作用域
// 调试开关 get id() {
get debug(){return this._debug} return this._id;
// 默认语言名称 }
get defaultLanguage(){return this._defaultLanguage} // 调试开关
// 默认语言名称 get debug() {
get activeLanguage(){return this._activeLanguage} return this._debug;
// 默认语言包 }
get default(){return this._default} // 默认语言名称
// 当前语言包 get defaultLanguage() {
get messages(){return this._messages} return this._defaultLanguage;
// 消息id映射列表 }
get idMap(){return this._idMap} // 默认语言名称
// 当前作用域的格式化器 {<lang>:{$types,$options,[格式化器名称]:()=>{},[格式化器名称]:()=>{}}} get activeLanguage() {
get formatters(){return this._formatters} return this._activeLanguage;
// 当前作用域支持的语言列表[{name,title,fallback}] }
get languages(){return this._languages} // 默认语言包
// 异步加载语言文件的函数列表 get default() {
get loaders(){return this._loaders} return this._default;
// 引用全局VoerkaI18n配置注册后自动引用 }
get global(){return this._global} // 当前语言包
/** get messages() {
* 在全局注册作用域 return this._messages;
* @param {*} callback 注册成功后的回调 }
*/ // 消息id映射列表
register(callback){ get idMap() {
if(!isFunction(callback)) callback = ()=>{} return this._idMap;
this.global.register(this).then(callback).catch(callback) }
} // 当前作用域的格式化器 {<lang>:{$types,$options,[格式化器名称]:()=>{},[格式化器名称]:()=>{}}}
/** get formatters() {
return this._formatters;
}
// 当前作用域支持的语言列表[{name,title,fallback}]
get languages() {
return this._languages;
}
// 异步加载语言文件的函数列表
get loaders() {
return this._loaders;
}
// 引用全局VoerkaI18n配置注册后自动引用
get global() {
return this._global;
}
/**
* 在全局注册作用域
* @param {*} callback 注册成功后的回调
*/
register(callback) {
if (!isFunction(callback)) callback = () => {};
this.global.register(this).then(callback).catch(callback);
}
/**
* 注册格式化器 * 注册格式化器
* *
* 格式化器是一个简单的同步函数value=>{...}用来对输入进行格式化后返回结果 * 格式化器是一个简单的同步函数value=>{...}用来对输入进行格式化后返回结果
@ -87,213 +123,242 @@ module.exports = class i18nScope {
language : 声明该格式化器适用语言 language : 声明该格式化器适用语言
asGlobal : 注册到全局 asGlobal : 注册到全局
*/ */
registerFormatter(name,formatter,{language="*",asGlobal}={}){ registerFormatter(name, formatter, { language = "*", asGlobal } = {}) {
if(!isFunction(formatter) || typeof(name)!=="string"){ if (!isFunction(formatter) || typeof name !== "string") {
throw new TypeError("Formatter must be a function") throw new TypeError("Formatter must be a function");
} }
language = Array.isArray(language) ? language : (language ? language.split(",") : []) language = Array.isArray(language)
if(asGlobal){ ? language
this.global.registerFormatter(name,formatter,{language}) : language
}else{ ? language.split(",")
language.forEach(lng=>{ : [];
if(DataTypes.includes(name)){ if (asGlobal) {
this._formatters[lng].$types[name] = formatter this.global.registerFormatter(name, formatter, { language });
}else{ } else {
this._formatters[lng][name] = formatter language.forEach((lng) => {
} if (DataTypes.includes(name)) {
}) this._formatters[lng].$types[name] = formatter;
} } else {
} this._formatters[lng][name] = formatter;
/** }
* 注册默认文本信息加载器 });
* @param {Function} 必须是异步函数或者是返回Promise }
*/ }
registerDefaultLoader(fn){ /**
this.global.registerDefaultLoader(fn) * 注册默认文本信息加载器
} * @param {Function} 必须是异步函数或者是返回Promise
/** */
* 获取指定语言信息 registerDefaultLoader(fn) {
* @param {*} language this.global.registerDefaultLoader(fn);
* @returns }
*/ /**
_getLanguage(language){ * 获取指定语言信息
let index = this._languages.findIndex(lng=>lng.name==language) * @param {*} language
if(index!==-1) return this._languages[index] * @returns
} */
/** getLanguage(language) {
* 返回是否存在指定的语言 let index = this._languages.findIndex((lng) => lng.name == language);
* @param {*} language 语言名称 if (index !== -1) return this._languages[index];
* @returns }
*/ /**
hasLanguage(language){ * 返回是否存在指定的语言
return this._languages.indexOf(lang=>lang.name==language)!==-1 * @param {*} language 语言名称
} * @returns
/** */
* 获取指定语言的回退语言名称 hasLanguage(language) {
return this._languages.indexOf((lang) => lang.name == language) !== -1;
}
/**
* 回退到默认语言
*/
_fallback() {
this._messages = this._default;
this._activeLanguage = this.defaultLanguage;
}
/**
* 当切换语言时格式化器应该切换到对应语言的格式化器
* *
* 如果没有指定则总是回退到到默认语言 * 重要需要处理
* $options参数采用合并继承机制
* *
* 但是不支持回退链
* *
* 可以在配置中指定回退语言 * @param {*} language
* // settings.json */
* { async _changeFormatters(newLanguage) {
* languages:[ try {
* {name:"zh"}, if (newLanguage in this._formatters) {
* {name:"cht",fallback:"zh"}, //繁体中文可以回退到简体中文, let loader = this._formatters[newLanguage];
* {name:"en"}, if (isPlainObject(loader)) {
* ] this._activeFormatters = loader;
* } } else if (isFunction(loader)) {
* this._activeFormatters = (await loader()).default;
* @param {*} language }
* @returns {Object} 语言信息数据 {name,title,fallback,...} // 合并生成格式化器的配置参数,当执行格式化器时该参数将被传递给格式化器
*/ this._generateFormatterOptions(newLanguage)
getFallbackLanguage(language){ } else {
let lang = this._getLanguage(language) if (this._debug) console.warn(`Not configured <${newLanguage}> formatters.`);
if(lang){ }
return this.hasLanguage(lang.fallback) ? lang.fallback : this.defaultLanguage } catch (e) {
} if (this._debug) console.error(`Error loading ${newLanguage} formatters: ${e.message}`);
} }
}
/** /**
* 回退到默认语言 * 生成格式化器的配置参数该参数由以下合并而成
* - global.formatters[*].$options
* - global.formatters[language].$options
* - scope.activeFormattes.$options 优先
*/ */
_fallback(){ _generateFormatterOptions(language){
this._messages = this._default let options = Object.assign({},getByPath(global.formatters,`*.$options`,{}))
this._activeLanguage = this.defaultLanguage deepMixin(options,getByPath(global.formatters,`${language}.$options`,{}))
deepMixin(options,getByPath(scope.activeFormattes,"$options",{}))
return this._activeFormatterOptions = options
} }
/** /**
* 当切换语言时格式化器应该切换到对应语言的格式化器 * 刷新当前语言包
* @param {*} language * @param {*} newLanguage
*/ */
async _loadFormatters(newLanguage){ async refresh(newLanguage) {
try{ this._refreshing = true;
if(newLanguage in this._formatters){ if (!newLanguage) newLanguage = this.activeLanguage;
let loader = this._formatters[newLanguage] // 默认语言:由于默认语言采用静态加载方式而不是异步块,因此只需要简单的替换即可
if(isPlainObject(loader)){ if (newLanguage === this.defaultLanguage) {
this._activeFormatters = loader this._messages = this._default;
}else if(isFunction(loader)){ await this._patch(this._messages, newLanguage); // 异步补丁
this._activeFormatters = (await loader()).default this._changeFormatters(newLanguage);
} return;
}else{ }
if(this._debug) console.warn(`Not configured <${newLanguage}> formatters.`) // 非默认语言需要异步加载语言包文件,加载器是一个异步函数
} // 如果没有加载器,则无法加载语言包,因此回退到默认语言
}catch(e){ let loader = this.loaders[newLanguage];
if(this._debug) console.error(`Error loading ${newLanguage} formatters: ${e.message}`) try {
} if (isPlainObject(loader)) {
} this._messages = loader;
/** await this._patch(this._messages, newLanguage);
* 刷新当前语言包 } else if (isFunction(loader)) {
* @param {*} newLanguage this._messages = (await loader()).default;
*/ this._activeLanguage = newLanguage;
async refresh(newLanguage){ await this._patch(this._messages, newLanguage);
this._refreshing = true } else if (isFunction(this.global.defaultMessageLoader)) {
if(!newLanguage) newLanguage = this.activeLanguage // 如果该语言没有指定加载器,则使用全局配置的默认加载器
// 默认语言:由于默认语言采用静态加载方式而不是异步块,因此只需要简单的替换即可 const loadedMessages =
if(newLanguage === this.defaultLanguage){ await this.global.loadMessagesFromDefaultLoader(
this._messages = this._default newLanguage,
await this._patch(this._messages,newLanguage) // 异步补丁 this
this._loadFormatters(newLanguage) );
return this._messages = Object.assign(
} {},
// 非默认语言需要异步加载语言包文件,加载器是一个异步函数 this._default,
// 如果没有加载器,则无法加载语言包,因此回退到默认语言 loadedMessages
let loader = this.loaders[newLanguage] );
try{ this._activeLanguage = newLanguage;
if(isPlainObject(loader)){ } else {
this._messages = loader this._fallback();
await this._patch(this._messages,newLanguage) }
}else if(isFunction(loader)){ // 应该切换到对应语言的格式化器
this._messages = (await loader()).default this._changeFormatters(newLanguage);
this._activeLanguage = newLanguage } catch (e) {
await this._patch(this._messages,newLanguage) if (this._debug) console.warn(`Error while loading language <${newLanguage}> on i18nScope(${this.id}): ${e.message}`);
}else if(isFunction(this.global.defaultMessageLoader)){// 如果该语言没有指定加载器,则使用全局配置的默认加载器 this._fallback();
const loadedMessages = await this.global.loadMessagesFromDefaultLoader(newLanguage,this) } finally {
this._messages = Object.assign({},this._default,loadedMessages) this._refreshing = false;
this._activeLanguage = newLanguage }
}else{ }
this._fallback() /**
} * 当指定了默认语言包加载器后会从服务加载语言补丁包来更新本地的语言包
// 应该切换到对应语言的格式化器 *
this._loadFormatters(newLanguage) * 补丁包会自动存储到本地的LocalStorage中
}catch(e){ *
if(this._debug) console.warn(`Error while loading language <${newLanguage}> on i18nScope(${this.id}): ${e.message}`) * @param {*} messages
this._fallback() * @param {*} newLanguage
}finally{ * @returns
this._refreshing = false */
} async _patch(messages, newLanguage) {
} if (!isFunction(this.global.loadMessagesFromDefaultLoader)) return;
/** try {
* 当指定了默认语言包加载器后会从服务加载语言补丁包来更新本地的语言包 let pachedMessages =
* await this.global.loadMessagesFromDefaultLoader(
* 补丁包会自动存储到本地的LocalStorage中 newLanguage,
* this
* @param {*} messages );
* @param {*} newLanguage if (isPlainObject(pachedMessages)) {
* @returns Object.assign(messages, pachedMessages);
*/ this._savePatchedMessages(pachedMessages, newLanguage);
async _patch(messages,newLanguage){ }
if(!isFunction(this.global.loadMessagesFromDefaultLoader)) return } catch (e) {
try{ if (this._debug) console.error(`Error while loading <${newLanguage}> messages from remote:${error.message}`);
let pachedMessages = await this.global.loadMessagesFromDefaultLoader(newLanguage,this) }
if(isPlainObject(pachedMessages)){ }
Object.assign(messages,pachedMessages) /**
this._savePatchedMessages(pachedMessages,newLanguage) * 从本地存储中读取语言包补丁合并到当前语言包中
} */
}catch(e){ _mergePatchedMessages() {
if(this._debug) console.error(`Error while loading <${newLanguage}> messages from remote:${error.message}`) let patchedMessages = this._getPatchedMessages(this.activeLanguage);
} if (isPlainObject(patchedMessages)) {
} Object.assign(this._messages, patchedMessages);
/** }
* 从本地存储中读取语言包补丁合并到当前语言包中 }
*/ /**
_mergePatchedMessages(){ * 将读取的补丁包保存到本地的LocalStorage中
let patchedMessages= this._getPatchedMessages(this.activeLanguage) *
if(isPlainObject(patchedMessages)){ * 为什么要保存到本地的LocalStorage中
Object.assign(this._messages,patchedMessages) *
} * 因为默认语言是静态嵌入到源码中的而加载语言包补丁是延后异步的
} * 当应用启动第一次就会渲染出来的是没有打过补丁的内容
/** *
* 将读取的补丁包保存到本地的LocalStorage中 * - 如果还需要等待从服务器加载语言补丁合并后再渲染会影响速度
* * - 如果不等待从服务器加载语言补丁就渲染则会先显示未打补丁的内容然后在打完补丁后再对应用进行重新渲染生效
* 为什么要保存到本地的LocalStorage中 * 这明显不是个好的方式
* *
* 因为默认语言是静态嵌入到源码中的而加载语言包补丁是延后异步的 * 因此采用的方式是
* 当应用启动第一次就会渲染出来的是没有打过补丁的内容 * - 加载语言包补丁后将之保存到到本地的LocalStorage中
* * - 当应用加载时会查询是否存在补丁如果存在就会合并渲染
* - 如果还需要等待从服务器加载语言补丁合并后再渲染会影响速度 *
* - 如果不等待从服务器加载语言补丁就渲染则会先显示未打补丁的内容然后在打完补丁后再对应用进行重新渲染生效 * @param {*} messages
* 这明显不是个好的方式 */
* _savePatchedMessages(messages, language) {
* 因此采用的方式是 try {
* - 加载语言包补丁后将之保存到到本地的LocalStorage中 if (globalThis.localStorage) {
* - 当应用加载时会查询是否存在补丁如果存在就会合并渲染 globalThis.localStorage.setItem(
* `voerkai18n_${this.id}_${language}_patched_messages`,
* @param {*} messages JSON.stringify(messages)
*/ );
_savePatchedMessages(messages,language){ }
try{ } catch (e) {
if(globalThis.localStorage){ if (this.$cache._debug)
globalThis.localStorage.setItem(`voerkai18n_${this.id}_${language}_patched_messages`, JSON.stringify(messages)); console.error(
} "Error while save voerkai18n patched messages:",
}catch(e){ e.message
if(this.$cache._debug) console.error("Error while save voerkai18n patched messages:",e.message) );
} }
} }
/** /**
* 从本地缓存中读取补丁语言包 * 从本地缓存中读取补丁语言包
* @param {*} language * @param {*} language
* @returns * @returns
*/ */
_getPatchedMessages(language){ _getPatchedMessages(language) {
try{ try {
return JSON.parse(localStorage.getItem(`voerkai18n_${this.id}_${language}_patched_messages`)) return JSON.parse(
}catch(e){ localStorage.getItem(
return {} `voerkai18n_${this.id}_${language}_patched_messages`
} )
} );
// 以下方法引用全局VoerkaI18n实例的方法 } catch (e) {
get on(){return this._global.on.bind(this._global)} return {};
get off(){return this._global.off.bind(this._global)} }
get offAll(){return this._global.offAll.bind(this._global)} }
get change(){return this._global.change.bind(this._global)} // 以下方法引用全局VoerkaI18n实例的方法
} get on() {
return this._global.on.bind(this._global);
}
get off() {
return this._global.off.bind(this._global);
}
get offAll() {
return this._global.offAll.bind(this._global);
}
get change() {
return this._global.change.bind(this._global);
}
};

View File

@ -172,6 +172,31 @@ function toNumber(value,defualt=0) {
return prefix + result.join("") + suffix return prefix + result.join("") + suffix
} }
/**
* 根据路径获取指定值
*
* getByPath({a:{b:1}},"a.b") == 1
* getByPath({a:{b:1}},"a.c",2) == 2
*
* @param {*} obj
* @param {*} path 使用.分割的路径
* @param {*} defaultValue 默认值
* @returns
*/
function getByPath(obj,path,defaultValue){
if(typeof(obj)!="object") return defaultValue
let paths = path.split(".")
let cur = obj
for(let key of paths){
if(typeof(cur)=="object" && key in cur ){
cur = cur[key]
}else{
return defaultValue
}
}
return cur
}
/** /**
* 返回value相对rel的相对时间 * 返回value相对rel的相对时间
* *
@ -191,6 +216,7 @@ module.exports ={
isNothing, isNothing,
deepMerge, deepMerge,
deepMixin, deepMixin,
getByPath,
getDataTypeName, getDataTypeName,
toDate, toDate,
toNumber, toNumber,