From 0f08a77555099e59da39f5c11fa75d057d39babc Mon Sep 17 00:00:00 2001 From: wxzhang Date: Thu, 25 Aug 2022 22:05:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A0=BC=E5=BC=8F=E5=8C=96?= =?UTF-8?q?=E5=99=A8=E5=85=A8=E5=B1=80=E6=B3=A8=E5=86=8C=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/src/guide/advanced/customformatter.md | 2 +- docs/src/guide/intro/history.md | 2 + packages/cli/compile.command.js | 6 +- packages/cli/languages/formatters/de.js | 3 +- packages/cli/languages/formatters/en.js | 3 +- packages/cli/languages/formatters/global.js | 106 -------------------- packages/cli/languages/formatters/zh.js | 3 +- packages/cli/languages/index.js | 2 - packages/cli/languages/runtime.js | 12 ++- packages/cli/templates/entry.js | 3 - packages/cli/templates/formatters.js | 13 ++- packages/runtime/interpolate.js | 1 + packages/runtime/scope.js | 87 ++++++++++------ 13 files changed, 82 insertions(+), 161 deletions(-) delete mode 100644 packages/cli/languages/formatters/global.js diff --git a/docs/src/guide/advanced/customformatter.md b/docs/src/guide/advanced/customformatter.md index 291c0ef..1b69e75 100644 --- a/docs/src/guide/advanced/customformatter.md +++ b/docs/src/guide/advanced/customformatter.md @@ -2,7 +2,7 @@ ## 概念 -格式化器是`voerkai18n`中引入的用来对待翻译内容中的插值变量进行链式处理的一种机制,目的是为不同的语言下对内容中的插值变量进行动态处理机制。格式化器机制为`voerkai18n`中的日期时间、货币等多语言输出提供了强大灵活、可扩展、可配置的处理方案。 +格式化器是`voerkai18n`中引入的用来对翻译内容中的插值变量进行链式处理的一种机制,目的是为不同的语言下对内容中的插值变量进行动态处理。格式化器机制为`voerkai18n`中的日期时间、货币等多语言输出提供了强大灵活、可扩展、可配置的处理方案。 格式化器具有以下特点: diff --git a/docs/src/guide/intro/history.md b/docs/src/guide/intro/history.md index a1c343d..cd4a9db 100644 --- a/docs/src/guide/intro/history.md +++ b/docs/src/guide/intro/history.md @@ -6,9 +6,11 @@ - 新增加日期格式化 - 新增加货币格式化 - 调整运行时代码组织 + ## 2022/8/7 - 更新文档 + ## 2022/8/5 - 增加语言包补丁功能,可以在应用上线后动态更新修复翻译错误 diff --git a/packages/cli/compile.command.js b/packages/cli/compile.command.js index 280d365..336aaeb 100644 --- a/packages/cli/compile.command.js +++ b/packages/cli/compile.command.js @@ -171,10 +171,8 @@ module.exports =async function compile(langFolder,opts={}){ // 为每一个语言生成一个对应的式化器 languages.forEach(lang=>{ generateFormatterFile(lang.name,{formattersFolder,templateContext,moduleType}) - }) - templateContext.comments = "注册到全局的格式化器" - generateFormatterFile("global",{formattersFolder,templateContext,moduleType}) - + }) + // 6. 生成编译后的访问入口文件 const entryFile = path.join(langFolder,"index.js") const entryContent = artTemplate(path.join(__dirname,"templates","entry.js"), templateContext ) diff --git a/packages/cli/languages/formatters/de.js b/packages/cli/languages/formatters/de.js index a63c1c1..f05b6d2 100644 --- a/packages/cli/languages/formatters/de.js +++ b/packages/cli/languages/formatters/de.js @@ -1,7 +1,5 @@ /** - - 格式化器用来对翻译文本内容中的插值变量进行处理 如何编写格式器请参阅官网! @@ -11,6 +9,7 @@ // import { Formatter,FlexFormatter } from "./runtime" export default { + // global : true, // 是否注册到全局,false只在当前scope生效 // 直接对内置格式化器进行配置,请参阅官网文档 // $config:{ // datetime : { diff --git a/packages/cli/languages/formatters/en.js b/packages/cli/languages/formatters/en.js index a63c1c1..f05b6d2 100644 --- a/packages/cli/languages/formatters/en.js +++ b/packages/cli/languages/formatters/en.js @@ -1,7 +1,5 @@ /** - - 格式化器用来对翻译文本内容中的插值变量进行处理 如何编写格式器请参阅官网! @@ -11,6 +9,7 @@ // import { Formatter,FlexFormatter } from "./runtime" export default { + // global : true, // 是否注册到全局,false只在当前scope生效 // 直接对内置格式化器进行配置,请参阅官网文档 // $config:{ // datetime : { diff --git a/packages/cli/languages/formatters/global.js b/packages/cli/languages/formatters/global.js deleted file mode 100644 index ba68ce8..0000000 --- a/packages/cli/languages/formatters/global.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - - 注册到全局的格式化器 - - 格式化器用来对翻译文本内容中的插值变量进行处理 - - 如何编写格式器请参阅官网! - - */ - - -// import { Formatter,FlexFormatter } from "./runtime" -export default { - // 直接对内置格式化器进行配置,请参阅官网文档 - // $config:{ - // datetime : { - // units : ["Year","Quarter","Month","Week","Day","Hour","Minute","Second","Millisecond","Microsecond"], - // date :{ - // long : 'YYYY/MM/DD HH:mm:ss', - // short : "YYYY/MM/DD", - // format : "local" - // }, - // quarter : { - // long : ["First Quarter","Second Quarter","Third Quarter","Fourth Quarter"], - // short : ["Q1","Q2","Q3","Q4"], - // format : "short" - // }, - // month:{ - // long : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - // short : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"], - // format : "long" // 0-长名称,1-短名称,2-数字 - // }, - // weekday:{ - // long : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], - // short : ["Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"], - // format : "long", // 0-长名称,1-短名称,2-数字 - // }, - // time : { - // long : "HH:mm:ss", - // short : "HH:mm:ss", - // format : 'local' - // }, - // timeSlots : { - // slots : [12], - // lowerCases : ["am","pm"], - // upperCases : ["AM","PM"] - // }, - // relativeTime : { - // units : ["seconds","minutes","hours","days","weeks","months","years"], - // now : "Now", - // before : "{value} {unit} ago", - // after : "after {value} {unit}" - // } - // }, - // currency : { - // default : "{symbol}{value}{unit}", - // long : "{prefix} {symbol}{value}{unit}{suffix}", - // short : "{symbol}{value}{unit}", - // custom : "{prefix} {symbol}{value}{unit}{suffix}", - // format : "default", - // //-- - // units : [""," thousands"," millions"," billions"," trillions"], //千,百万,十亿,万亿 - // radix : 3, // 进制,即三位一进,中文是4位一进 - // symbol : "$", // 符号 - // prefix : "USD", // 前缀 - // suffix : "", // 后缀 - // division : 3, // ,分割位 - // precision : 2, // 精度 - - // }, - // number : { - // division : 3, // , 分割位,3代表每3位添加一个, - // precision : 0 // 精度,即保留小数点位置,0代表不限 - // }, - // empty:{ - // //values : [], // 可选,定义空值,如果想让0,''也为空值,可以指定values=[0,''] - // escape : "", // 当空值时显示的备用值 - // next : 'break' // 当空值时下一步的行为: break=中止;skip=跳过 - // }, - // error : { - // //当错误时显示的内容,支持的插值变量有message=错误信息,error=错误类名,也可以是一个返回上面内容的同步函数 - // escape : null, // 默认当错误时显示空内容 - // next : 'break' // 当出错时下一步的行为: break=中止;skip=忽略 - // }, - // fileSize:{ - // brief : ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB","NB","DB"], - // whole : ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "TeraBytes", "PetaBytes", "ExaBytes", "ZetaBytes", "YottaBytes","DoggaBytes"], - // precision: 2 // 小数精度 - // } - // }, - // 改变特定数据类型的默认格式化器 - // $types:{ - // Date : dateFormatter, - // Null : value =>"", - // Undefined: value =>"", - // Error : value => "ERROR", - // Boolean : value =>value ? "True":"False", - // Number : numberFormartter - // } - // 以下可以自定义编写格式化器 - // xxxx : value => { ... }, - // xxxx : (value,$config) => { ... }, - // xxxx : (value,...args,$config) => { ... }, - // xxxx : Formatter(value,...args,$config) => { ... }, - // xxxx : FlexFormatter(value,params,$config) => { ... }, -} diff --git a/packages/cli/languages/formatters/zh.js b/packages/cli/languages/formatters/zh.js index a63c1c1..f05b6d2 100644 --- a/packages/cli/languages/formatters/zh.js +++ b/packages/cli/languages/formatters/zh.js @@ -1,7 +1,5 @@ /** - - 格式化器用来对翻译文本内容中的插值变量进行处理 如何编写格式器请参阅官网! @@ -11,6 +9,7 @@ // import { Formatter,FlexFormatter } from "./runtime" export default { + // global : true, // 是否注册到全局,false只在当前scope生效 // 直接对内置格式化器进行配置,请参阅官网文档 // $config:{ // datetime : { diff --git a/packages/cli/languages/index.js b/packages/cli/languages/index.js index 2dfc09a..005d4ec 100644 --- a/packages/cli/languages/index.js +++ b/packages/cli/languages/index.js @@ -2,7 +2,6 @@ import messageIds from "./idMap.js" // 语言ID映射文件 import runtime from "./runtime.js" // 运行时 const { translate,i18nScope } = runtime -import globalFormatters from "./formatters/global.js" // 注册到全局的格式化器 import defaultFormatters from "./formatters/zh.js" // 默认语言格式化器 const activeFormatters = defaultFormatters // 激活语言格式化器 @@ -31,7 +30,6 @@ const scopeSettings = { "namespaces": {} } const formatters = { - "*" : globalFormatters, 'zh' : defaultFormatters, 'en' : ()=>import("./formatters/en.js"), 'de' : ()=>import("./formatters/de.js") diff --git a/packages/cli/languages/runtime.js b/packages/cli/languages/runtime.js index 05c31f0..666d5f4 100644 --- a/packages/cli/languages/runtime.js +++ b/packages/cli/languages/runtime.js @@ -1659,8 +1659,8 @@ var en = { next : 'break' // 当出错时下一步的行为: break=中止;skip=忽略 }, fileSize:{ - brief : ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB","NB","DB"], - whole : ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "TeraBytes", "PetaBytes", "ExaBytes", "ZetaBytes", "YottaBytes","DoggaBytes"], + brief: ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB","NB","DB"], + whole:["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "TeraBytes", "PetaBytes", "ExaBytes", "ZetaBytes", "YottaBytes","DoggaBytes"], precision: 2 // 小数精度 } }, @@ -1965,6 +1965,8 @@ const empty = Formatter$1(function(value,escapeValue,next,$config){ { value | error('ERROR:{ error}',) } == 显示error.constructor.name + + * @param {*} value * @param {*} escapeValue * @param {*} next 下一步的行为,取值,break,ignore @@ -2171,7 +2173,11 @@ var scope = class i18nScope { if (!isFunction$2(formatter) || typeof name !== "string") { throw new TypeError("Formatter must be a function"); } - language = Array.isArray(language) ? language: language ? language.split(","): []; + language = Array.isArray(language) + ? language + : language + ? language.split(",") + : []; if (asGlobal) { this.global.registerFormatter(name, formatter, { language }); } else { diff --git a/packages/cli/templates/entry.js b/packages/cli/templates/entry.js index 26797e9..8f1cefb 100644 --- a/packages/cli/templates/entry.js +++ b/packages/cli/templates/entry.js @@ -2,7 +2,6 @@ import messageIds from "./idMap.js" // 语言ID映射文件 {{if inlineRuntime }}import runtime from "./runtime.js" // 运行时 const { translate,i18nScope } = runtime -import globalFormatters from "./formatters/global.js" // 注册到全局的格式化器 import defaultFormatters from "./formatters/{{defaultLanguage}}.js" // 默认语言格式化器 {{if defaultLanguage === activeLanguage}}const activeFormatters = defaultFormatters{{else}}import activeFormatters from "./formatters/{{activeLanguage}}.js"{{/if}} // 激活语言格式化器 {{else}}import { translate,i18nScope } from "@voerkai18n/runtime" @@ -13,7 +12,6 @@ import defaultMessages from "./{{defaultLanguage}}.js" {{else}} const messageIds = require("./idMap") {{if inlineRuntime }}const { translate,i18nScope } = require("./runtime.js") -const globalFormatters = require("./formatters/global.js") // 注册到全局的格式化器 const defaultFormatters = require("./formatters/{{defaultLanguage}}.js") {{if defaultLanguage === activeLanguage}}const activeFormatters = defaultFormatters{{else}}const activeFormatters = require("./formatters/{{activeLanguage}}.js"){{/if}} {{else}}const { translate,i18nScope } = require("@voerkai18n/runtime") @@ -26,7 +24,6 @@ const defaultMessages = require("./{{defaultLanguage}}.js") // 默认语 // 语言配置文件 const scopeSettings = {{@ settings}} const formatters = { - "*" : globalFormatters, {{each languages}}{{if $value.name == defaultLanguage}}'{{defaultLanguage}}' : defaultFormatters{{if $index !== languages.length - 1}},{{/if}} {{else if $value.name == activeLanguage}}{{if defaultLanguage !== activeLanguage}}'{{activeLanguage}}':activeFormatters{{/if}}{{if $index !== languages.length - 1}},{{/if}} {{else}}'{{$value.name}}' : ()=>import("./formatters/{{$value.name}}.js"){{if $index !== languages.length - 1}},{{'\n\t'}}{{/if}}{{/if}}{{/each}} diff --git a/packages/cli/templates/formatters.js b/packages/cli/templates/formatters.js index c6564a8..a06cf0d 100644 --- a/packages/cli/templates/formatters.js +++ b/packages/cli/templates/formatters.js @@ -1,7 +1,5 @@ /** - {{comments}} - 格式化器用来对翻译文本内容中的插值变量进行处理 如何编写格式器请参阅官网! @@ -11,7 +9,16 @@ {{if moduleType === "esm"}} // import { Formatter,FlexFormatter } from "./runtime" export default{{else}}//const { Formatter,FlexFormatter } = require("./runtime") -module.exports = {{/if}} { +module.exports = {{/if}} { + // global : true, // 简单地设置为true,代表当前所有格式化器均注册到全局,false只在当前scope生效 + // global : { // 仅将里面的格式化器注册到全局 + // $config:{... } + // xxxx : value => { ... }, + // xxxx : (value,$config) => { ... }, + // xxxx : (value,...args,$config) => { ... }, + // xxxx : Formatter(value,...args,$config) => { ... }, + // xxxx : FlexFormatter(value,params,$config) => { ... }, + //}, // 是否注册到全局,false只在当前scope生效 // 直接对内置格式化器进行配置,请参阅官网文档 // $config:{ // datetime : { diff --git a/packages/runtime/interpolate.js b/packages/runtime/interpolate.js index 12d8ccc..7caac27 100644 --- a/packages/runtime/interpolate.js +++ b/packages/runtime/interpolate.js @@ -209,6 +209,7 @@ function getFormatter(scope, activeLanguage, name) { scope.activeFormatters, scope.formatters[fallbackLanguage], // 如果指定了回退语言时,也在该回退语言中查找 scope.global.formatters[activeLanguage], // 适用于activeLanguage全局格式化器 + scope.global.formatters[fallbackLanguage], scope.global.formatters["*"], // 适用于所有语言的格式化器 ]; for (const formatters of range) { diff --git a/packages/runtime/scope.js b/packages/runtime/scope.js index d2e0e9c..2c5f62f 100644 --- a/packages/runtime/scope.js +++ b/packages/runtime/scope.js @@ -21,6 +21,7 @@ module.exports = class i18nScope { typedFormatters: {}, formatters : {}, }; + this._initiLanguages() // 如果不存在全局VoerkaI18n实例,说明当前Scope是唯一或第一个加载的作用域,则自动创建全局VoerkaI18n实例 if (!globalThis.VoerkaI18n) { const { I18nManager } = require("./"); @@ -51,6 +52,16 @@ module.exports = class i18nScope { get activeFormatters() {return this._activeFormatters} // 当前作用域激活的格式化器定义 {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () = >{}} get activeFormatterConfig(){return this._activeFormatterConfig} // 当前格式化器合并后的配置参数,参数已经合并了全局格式化器中的参数 + /** + * 对输入的语言配置进行处理 + * - 将en配置为默认回退语言 + */ + _initiLanguages(){ + Object.entries(this._languages).forEach(([name,language])=>{ + if(!language.fallback) language.fallback = "en" + }) + } + /** * 在全局注册作用域当前作用域 * @param {*} callback 注册成功后的回调 @@ -107,46 +118,23 @@ module.exports = class i18nScope { }) }) } - /** - * 注册默认文本信息加载器 - * @param {Function} 必须是异步函数或者是返回Promise - */ - registerDefaultLoader(fn) { - this.global.registerDefaultLoader(fn); - } - /** - * 获取指定语言信息 - * @param {*} language - * @returns - */ - getLanguage(language) { - let index = this._languages.findIndex((lng) => lng.name == language); - if (index !== -1) return this._languages[index]; - } - /** - * 返回是否存在指定的语言 - * @param {*} language 语言名称 - * @returns - */ - hasLanguage(language) { - return this._languages.indexOf((lang) => lang.name == language) !== -1; - } - /** - * 回退到默认语言 - */ - _fallback() { - this._messages = this._default; - this._activeLanguage = this.defaultLanguage; - } /** * 初始化格式化器 * 激活和默认语言的格式化器采用静态导入的形式,而没有采用异步块的形式,这是为了确保首次加载时的能马上读取,而不能采用延迟加载方式 * _activeFormatters={$config:{...},$types:{...},[格式化器名称]:()=>{...},[格式化器名称]:()=>{...},...}} */ - _initFormatters(newLanguage){ + _initFormatters(newLanguage){ + // 全局格式化器,用来注册到全局 + Object.entries(this._formatters).forEach(([langName,formatters])=>{ + if(formatters.global===true){ + this.registerFormatters({[langName]:formatters},true) + }else if(isPlainObject(formatters.global)){ + this.registerFormatters({[langName]:formatters.global},true) + } + }) this._activeFormatters = {} try { - if (newLanguage in this._formatters) { + if (newLanguage in this._formatters) { this._activeFormatters = this._formatters[newLanguage]; } else { if (this._debug) console.warn(`Not initialize <${newLanguage}> formatters.`); @@ -205,6 +193,39 @@ module.exports = class i18nScope { } return this._activeFormatterConfig = options } + + /** + * 注册默认文本信息加载器 + * @param {Function} 必须是异步函数或者是返回Promise + */ + registerDefaultLoader(fn) { + this.global.registerDefaultLoader(fn); + } + /** + * 获取指定语言信息 + * @param {*} language + * @returns + */ + getLanguage(language) { + let index = this._languages.findIndex((lng) => lng.name == language); + if (index !== -1) return this._languages[index]; + } + /** + * 返回是否存在指定的语言 + * @param {*} language 语言名称 + * @returns + */ + hasLanguage(language) { + return this._languages.indexOf((lang) => lang.name == language) !== -1; + } + /** + * 回退到默认语言 + */ + _fallback() { + this._messages = this._default; + this._activeLanguage = this.defaultLanguage; + } + /** * 刷新当前语言包 * @param {*} newLanguage