2023-01-11 18:10:59 +08:00

173 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const {DataTypes,getDataTypeName,isFunction,deepMerge,toBoolean} = require("./utils")
const {createFormatter,Formatter,FlexFormatter,createFlexFormatter} = require("./formatter")
const { toDate } = require("./datatypes/datetime")
const { toNumber } = require("./datatypes/numeric")
const EventEmitter = require("./eventemitter")
const inlineFormatters = require("./formatters")
const VoerkaI18nScope = require("./scope")
const { translate } = require("./translate")
// 默认语言配置
const defaultLanguageSettings = {
debug : true,
defaultLanguage: "zh",
activeLanguage : "zh",
formatters : inlineFormatters,
languages : [
{name:"zh",title:"中文",default:true},
{name:"en",title:"英文"}
]
}
/**
* 多语言管理类
*
* 当导入编译后的多语言文件时(import("./languages"))会自动生成全局实例VoerkaI18n
*
* VoerkaI18n.languages // 返回支持的语言列表
* VoerkaI18n.defaultLanguage // 默认语言
* VoerkaI18n.language // 当前语言
* VoerkaI18n.change(language) // 切换到新的语言
*
*
* VoerkaI18n.on("change",(language)=>{}) // 注册语言切换事件
* VoerkaI18n.off("change",(language)=>{})
*
* */
class VoerkaI18nManager extends EventEmitter{
constructor(settings={}){
super()
if(VoerkaI18nManager.instance!=null){
return VoerkaI18nManager.instance;
}
VoerkaI18nManager.instance = this;
this._settings = deepMerge(defaultLanguageSettings,settings)
this._scopes=[] // 保存VoerkaI18nScope实例
this._defaultMessageLoader = null // 默认语言包加载器
}
get settings(){ return this._settings } // 配置参数
get scopes(){ return this._scopes } // 注册的报有VoerkaI18nScope实例q
get activeLanguage(){ return this._settings.activeLanguage} // 当前激活语言 名称
get defaultLanguage(){ return this._settings.defaultLanguage} // 默认语言名称
get languages(){ return this._settings.languages} // 支持的语言列表
get formatters(){ return this._settings.formatters } // 内置格式化器{*:{$config,$types,...},zh:{$config,$types,...},en:{$config,$types,...}}
get defaultMessageLoader(){ return this._defaultMessageLoader} // 默认语言包加载器
// 通过默认加载器加载文件
async loadMessagesFromDefaultLoader(newLanguage,scope){
if(!isFunction(this._defaultMessageLoader)) return //throw new Error("No default message loader specified")
return await this._defaultMessageLoader.call(scope,newLanguage,scope)
}
/**
* 切换语言
*/
async change(language){
if(this.languages.findIndex(lang=>lang.name === language)!==-1 || isFunction(this._defaultMessageLoader)){
await this._refreshScopes(language) // 通知所有作用域刷新到对应的语言包
this._settings.activeLanguage = language
await this.emit(language) // 触发语言切换事件
return language
}else{
throw new Error("Not supported language:"+language)
}
}
/**
* 当切换语言时调用此方法来加载更新语言包
* @param {*} newLanguage
*/
async _refreshScopes(newLanguage){
try{
const scopeRefreshers = this._scopes.map(scope=>{
return scope.refresh(newLanguage)
})
if(Promise.allSettled){
await Promise.allSettled(scopeRefreshers)
}else{
await Promise.all(scopeRefreshers)
}
}catch(e){
console.warn("Error while refreshing i18n scopes:",e.message)
}
}
/**
*
* 注册一个新的作用域
*
* 每一个库均对应一个作用域,每个作用域可以有多个语言包,且对应一个翻译函数
* 除了默认语言外,其他语言采用动态加载的方式
*
* @param {*} scope
*/
async register(scope){
if(!(scope instanceof VoerkaI18nScope)){
throw new TypeError("Scope must be an instance of VoerkaI18nScope")
}
this._scopes.push(scope)
await scope.refresh(this.activeLanguage)
}
/**
* 注册全局格式化器
* 格式化器是一个简单的同步函数value=>{...},用来对输入进行格式化后返回结果
*
* registerFormatter(name,value=>{...}) // 注册到所有语言
* registerFormatter(name,value=>{...},{langauge:"zh"}) // 注册到zh语言
* registerFormatter(name,value=>{...},{langauge:"en"}) // 注册到en语言
registerFormatter("Date",value=>{...},{langauge:"en"}) // 注册到en语言的默认数据类型格式化器
registerFormatter(name,value=>{...},{langauge:["zh","cht"]}) // 注册到zh和cht语言
registerFormatter(name,value=>{...},{langauge:"zh,cht"})
* @param {*} formatter
language : 声明该格式化器适用语言
isGlobal : 注册到全局
*/
registerFormatter(name,formatter,{language="*"}={}){
if(!isFunction(formatter) || typeof(name)!=="string"){
throw new TypeError("Formatter must be a function")
}
language = Array.isArray(language) ? language : (language ? language.split(",") : [])
language.forEach(lng=>{
if(DataTypes.includes(name)){
this.formatters[lng].$types[name] = formatter
}else{
this.formatters[lng][name] = formatter
}
})
}
/**
* 注册默认文本信息加载器
*/
registerDefaultLoader(fn){
if(!isFunction(fn)) throw new Error("The default loader must be a async function or promise returned")
this._defaultMessageLoader = fn
this.refresh()
}
async refresh(){
try{
let requests = this._scopes.map(scope=>scope.refresh())
if(Promise.allSettled){
await Promise.allSettled(requests)
}else{
await Promise.all(requests)
}
}catch(e){
if(this._debug) console.error(`Error while refresh voerkai18n scopes:${e.message}`)
}
}
}
module.exports ={
toDate,
toNumber,
toBoolean,
deepMerge,
VoerkaI18nManager,
translate,
VoerkaI18nScope,
createFormatter,
Formatter,
createFlexFormatter,
FlexFormatter,
getDataTypeName
}