From 136e8b2ddbf83536560c152019c7b658228f4bfa Mon Sep 17 00:00:00 2001 From: wxzhang Date: Tue, 23 Aug 2022 21:59:13 +0800 Subject: [PATCH] update formatters --- packages/runtime/datatypes/chinese.js | 22 +- packages/runtime/datatypes/currency.js | 38 ++- packages/runtime/datatypes/datetime.js | 92 +++++-- packages/runtime/datatypes/numeric.js | 30 +-- packages/runtime/formatter.js | 39 +-- packages/runtime/formatters/en.js | 186 ++++---------- packages/runtime/formatters/zh.js | 11 +- packages/runtime/index.js | 9 +- packages/runtime/utils.js | 33 +++ test/runtime.test.js | 338 +++++++++++++------------ 10 files changed, 412 insertions(+), 386 deletions(-) diff --git a/packages/runtime/datatypes/chinese.js b/packages/runtime/datatypes/chinese.js index 62d5425..4e77574 100644 --- a/packages/runtime/datatypes/chinese.js +++ b/packages/runtime/datatypes/chinese.js @@ -3,7 +3,8 @@ * 处理中文数字和货币相关 * */ - const { isNumber } = require('./utils') + const { FlexFormatter } = require('../dist/index.cjs') +const { isNumber } = require('./utils') const CN_DATETIME_UNITS = ["年","季度","月","周","日","小时","分钟","秒","毫秒","微秒"] const CN_WEEK_DAYS = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"] @@ -72,9 +73,10 @@ * @param {*} division 分割符号位数,3代表每3个数字添加一个,号 * @param {*} prefix 前缀 * @param {*} suffix 后缀 + * @param {*} showWhole 显示 * @param {*} precision 小数点精确到几位 */ - function toChineseCurrency(value,{big=false,prefix="",unit="元",suffix=""}={}){ +function toChineseCurrency(value,{big=false,prefix="",unit="元",suffix="",precision=2,showWhole=true}={}){ let [wholeValue,decimalValue] = String(value).split(".") let result if(big){ @@ -87,12 +89,20 @@ if(decimalValue[1]) result =result+ CN_NUMBER_DIGITS[parseInt(decimalValue[1])]+"分" } return prefix+result+suffix - } - - module.exports ={ +} + +const rmbFormater = FlexFormatter((value,params,$config)=>{ + return toChineseCurrency(value,params,$config) +},{ + params:["big","prefix","unit","suffix","precision","showWhole"], + configKey:"rmb" +}) + +module.exports ={ toChineseCurrency, toChineseNumber, toChineseBigNumber, + rmbFormater, CN_DATETIME_UNITS, CN_WEEK_DAYS, CN_SHORT_WEEK_DAYS, @@ -102,4 +112,4 @@ CN_NUMBER_UNITS, CN_NUMBER_BIG_DIGITS, CN_NUMBER_BIG_UNITS - } \ No newline at end of file +} \ No newline at end of file diff --git a/packages/runtime/datatypes/currency.js b/packages/runtime/datatypes/currency.js index 152c4b2..fa32560 100644 --- a/packages/runtime/datatypes/currency.js +++ b/packages/runtime/datatypes/currency.js @@ -4,8 +4,8 @@ * */ -const { isNumber } = require('../utils') - +const { isNumber, toNumber, getByPath } = require('../utils') +const { FlexFormatter } = require("../formatter") /** * 为字符串按bits位添加一个, @@ -33,8 +33,8 @@ function addSplitChars(str,bits=3){ * @param {*} format 格式模块板字符串 * @returns */ - function toCurrency(value,params={}){ - let {symbol="",division=3,prefix="",precision=2,suffix="",unit=0,unitName="",radix=3,format="{symbol}{value}{unit}"} = params + function toCurrency(value,params={},$config={}){ + let {symbol="",division=3,prefix="",precision=2,suffix="",unit=0,radix=3,format="{symbol}{value}{unit}"} = params // 1. 分离出整数和小数部分 let [wholeDigits,decimalDigits] = String(value).split(".") @@ -50,8 +50,7 @@ function addSplitChars(str,bits=3){ decimalDigits=wholeDigits.substring(wholeDigits,wholeDigits.length-radix*unit)+decimalDigits wholeDigits = wholeDigits.substring(0,wholeDigits.length-radix*unit) if(wholeDigits=="") wholeDigits = "0" - } - + } // 3. 添加分割符号 let result = [] result.push(addSplitChars(wholeDigits,division)) @@ -68,13 +67,36 @@ function addSplitChars(str,bits=3){ result.push(`.${decimalDigits}`) } // 5. 模板替换 + const unitName = getByPath($config,`units`,[])[unit] || "" return format.replace("{value}",result.join("")) .replace("{symbol}",symbol) .replace("{prefix}",prefix) .replace("{suffix}",suffix) .replace("{unit}",unitName) } +const currencyFormatter = FlexFormatter((value,params={},$config)=>{ + params.unit = parseInt(params.unit) || 0 + if(params.unit>$config.units.length-1) params.unit = $config.units.length-1 + if(params.unit<0) params.unit = 0 + // 当指定unit大于0时取消小数点精度控制 + // 例 value = 12345678.99 默认情况下精度是2,如果unit=1,则显示1234.47+, + // 将params.precision=0取消精度限制就可以显示1234.567899万,从而保证完整的精度 + // 除非显式将precision设置为>2的值 + if(params.unit>0 && params.precision==2){ + params.precision = 0 + } + return toCurrency(value,params,$config) +},{ + normalize: toNumber, + params : ["format","unit","precision","prefix","suffix","division","symbol","radix"], + configKey: "currency" +},{ + format:"default", + unit:0 // 小数点精度控制,0代表不控制 +}) - module.exports = { - toCurrency + +module.exports = { + toCurrency, + currencyFormatter } \ No newline at end of file diff --git a/packages/runtime/datatypes/datetime.js b/packages/runtime/datatypes/datetime.js index e22acf9..aad855b 100644 --- a/packages/runtime/datatypes/datetime.js +++ b/packages/runtime/datatypes/datetime.js @@ -3,22 +3,9 @@ 处理日期时间相关 */ -const { isFunction,replaceAll } = require('../utils') +const { isFunction,replaceAll,toDate } = require('../utils') const { Formatter } = require('../formatter'); -/** - * 格式化日期 - * 将值转换为Date类型 - * @param {*} value - */ - function toDate(value) { - try { - return value instanceof Date ? value : new Date(value) - } catch { - return parseInt(value) - } -} - /** * 获取一天中的时间段 * @param {*} hour 小时,取值0-23 @@ -156,9 +143,84 @@ function createDateTimeFormatter(options={},transformer){ } +/** + * 日期格式化器 + * - format取值:local,long,short,iso,gmt,utc,<模板字符串> + * - 默认值由$config.datetime.date.format指定 + */ + const dateFormatter = createDateTimeFormatter({ + normalize: toDate, + params : ["format"], + configKey: "datetime.date", + presets : { + local: value=>value.toLocaleString(), + iso : value=>value.toISOString(), + utc : value=>value.toUTCString(), + gmt : value=>value.toGMTString() + } +},formatDatetime) + + +/** + * 季度格式化器 + * - format: long,short,number + * - 默认值是 short + */ +const quarterFormatter = createDateTimeFormatter({ + normalize : value=>{ + const month = value.getMonth() + 1 + return Math.floor( ( month % 3 == 0 ? ( month / 3 ) : (month / 3 + 1 ) )) + }, + params : ["format"], + configKey: "datetime.quarter" +},(quarter,format)=>format[quarter-1]) + +/** + * 月份格式化器 + * - format: long,short,number + * - 默认值是 short + */ +const monthFormatter = createDateTimeFormatter({ + normalize: value=> value.getMonth() + 1, + params : ["format"], + configKey: "datetime.month" +},(month,format)=>format[month-1]) + +/** + * 周格式化器 + * - format: long,short,number + * - 默认值是 long + */ +const weekdayFormatter = createDateTimeFormatter({ + normalize: value=> value.getDay(), + params : ["format"], + configKey: "datetime.weekday" +},(day,format)=>format[day]) + +/** + * 时间格式化器 + * - format取值:local,long,short,timestamp,<模板字符串> + * - 默认值由$config.datetime.time.format指定 + */ + const timeFormatter = createDateTimeFormatter({ + normalize : toDate, + params : ["format"], + configKey : "datetime.time", + presets : { + local : value=>value.toLocaleTimeString(), + timestamp: value=>value.getTime() + } +},formatTime) + + module.exports = { toDate, formatTime, formatDatetime, - createDateTimeFormatter + createDateTimeFormatter, + dateFormatter, + quarterFormatter, + monthFormatter, + weekdayFormatter, + timeFormatter } \ No newline at end of file diff --git a/packages/runtime/datatypes/numeric.js b/packages/runtime/datatypes/numeric.js index 65224af..cdf80a4 100644 --- a/packages/runtime/datatypes/numeric.js +++ b/packages/runtime/datatypes/numeric.js @@ -2,32 +2,26 @@ * * 处理数字相关 * + * { value | number } + * { value | number('default') } + * { value | number('regular') } + * { value | number('big') } + * */ - const { Formatter } = require("../formatter") -/** - * 转换为数字类型 - */ - function toNumber(value,defualt=0) { - try { - if (isNumber(value)) { - return parseFloat(value) - } else { - return defualt - } - } catch { - return value - } -} +const { isNumber,toNumber } = require("../utils") +const { Formatter } = require("../formatter") +const { toCurrency } = require("./currency") const numberFormartter = Formatter(function(value,precision,division,$config){ - return toCurrency(value, { division, precision}) + return toCurrency(value, { division, precision},$config) },{ normalize: toNumber, params:["precision","division"], configKey: "number" }) -module.exports = { - toNumber, + + +module.exports = { numberFormartter } \ No newline at end of file diff --git a/packages/runtime/formatter.js b/packages/runtime/formatter.js index c42d877..d925131 100644 --- a/packages/runtime/formatter.js +++ b/packages/runtime/formatter.js @@ -10,8 +10,6 @@ const { getByPath,isNumber,isFunction,isPlainObject,escapeRegexpStr,safeParseJson } = require("./utils") -const { toNumber } = require("./datatypes/numeric"); - /** 使用正则表达式对原始文本内容进行解析匹配后得到的便以处理的数组 @@ -334,42 +332,25 @@ const createFlexFormatter = function(fn,options={},defaultParams={}){ return r } ,{}) // 3. 从格式化器中传入的参数具有最高优先级,覆盖默认参数 - if(args.length==1) { // 无参调用 - Object.assign(params,{format:'default'}) - }else if(args.length==2 && isPlainObject(args[0])){ // 一个参数且是{} - Object.assign(params,args[0]) + if(args.length==2 && isPlainObject(args[0])){ // 一个参数且是{} + Object.assign(finalParams,{format:"custom"},args[0]) }else{ // 位置参数,如果是空则代表 for(let i=0; i{ - params.unit = parseInt(params.unit) || 0 - if(params.unit>4) params.unit = 4 - if(params.unit<0) params.unit = 0 - // 当指定unit大于0时取消小数点精度控制 - // 例 value = 12345678.99 默认情况下精度是2,如果unit=1,则显示1234.47+, - // 将params.precision=0取消精度限制就可以显示1234.567899万,从而保证完整的精度 - // 除非显式将precision设置为>2的值 - if(params.unit>0 && params.precision==2){ - params.precision = 0 - } - return toCurrency(value,params) -},{ - normalize: toNumber, - params : ["format","unit","precision","prefix","suffix","division","radix"], - configKey: "currency" -},{ - format:"default", - unit:0 // 小数点精度控制,0代表不控制 -}) -const FlexFormatter =createFlexFormatter + +const FlexFormatter = createFlexFormatter module.exports = { createFormatter, diff --git a/packages/runtime/formatters/en.js b/packages/runtime/formatters/en.js index 250513b..b988d99 100644 --- a/packages/runtime/formatters/en.js +++ b/packages/runtime/formatters/en.js @@ -4,84 +4,11 @@ */ const { isFunction,isPlainObject} = require("../utils") -const { toDate,formatDatetime,formatTime,createDateTimeFormatter } = require("../datatypes/datetime") const { Formatter } = require("../formatter") +const { dateFormatter,quarterFormatter,monthFormatter,weekdayFormatter,timeFormatter } = require("../datatypes/datetime") +const { numberFormartter } = require("../datatypes/numeric") +const { currencyFormatter } = require("../datatypes/currency") -const { toCurrency } = require("../datatypes/currency") -const { toNumber,numberFormartter } = require("../datatypes/numeric") - - - - - -/** - * 日期格式化器 - * - format取值:local,long,short,iso,gmt,utc,<模板字符串> - * - 默认值由$config.datetime.date.format指定 - */ -const dateFormatter = createDateTimeFormatter({ - normalize: toDate, - params : ["format"], - configKey: "datetime.date", - presets : { - local: value=>value.toLocaleString(), - iso : value=>value.toISOString(), - utc : value=>value.toUTCString(), - gmt : value=>value.toGMTString() - } -},formatDatetime) - - -/** - * 季度格式化器 - * - format: long,short,number - * - 默认值是 short - */ -const quarterFormatter = createDateTimeFormatter({ - normalize : value=>{ - const month = value.getMonth() + 1 - return Math.floor( ( month % 3 == 0 ? ( month / 3 ) : (month / 3 + 1 ) )) - }, - params : ["format"], - configKey: "datetime.quarter" -},(quarter,format)=>format[quarter-1]) - -/** - * 月份格式化器 - * - format: long,short,number - * - 默认值是 short - */ -const monthFormatter = createDateTimeFormatter({ - normalize: value=> value.getMonth() + 1, - params : ["format"], - configKey: "datetime.month" -},(month,format)=>format[month-1]) - -/** - * 周格式化器 - * - format: long,short,number - * - 默认值是 long - */ -const weekdayFormatter = createDateTimeFormatter({ - normalize: value=> value.getDay(), - params : ["format"], - configKey: "datetime.weekday" -},(day,format)=>format[day]) - -/** - * 时间格式化器 - * - format取值:local,long,short,timestamp,<模板字符串> - * - 默认值由$config.datetime.time.format指定 - */ - const timeFormatter = createDateTimeFormatter({ - normalize : toDate, - params : ["format"], - configKey : "datetime.time", - presets : { - local : value=>value.toLocaleTimeString(), - timestamp: value=>value.getTime() - } -},formatTime) // 货币格式化器, CNY $13,456.00 @@ -92,55 +19,55 @@ const weekdayFormatter = createDateTimeFormatter({ * { value | currency('long',2) } 亿元 * { value | currency({symbol,unit,prefix,precision,suffix}) } */ -const currencyFormatter = Formatter((value,...args) =>{ - // 1. 最后一个参数是格式化器的参数,不同语言不一样 - let $config = args[args.length-1] - // 2. 从语言配置中读取默认参数 - let params = { - unit : 0, - radix : $config.radix, // 进制,取值,0-4, - symbol : $config.symbol, // 符号,即三位一进制,中文是是4位一进 - prefix : $config.prefix, // 前缀 - suffix : $config.suffix, // 后缀 - division : $config.division, // ,分割位 - precision : $config.precision, // 精度 - format : $config.format, // 模板字符串 - } - // 3. 从格式化器中传入的参数具有最高优先级,覆盖默认参数 - if(args.length==1) { // 无参调用 - Object.assign(params,{format:'default'}) - }else if(args.length==2 && isPlainObject(args[0])){ // 一个参数且是{} - Object.assign(params,{format:$config.custom},args[0]) - }else if(args.length==2){ - // 一个字符串参数,只能是default,long,short, 或者是一个模板字符串,如"{symbol}{value}{unit}" - Object.assign(params,{format:args[0]}) - }else if(args.length==3){// 2个参数,分别是format,unit - Object.assign(params,{format:args[0],unit:args[1]}) - }else if(args.length==4){// 3个参数,分别是format,unit,precision - Object.assign(params,{format:args[0],unit:args[1],precision:args[2]}) - } - // 4. 检查参数正确性 - params.unit = parseInt(params.unit) || 0 - if(params.unit>4) params.unit = 4 - if(params.unit<0) params.unit = 0 - // 当指定unit大于0时取消小数点精度控制 - // 例 value = 12345678.99 默认情况下精度是2,如果unit=1,则显示1234.47+, - // 将params.precision=0取消精度限制就可以显示1234.567899万,从而保证完整的精度 - // 除非显示将precision设置为>2的值 - if(params.unit>0 && params.precision==2){ - params.precision = 0 - } +// const currencyFormatter = Formatter((value,...args) =>{ +// // 1. 最后一个参数是格式化器的参数,不同语言不一样 +// let $config = args[args.length-1] +// // 2. 从语言配置中读取默认参数 +// let params = { +// unit : 0, +// radix : $config.radix, // 进制,取值,0-4, +// symbol : $config.symbol, // 符号,即三位一进制,中文是是4位一进 +// prefix : $config.prefix, // 前缀 +// suffix : $config.suffix, // 后缀 +// division : $config.division, // ,分割位 +// precision : $config.precision, // 精度 +// format : $config.format, // 模板字符串 +// } +// // 3. 从格式化器中传入的参数具有最高优先级,覆盖默认参数 +// if(args.length==1) { // 无参调用 +// Object.assign(params,{format:'default'}) +// }else if(args.length==2 && isPlainObject(args[0])){ // 一个参数且是{} +// Object.assign(params,{format:$config.custom},args[0]) +// }else if(args.length==2){ +// // 一个字符串参数,只能是default,long,short, 或者是一个模板字符串,如"{symbol}{value}{unit}" +// Object.assign(params,{format:args[0]}) +// }else if(args.length==3){// 2个参数,分别是format,unit +// Object.assign(params,{format:args[0],unit:args[1]}) +// }else if(args.length==4){// 3个参数,分别是format,unit,precision +// Object.assign(params,{format:args[0],unit:args[1],precision:args[2]}) +// } +// // 4. 检查参数正确性 +// params.unit = parseInt(params.unit) || 0 +// if(params.unit>4) params.unit = 4 +// if(params.unit<0) params.unit = 0 +// // 当指定unit大于0时取消小数点精度控制 +// // 例 value = 12345678.99 默认情况下精度是2,如果unit=1,则显示1234.47+, +// // 将params.precision=0取消精度限制就可以显示1234.567899万,从而保证完整的精度 +// // 除非显示将precision设置为>2的值 +// if(params.unit>0 && params.precision==2){ +// params.precision = 0 +// } - // 模板字符串 - if(params.format in $config){ - params.format = $config[params.format] - } - params.unitName =(Array.isArray($config.units) && params.unit> 0 && params.unit<$config.units.length) ? $config.units[params.unit] : "" - return toCurrency(value,params) -},{ - normalize: toNumber, - configKey: "currency" -}) +// // 模板字符串 +// if(params.format in $config){ +// params.format = $config[params.format] +// } +// params.unitName =(Array.isArray($config.units) && params.unit> 0 && params.unit<$config.units.length) ? $config.units[params.unit] : "" +// return toCurrency(value,params) +// },{ +// normalize: toNumber, +// configKey: "currency" +// }) module.exports = { @@ -197,10 +124,7 @@ module.exports = { }, number : { division : 3, // , 分割位,3代表每3位添加一个, - precision : 0, // 精度,即保留小数点位置,0代表不限 - default : null, // 默认数字写法 - regular : null, // 正规数字,不同的语言可能理解不一样,在中文中对应一、二、三 - big : null // 正则数字,在中文中对应的是大写壹、貳、參 + precision : 0 // 精度,即保留小数点位置,0代表不限 }, empty:{ //values : [], // 可选,定义空值,如果想让0,''也为空值,可以指定values=[0,''] @@ -224,12 +148,12 @@ module.exports = { Null : value =>"", Undefined: value =>"", Error : value => "ERROR", - Boolean : value =>value ? "True":"False" + Boolean : value =>value ? "True":"False", + Number : numberFormartter }, // 以下是格式化定义 // ******************* 日期 ******************* date : dateFormatter, - year : value => toDate(value).getFullYear(), quarter : quarterFormatter, month : monthFormatter, weekday : weekdayFormatter, @@ -237,6 +161,6 @@ module.exports = { time : timeFormatter, // ******************* 货币 ******************* currency : currencyFormatter, - // 数字,如,使用分割符 + // ******************* 数字 ******************* number : numberFormartter } \ No newline at end of file diff --git a/packages/runtime/formatters/zh.js b/packages/runtime/formatters/zh.js index 9b44e28..c5a7c3b 100644 --- a/packages/runtime/formatters/zh.js +++ b/packages/runtime/formatters/zh.js @@ -4,8 +4,6 @@ */ const { toChineseCurrency,toChineseNumber,CN_DATETIME_UNITS,CN_WEEK_DAYS,CN_SHORT_WEEK_DAYS, CN_MONTH_NAMES, CN_SHORT_MONTH_NAMES} = require("../cnutils") -const { toDate } = require("../datatypes/datetime") -const { toCurrency } = require("../datatypes/currency") module.exports = { // 配置参数: 格式化器函数的最后一个参数就是该配置参数 @@ -54,10 +52,7 @@ module.exports = { }, number : { division : 4, - precision : 0, - default : null, // 默认数字写法 - short : null, // 正规数字,不同的语言可能理解不一样,在中文中对应一、二、三 - long : null // 正则数字,在中文中对应的是大写壹、貳、參 + precision : 0 } }, $types: { @@ -65,6 +60,6 @@ module.exports = { }, // 中文货币,big=true代表大写形式 rmb : (value,big,unit="元",prefix,suffix)=>toChineseCurrency(value,{big,prefix,suffix,unit}), - // 中文数字,如一千二百三十一 - number :(value,isBig)=>toChineseNumber(value,isBig) + // // 中文数字,如一千二百三十一 + chineseNumber :(value,isBig)=>toChineseNumber(value,isBig) } \ No newline at end of file diff --git a/packages/runtime/index.js b/packages/runtime/index.js index 121035f..48e5ffc 100644 --- a/packages/runtime/index.js +++ b/packages/runtime/index.js @@ -1,8 +1,9 @@ const {DataTypes,getDataTypeName,isPlainObject,isFunction,isNumber,isNothing,deepMerge,deepMixin} = require("./utils") const {getInterpolatedVars,replaceInterpolatedVars} = require("./interpolate") -const {createFormatter,Formatter} = require("./formatter") +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 i18nScope = require("./scope") @@ -158,12 +159,12 @@ const defaultLanguageSettings = { } module.exports ={ - toDate, - toNumber, isNumber, isNothing, isPlainObject, isFunction, + toDate, + toNumber, deepMerge, deepMixin, getInterpolatedVars, @@ -173,5 +174,7 @@ module.exports ={ i18nScope, createFormatter, Formatter, + createFlexFormatter, + FlexFormatter, getDataTypeName } \ No newline at end of file diff --git a/packages/runtime/utils.js b/packages/runtime/utils.js index 00e9afc..6b6924e 100644 --- a/packages/runtime/utils.js +++ b/packages/runtime/utils.js @@ -228,6 +228,36 @@ function safeParseJson(str){ return JSON.parse(str) } const DataTypes = ["String","Number","Boolean","Object","Array","Function","Error","Symbol","RegExp","Date","Null","Undefined","Set","Map","WeakSet","WeakMap"] +/** + * 转换为数字类型 + */ + function toNumber(value,defualt=0) { + try { + if (isNumber(value)) { + return parseFloat(value) + } else { + return defualt + } + } catch { + return value + } +} + +/** + * 将值转换为Date类型 + * @param {*} value + */ + function toDate(value) { + try { + return value instanceof Date ? value : new Date(value) + } catch { + return parseInt(value) + } +} + +function toBoolean(value){ + return !!value +} module.exports ={ DataTypes, @@ -235,6 +265,9 @@ module.exports ={ isFunction, isNumber, isNothing, + toNumber, + toDate, + toBoolean, deepClone, deepMerge, deepMixin, diff --git a/test/runtime.test.js b/test/runtime.test.js index 8d932c1..dae57e7 100644 --- a/test/runtime.test.js +++ b/test/runtime.test.js @@ -332,192 +332,194 @@ scope.registerFormatters({ describe("翻译函数",()=>{ beforeEach(() => { scope.change("zh") - }); -test("获取翻译内容中的插值变量",done=>{ - const results = getInterpolatedVars("中华人民共和国成立于{date | year(1,2) | time('a','b') | rel }年,首都是{city}市"); - expect(results.length).toEqual(2); - // - expect(results[0].name).toEqual("date"); - expect(results[0].formatters.length).toEqual(3); - // year(1,2) - expect(results[0].formatters[0].name).toEqual("year"); - expect(results[0].formatters[0].args).toEqual([1,2]); - // time('a','b') - expect(results[0].formatters[1].name).toEqual("time"); - expect(results[0].formatters[1].args).toEqual(["a","b"]); - // rel - expect(results[0].formatters[2].name).toEqual("rel"); - expect(results[0].formatters[2].args).toEqual([]); - - expect(results[1].name).toEqual("city"); - expect(results[1].formatters.length).toEqual(0); + }); + test("获取翻译内容中的插值变量",done=>{ + const results = getInterpolatedVars("中华人民共和国成立于{date | year(1,2) | time('a','b') | rel }年,首都是{city}市"); + expect(results.length).toEqual(2); + // + expect(results[0].name).toEqual("date"); + expect(results[0].formatters.length).toEqual(3); + // year(1,2) + expect(results[0].formatters[0].name).toEqual("year"); + expect(results[0].formatters[0].args).toEqual([1,2]); + // time('a','b') + expect(results[0].formatters[1].name).toEqual("time"); + expect(results[0].formatters[1].args).toEqual(["a","b"]); + // rel + expect(results[0].formatters[2].name).toEqual("rel"); + expect(results[0].formatters[2].args).toEqual([]); + + expect(results[1].name).toEqual("city"); + expect(results[1].formatters.length).toEqual(0); - done() -}) + done() + }) -test("获取翻译内容中定义了重复的插值变量",done=>{ - const results = getInterpolatedVars("{a}{a}{a|x}{a|x}{a|x|y}{a|x|y}"); - expect(results.length).toEqual(3); - expect(results[0].name).toEqual("a"); - expect(results[0].formatters.length).toEqual(0); - - expect(results[1].name).toEqual("a"); - expect(results[1].formatters.length).toEqual(1); - expect(results[1].formatters[0].name).toEqual("x"); - expect(results[1].formatters[0].args).toEqual([]); + test("获取翻译内容中定义了重复的插值变量",done=>{ + const results = getInterpolatedVars("{a}{a}{a|x}{a|x}{a|x|y}{a|x|y}"); + expect(results.length).toEqual(3); + expect(results[0].name).toEqual("a"); + expect(results[0].formatters.length).toEqual(0); + + expect(results[1].name).toEqual("a"); + expect(results[1].formatters.length).toEqual(1); + expect(results[1].formatters[0].name).toEqual("x"); + expect(results[1].formatters[0].args).toEqual([]); - expect(results[2].name).toEqual("a"); - expect(results[2].formatters.length).toEqual(2); - expect(results[2].formatters[0].name).toEqual("x"); - expect(results[2].formatters[0].args).toEqual([]); - expect(results[2].formatters[1].name).toEqual("y"); - expect(results[2].formatters[1].args).toEqual([]); - - done() -}) + expect(results[2].name).toEqual("a"); + expect(results[2].formatters.length).toEqual(2); + expect(results[2].formatters[0].name).toEqual("x"); + expect(results[2].formatters[0].args).toEqual([]); + expect(results[2].formatters[1].name).toEqual("y"); + expect(results[2].formatters[1].args).toEqual([]); + + done() + }) -test("替换翻译内容的位置插值变量",done=>{ - expect(t("{}{}{}",1,2,3)).toBe("123"); - expect(t("{a}{b}{c}",1,2,3)).toBe("123"); - // 定义了一些无效的格式化器,直接忽略 - expect(t("{a|xxx}{b|dd}{c|}",1,2,3)).toBe("123"); - expect(t("{a|xxx}{b|dd}{c|}",1,2,3,4,5,6)).toBe("123"); - expect(t("{ a|}{b|dd}{c|}{}",1,2,3)).toBe("123{}"); - // 中文状态下true和false被转换成中文的"是"和"否" - expect(t("{}{}{}",1,"2",true)).toBe("12是"); - expect(t("{|double}{}{}",1,"2",true)).toBe("22是"); - done() -}) + test("替换翻译内容的位置插值变量",done=>{ + expect(t("{}{}{}",1,2,3)).toBe("123"); + expect(t("{a}{b}{c}",1,2,3)).toBe("123"); + // 定义了一些无效的格式化器,直接忽略 + expect(t("{a|xxx}{b|dd}{c|}",1,2,3)).toBe("123"); + expect(t("{a|xxx}{b|dd}{c|}",1,2,3,4,5,6)).toBe("123"); + expect(t("{ a|}{b|dd}{c|}{}",1,2,3)).toBe("123{}"); + // 中文状态下true和false被转换成中文的"是"和"否" + expect(t("{}{}{}",1,"2",true)).toBe("12是"); + expect(t("{|double}{}{}",1,"2",true)).toBe("22是"); + done() + }) -test("替换翻译内容的命名插值变量",done=>{ - expect(t("{a}{b}{c}",{a:11,b:22,c:33})).toBe("112233"); - expect(t("{a}{b}{c}{a}{b}{c}",{a:1,b:"2",c:3})).toBe("123123"); - done() -}) + test("替换翻译内容的命名插值变量",done=>{ + expect(t("{a}{b}{c}",{a:11,b:22,c:33})).toBe("112233"); + expect(t("{a}{b}{c}{a}{b}{c}",{a:1,b:"2",c:3})).toBe("123123"); + done() + }) -test("命名插值变量使用格式化器",done=>{ - // 提供无效的格式化器,直接忽略 - expect(t("{a|x}{b|x|y}{c|}",{a:1,b:2,c:3})).toBe("123"); - expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126"); - // padStart和trim格式化器只是字符串的原型方法,不需要额外定义可以直接使用 - expect(t("{a|padStart(10)}",{a:"123"})).toBe(" 123"); - expect(t("{a|padStart(10)|trim}",{a:"123"})).toBe("123"); - done() -}) - - -test("命名插值变量使用格式化器",done=>{ + test("命名插值变量使用格式化器",done=>{ // 提供无效的格式化器,直接忽略 expect(t("{a|x}{b|x|y}{c|}",{a:1,b:2,c:3})).toBe("123"); expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126"); - // 默认的字符串格式化器,不需要定义使用字符串方法 - expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126"); + // padStart和trim格式化器只是字符串的原型方法,不需要额外定义可以直接使用 expect(t("{a|padStart(10)}",{a:"123"})).toBe(" 123"); expect(t("{a|padStart(10)|trim}",{a:"123"})).toBe("123"); done() - }) + }) - -test("切换到其他语言时的自动匹配同名格式化器",async ()=>{ - expect(t("{a}",{a:true})).toBe("是"); - expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("《毛泽东选集》是毛泽东思想的重要载体"); - await scope.change("en") - expect(t("{a}",{a:false})).toBe("False"); - expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("<毛泽东选集>是毛泽东思想的重要载体"); -}) + test("命名插值变量使用格式化器",done=>{ + // 提供无效的格式化器,直接忽略 + expect(t("{a|x}{b|x|y}{c|}",{a:1,b:2,c:3})).toBe("123"); + expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126"); + // 默认的字符串格式化器,不需要定义使用字符串方法 + expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126"); + expect(t("{a|padStart(10)}",{a:"123"})).toBe(" 123"); + expect(t("{a|padStart(10)|trim}",{a:"123"})).toBe("123"); + done() + }) -test("位置插值翻译文本内容",async ()=>{ - const now = new Date() - expect(t("你好")).toBe("你好"); - expect(t("现在是{ value | }",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); - - // 经babel自动码换后,文本内容会根据idMap自动转为id - expect(t("1")).toBe("你好"); - expect(t("2",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); - - await scope.change("en") - - expect(t("你好")).toBe("hello"); - expect(t("现在是{ value | }",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); - expect(t("1")).toBe("hello"); - expect(t("2",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); -}) - -test("命名插值翻译文本内容",async ()=>{ - const now = new Date() - expect(t("你好")).toBe("你好"); - expect(t("现在是{ value | }",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); - - await scope.change("en") - expect(t("你好")).toBe("hello"); - expect(t("现在是{ value | }",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); - // 使用idMap - expect(t("1")).toBe("hello"); - expect(t("2",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); -}) - - -test("当没有对应的语言翻译时,保持原始输出",async ()=>{ - expect(t("我是中国人")).toBe("我是中国人"); - await scope.change("en") - expect(t("我是中国人")).toBe("我是中国人"); -}) - - -test("切换到未知语言时回退到默认语言",async ()=>{ - expect(t("我是中国人")).toBe("我是中国人"); - expect(async ()=>await scope.change("xn")).rejects.toThrow(Error); - expect(t("我是中国人")).toBe("我是中国人"); -}) - - -test("翻译复数支持",async ()=>{ - await scope.change("en") - expect(t("我有{}个朋友",0)).toBe("I have no friends"); - expect(t("我有{}个朋友",1)).toBe("I have one friends"); - expect(t("我有{}个朋友",2)).toBe("I have two friends"); - expect(t("我有{}个朋友",3)).toBe("I have 3 friends"); - expect(t("我有{}个朋友",4)).toBe("I have 4 friends"); -}) -test("日期时间格式化器",async ()=>{ - let zhTranslatedResults = zhDatetimes.map(v=>t(v,NOW)) - let p = diffArray(zhTranslatedResults,expectZhDatetimes) - expect(zhTranslatedResults).toStrictEqual(expectZhDatetimes) - await scope.change("en") - let enTranslatedResults = zhDatetimes.map(v=>t(v,NOW)) - expect(enTranslatedResults).toStrictEqual(expectEnDatetimes) - }) - - - test("货币格式化器",async ()=>{ - let zhMoneysResults = zhMoneys.map(v=>t(v,MONEY)) - expect(zhMoneysResults).toStrictEqual(expectZhMoneys) - await scope.change("en") - let enMoneysResults = enMoneys.map(v=>t(v,MONEY)) - expect(enMoneysResults).toStrictEqual(expectEnMoneys) - }) - - test("数字格式化器",async ()=>{ - - expect(t("{value}",123)).toBe("123") - expect(t("{value | number}",123)).toBe("123") - expect(t("{value | number}",123456789)).toBe("1,2345,6789") - expect(t("{value | number}",123456789.8888)).toBe("1,2345,6789.8888") - expect(t("{value | number(3)}",123456789.8888)).toBe("1,2345,6789.889") - expect(t("{value | number(3,2)}",123456789.8888)).toBe("12,34,567,89.889") - await scope.change("en") - - expect(t("{value}",123)).toBe("123") - expect(t("{value | number}",123)).toBe("123") - expect(t("{value | number}",123456789)).toBe("123,456,789") - expect(t("{value | number}",123456789.8888)).toBe("123,456,789.8888") - expect(t("{value | number(3)}",123456789.8888)).toBe("1,2345,6789.889") - expect(t("{value | number(3,2)}",123456789.8888)).toBe("12,34,567,89.889") + test("切换到其他语言时的自动匹配同名格式化器",async ()=>{ + expect(t("{a}",{a:true})).toBe("是"); + expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("《毛泽东选集》是毛泽东思想的重要载体"); + await scope.change("en") + expect(t("{a}",{a:false})).toBe("False"); + expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("<毛泽东选集>是毛泽东思想的重要载体"); + }) - }) + + test("位置插值翻译文本内容",async ()=>{ + const now = new Date() + expect(t("你好")).toBe("你好"); + expect(t("现在是{ value | }",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); + + // 经babel自动码换后,文本内容会根据idMap自动转为id + expect(t("1")).toBe("你好"); + expect(t("2",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); + + await scope.change("en") + + expect(t("你好")).toBe("hello"); + expect(t("现在是{ value | }",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); + expect(t("1")).toBe("hello"); + expect(t("2",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); + }) + + test("命名插值翻译文本内容",async ()=>{ + const now = new Date() + expect(t("你好")).toBe("你好"); + expect(t("现在是{ value | }",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); + + await scope.change("en") + expect(t("你好")).toBe("hello"); + expect(t("现在是{ value | }",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); + // 使用idMap + expect(t("1")).toBe("hello"); + expect(t("2",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`); + }) + + + test("当没有对应的语言翻译时,保持原始输出",async ()=>{ + expect(t("我是中国人")).toBe("我是中国人"); + await scope.change("en") + expect(t("我是中国人")).toBe("我是中国人"); + }) + + + test("切换到未知语言时回退到默认语言",async ()=>{ + expect(t("我是中国人")).toBe("我是中国人"); + expect(async ()=>await scope.change("xn")).rejects.toThrow(Error); + expect(t("我是中国人")).toBe("我是中国人"); + }) + + + test("翻译复数支持",async ()=>{ + await scope.change("en") + expect(t("我有{}个朋友",0)).toBe("I have no friends"); + expect(t("我有{}个朋友",1)).toBe("I have one friends"); + expect(t("我有{}个朋友",2)).toBe("I have two friends"); + expect(t("我有{}个朋友",3)).toBe("I have 3 friends"); + expect(t("我有{}个朋友",4)).toBe("I have 4 friends"); + }) + test("日期时间格式化",async ()=>{ + let zhTranslatedResults = zhDatetimes.map(v=>t(v,NOW)) + let p = diffArray(zhTranslatedResults,expectZhDatetimes) + expect(zhTranslatedResults).toStrictEqual(expectZhDatetimes) + await scope.change("en") + let enTranslatedResults = zhDatetimes.map(v=>t(v,NOW)) + expect(enTranslatedResults).toStrictEqual(expectEnDatetimes) + }) + + + test("货币格式化",async ()=>{ + const v= t("商品价格: { value | currency({symbol:'¥¥',prefix:'人民币:'})}",MONEY) // 长格式: 万元 + + let zhMoneysResults = zhMoneys.map(v=>t(v,MONEY)) + const p = diffArray(zhMoneysResults,expectZhMoneys) + expect(zhMoneysResults).toStrictEqual(expectZhMoneys) + await scope.change("en") + let enMoneysResults = enMoneys.map(v=>t(v,MONEY)) + expect(enMoneysResults).toStrictEqual(expectEnMoneys) + }) + + test("数字格式化",async ()=>{ + + expect(t("{value}",123)).toBe("123") + expect(t("{value | number}",123)).toBe("123") + expect(t("{value | number}",123456789)).toBe("1,2345,6789") + expect(t("{value | number}",123456789.8888)).toBe("1,2345,6789.8888") + expect(t("{value | number(3)}",123456789.8888)).toBe("1,2345,6789.889+") + expect(t("{value | number(3,2)}",123456789.8888)).toBe("1,23,45,67,89.889+") + + await scope.change("en") + + expect(t("{value}",123)).toBe("123") + expect(t("{value | number }",123)).toBe("123") + expect(t("{value | number }",123456789)).toBe("123,456,789") + expect(t("{value | number }",123456789.8888)).toBe("123,456,789.8888") + expect(t("{value | number(3) }",123456789.8888)).toBe("123,456,789.889+") + expect(t("{value | number(3,2) }",123456789.8888)).toBe("1,23,45,67,89.889+") + }) })