update formatters

This commit is contained in:
wxzhang 2022-08-23 21:59:13 +08:00
parent c6a9b74166
commit 136e8b2ddb
10 changed files with 412 additions and 386 deletions

View File

@ -3,7 +3,8 @@
* 处理中文数字和货币相关 * 处理中文数字和货币相关
* *
*/ */
const { isNumber } = require('./utils') const { FlexFormatter } = require('../dist/index.cjs')
const { isNumber } = require('./utils')
const CN_DATETIME_UNITS = ["年","季度","月","周","日","小时","分钟","秒","毫秒","微秒"] const CN_DATETIME_UNITS = ["年","季度","月","周","日","小时","分钟","秒","毫秒","微秒"]
const CN_WEEK_DAYS = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"] const CN_WEEK_DAYS = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]
@ -72,9 +73,10 @@
* @param {*} division 分割符号位数,3代表每3个数字添加一个, * @param {*} division 分割符号位数,3代表每3个数字添加一个,
* @param {*} prefix 前缀 * @param {*} prefix 前缀
* @param {*} suffix 后缀 * @param {*} suffix 后缀
* @param {*} showWhole 显示
* @param {*} precision 小数点精确到几位 * @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 [wholeValue,decimalValue] = String(value).split(".")
let result let result
if(big){ if(big){
@ -87,12 +89,20 @@
if(decimalValue[1]) result =result+ CN_NUMBER_DIGITS[parseInt(decimalValue[1])]+"分" if(decimalValue[1]) result =result+ CN_NUMBER_DIGITS[parseInt(decimalValue[1])]+"分"
} }
return prefix+result+suffix 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, toChineseCurrency,
toChineseNumber, toChineseNumber,
toChineseBigNumber, toChineseBigNumber,
rmbFormater,
CN_DATETIME_UNITS, CN_DATETIME_UNITS,
CN_WEEK_DAYS, CN_WEEK_DAYS,
CN_SHORT_WEEK_DAYS, CN_SHORT_WEEK_DAYS,
@ -102,4 +112,4 @@
CN_NUMBER_UNITS, CN_NUMBER_UNITS,
CN_NUMBER_BIG_DIGITS, CN_NUMBER_BIG_DIGITS,
CN_NUMBER_BIG_UNITS CN_NUMBER_BIG_UNITS
} }

View File

@ -4,8 +4,8 @@
* *
*/ */
const { isNumber } = require('../utils') const { isNumber, toNumber, getByPath } = require('../utils')
const { FlexFormatter } = require("../formatter")
/** /**
* 为字符串按bits位添加一个, * 为字符串按bits位添加一个,
@ -33,8 +33,8 @@ function addSplitChars(str,bits=3){
* @param {*} format 格式模块板字符串 * @param {*} format 格式模块板字符串
* @returns * @returns
*/ */
function toCurrency(value,params={}){ function toCurrency(value,params={},$config={}){
let {symbol="",division=3,prefix="",precision=2,suffix="",unit=0,unitName="",radix=3,format="{symbol}{value}{unit}"} = params let {symbol="",division=3,prefix="",precision=2,suffix="",unit=0,radix=3,format="{symbol}{value}{unit}"} = params
// 1. 分离出整数和小数部分 // 1. 分离出整数和小数部分
let [wholeDigits,decimalDigits] = String(value).split(".") let [wholeDigits,decimalDigits] = String(value).split(".")
@ -50,8 +50,7 @@ function addSplitChars(str,bits=3){
decimalDigits=wholeDigits.substring(wholeDigits,wholeDigits.length-radix*unit)+decimalDigits decimalDigits=wholeDigits.substring(wholeDigits,wholeDigits.length-radix*unit)+decimalDigits
wholeDigits = wholeDigits.substring(0,wholeDigits.length-radix*unit) wholeDigits = wholeDigits.substring(0,wholeDigits.length-radix*unit)
if(wholeDigits=="") wholeDigits = "0" if(wholeDigits=="") wholeDigits = "0"
} }
// 3. 添加分割符号 // 3. 添加分割符号
let result = [] let result = []
result.push(addSplitChars(wholeDigits,division)) result.push(addSplitChars(wholeDigits,division))
@ -68,13 +67,36 @@ function addSplitChars(str,bits=3){
result.push(`.${decimalDigits}`) result.push(`.${decimalDigits}`)
} }
// 5. 模板替换 // 5. 模板替换
const unitName = getByPath($config,`units`,[])[unit] || ""
return format.replace("{value}",result.join("")) return format.replace("{value}",result.join(""))
.replace("{symbol}",symbol) .replace("{symbol}",symbol)
.replace("{prefix}",prefix) .replace("{prefix}",prefix)
.replace("{suffix}",suffix) .replace("{suffix}",suffix)
.replace("{unit}",unitName) .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
} }

View File

@ -3,22 +3,9 @@
处理日期时间相关 处理日期时间相关
*/ */
const { isFunction,replaceAll } = require('../utils') const { isFunction,replaceAll,toDate } = require('../utils')
const { Formatter } = require('../formatter'); 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 * @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 = { module.exports = {
toDate, toDate,
formatTime, formatTime,
formatDatetime, formatDatetime,
createDateTimeFormatter createDateTimeFormatter,
dateFormatter,
quarterFormatter,
monthFormatter,
weekdayFormatter,
timeFormatter
} }

View File

@ -2,32 +2,26 @@
* *
* 处理数字相关 * 处理数字相关
* *
* { value | number }
* { value | number('default') }
* { value | number('regular') }
* { value | number('big') }
*
*/ */
const { Formatter } = require("../formatter") const { isNumber,toNumber } = require("../utils")
/** const { Formatter } = require("../formatter")
* 转换为数字类型 const { toCurrency } = require("./currency")
*/
function toNumber(value,defualt=0) {
try {
if (isNumber(value)) {
return parseFloat(value)
} else {
return defualt
}
} catch {
return value
}
}
const numberFormartter = Formatter(function(value,precision,division,$config){ const numberFormartter = Formatter(function(value,precision,division,$config){
return toCurrency(value, { division, precision}) return toCurrency(value, { division, precision},$config)
},{ },{
normalize: toNumber, normalize: toNumber,
params:["precision","division"], params:["precision","division"],
configKey: "number" configKey: "number"
}) })
module.exports = {
toNumber,
module.exports = {
numberFormartter numberFormartter
} }

View File

@ -10,8 +10,6 @@
const { getByPath,isNumber,isFunction,isPlainObject,escapeRegexpStr,safeParseJson } = require("./utils") 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 return r
} ,{}) } ,{})
// 3. 从格式化器中传入的参数具有最高优先级,覆盖默认参数 // 3. 从格式化器中传入的参数具有最高优先级,覆盖默认参数
if(args.length==1) { // 无参调用 if(args.length==2 && isPlainObject(args[0])){ // 一个参数且是{}
Object.assign(params,{format:'default'}) Object.assign(finalParams,{format:"custom"},args[0])
}else if(args.length==2 && isPlainObject(args[0])){ // 一个参数且是{}
Object.assign(params,args[0])
}else{ // 位置参数,如果是空则代表 }else{ // 位置参数,如果是空则代表
for(let i=0; i<args.length-1; i++){ for(let i=0; i<args.length-1; i++){
if(args[i]!==undefined) params[options.params[i]] = args[i] if(args[i]!==undefined) finalParams[options.params[i]] = args[i]
} }
} }
return fn.call(this,value,params,$config) if(finalParams.format in $config){
finalParams.format = $config[finalParams.format]
}
return fn.call(this,value,finalParams,$config)
},{...options,params:null}) // 变参工式化器需要指定params=null },{...options,params:null}) // 变参工式化器需要指定params=null
return $formatter return $formatter
} }
const currencyFormatter = createFlexFormatter((value,params={},$config)=>{
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 = { module.exports = {
createFormatter, createFormatter,

View File

@ -4,84 +4,11 @@
*/ */
const { isFunction,isPlainObject} = require("../utils") const { isFunction,isPlainObject} = require("../utils")
const { toDate,formatDatetime,formatTime,createDateTimeFormatter } = require("../datatypes/datetime")
const { Formatter } = require("../formatter") 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 // 货币格式化器, CNY $13,456.00
@ -92,55 +19,55 @@ const weekdayFormatter = createDateTimeFormatter({
* { value | currency('long',2) } 亿元 * { value | currency('long',2) } 亿元
* { value | currency({symbol,unit,prefix,precision,suffix}) } * { value | currency({symbol,unit,prefix,precision,suffix}) }
*/ */
const currencyFormatter = Formatter((value,...args) =>{ // const currencyFormatter = Formatter((value,...args) =>{
// 1. 最后一个参数是格式化器的参数,不同语言不一样 // // 1. 最后一个参数是格式化器的参数,不同语言不一样
let $config = args[args.length-1] // let $config = args[args.length-1]
// 2. 从语言配置中读取默认参数 // // 2. 从语言配置中读取默认参数
let params = { // let params = {
unit : 0, // unit : 0,
radix : $config.radix, // 进制,取值,0-4, // radix : $config.radix, // 进制,取值,0-4,
symbol : $config.symbol, // 符号,即三位一进制中文是是4位一进 // symbol : $config.symbol, // 符号,即三位一进制中文是是4位一进
prefix : $config.prefix, // 前缀 // prefix : $config.prefix, // 前缀
suffix : $config.suffix, // 后缀 // suffix : $config.suffix, // 后缀
division : $config.division, // ,分割位 // division : $config.division, // ,分割位
precision : $config.precision, // 精度 // precision : $config.precision, // 精度
format : $config.format, // 模板字符串 // format : $config.format, // 模板字符串
} // }
// 3. 从格式化器中传入的参数具有最高优先级,覆盖默认参数 // // 3. 从格式化器中传入的参数具有最高优先级,覆盖默认参数
if(args.length==1) { // 无参调用 // if(args.length==1) { // 无参调用
Object.assign(params,{format:'default'}) // Object.assign(params,{format:'default'})
}else if(args.length==2 && isPlainObject(args[0])){ // 一个参数且是{} // }else if(args.length==2 && isPlainObject(args[0])){ // 一个参数且是{}
Object.assign(params,{format:$config.custom},args[0]) // Object.assign(params,{format:$config.custom},args[0])
}else if(args.length==2){ // }else if(args.length==2){
// 一个字符串参数只能是default,long,short, 或者是一个模板字符串,如"{symbol}{value}{unit}" // // 一个字符串参数只能是default,long,short, 或者是一个模板字符串,如"{symbol}{value}{unit}"
Object.assign(params,{format:args[0]}) // Object.assign(params,{format:args[0]})
}else if(args.length==3){// 2个参数分别是format,unit // }else if(args.length==3){// 2个参数分别是format,unit
Object.assign(params,{format:args[0],unit:args[1]}) // Object.assign(params,{format:args[0],unit:args[1]})
}else if(args.length==4){// 3个参数分别是format,unit,precision // }else if(args.length==4){// 3个参数分别是format,unit,precision
Object.assign(params,{format:args[0],unit:args[1],precision:args[2]}) // Object.assign(params,{format:args[0],unit:args[1],precision:args[2]})
} // }
// 4. 检查参数正确性 // // 4. 检查参数正确性
params.unit = parseInt(params.unit) || 0 // params.unit = parseInt(params.unit) || 0
if(params.unit>4) params.unit = 4 // if(params.unit>4) params.unit = 4
if(params.unit<0) params.unit = 0 // if(params.unit<0) params.unit = 0
// 当指定unit大于0时取消小数点精度控制 // // 当指定unit大于0时取消小数点精度控制
// 例 value = 12345678.99 默认情况下精度是2,如果unit=1,则显示1234.47+, // // 例 value = 12345678.99 默认情况下精度是2,如果unit=1,则显示1234.47+,
// 将params.precision=0取消精度限制就可以显示1234.567899万,从而保证完整的精度 // // 将params.precision=0取消精度限制就可以显示1234.567899万,从而保证完整的精度
// 除非显示将precision设置为>2的值 // // 除非显示将precision设置为>2的值
if(params.unit>0 && params.precision==2){ // if(params.unit>0 && params.precision==2){
params.precision = 0 // params.precision = 0
} // }
// 模板字符串 // // 模板字符串
if(params.format in $config){ // if(params.format in $config){
params.format = $config[params.format] // params.format = $config[params.format]
} // }
params.unitName =(Array.isArray($config.units) && params.unit> 0 && params.unit<$config.units.length) ? $config.units[params.unit] : "" // params.unitName =(Array.isArray($config.units) && params.unit> 0 && params.unit<$config.units.length) ? $config.units[params.unit] : ""
return toCurrency(value,params) // return toCurrency(value,params)
},{ // },{
normalize: toNumber, // normalize: toNumber,
configKey: "currency" // configKey: "currency"
}) // })
module.exports = { module.exports = {
@ -197,10 +124,7 @@ module.exports = {
}, },
number : { number : {
division : 3, // , 分割位3代表每3位添加一个, division : 3, // , 分割位3代表每3位添加一个,
precision : 0, // 精度,即保留小数点位置,0代表不限 precision : 0 // 精度,即保留小数点位置,0代表不限
default : null, // 默认数字写法
regular : null, // 正规数字,不同的语言可能理解不一样,在中文中对应一、二、三
big : null // 正则数字,在中文中对应的是大写壹、貳、參
}, },
empty:{ empty:{
//values : [], // 可选定义空值如果想让0,''也为空值可以指定values=[0,''] //values : [], // 可选定义空值如果想让0,''也为空值可以指定values=[0,'']
@ -224,12 +148,12 @@ module.exports = {
Null : value =>"", Null : value =>"",
Undefined: value =>"", Undefined: value =>"",
Error : value => "ERROR", Error : value => "ERROR",
Boolean : value =>value ? "True":"False" Boolean : value =>value ? "True":"False",
Number : numberFormartter
}, },
// 以下是格式化定义 // 以下是格式化定义
// ******************* 日期 ******************* // ******************* 日期 *******************
date : dateFormatter, date : dateFormatter,
year : value => toDate(value).getFullYear(),
quarter : quarterFormatter, quarter : quarterFormatter,
month : monthFormatter, month : monthFormatter,
weekday : weekdayFormatter, weekday : weekdayFormatter,
@ -237,6 +161,6 @@ module.exports = {
time : timeFormatter, time : timeFormatter,
// ******************* 货币 ******************* // ******************* 货币 *******************
currency : currencyFormatter, currency : currencyFormatter,
// 数字,如,使用分割符 // ******************* 数字 *******************
number : numberFormartter number : numberFormartter
} }

View File

@ -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 { 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 = { module.exports = {
// 配置参数: 格式化器函数的最后一个参数就是该配置参数 // 配置参数: 格式化器函数的最后一个参数就是该配置参数
@ -54,10 +52,7 @@ module.exports = {
}, },
number : { number : {
division : 4, division : 4,
precision : 0, precision : 0
default : null, // 默认数字写法
short : null, // 正规数字,不同的语言可能理解不一样,在中文中对应一、二、三
long : null // 正则数字,在中文中对应的是大写壹、貳、參
} }
}, },
$types: { $types: {
@ -65,6 +60,6 @@ module.exports = {
}, },
// 中文货币big=true代表大写形式 // 中文货币big=true代表大写形式
rmb : (value,big,unit="元",prefix,suffix)=>toChineseCurrency(value,{big,prefix,suffix,unit}), rmb : (value,big,unit="元",prefix,suffix)=>toChineseCurrency(value,{big,prefix,suffix,unit}),
// 中文数字,如一千二百三十一 // // 中文数字,如一千二百三十一
number :(value,isBig)=>toChineseNumber(value,isBig) chineseNumber :(value,isBig)=>toChineseNumber(value,isBig)
} }

View File

@ -1,8 +1,9 @@
const {DataTypes,getDataTypeName,isPlainObject,isFunction,isNumber,isNothing,deepMerge,deepMixin} = require("./utils") const {DataTypes,getDataTypeName,isPlainObject,isFunction,isNumber,isNothing,deepMerge,deepMixin} = require("./utils")
const {getInterpolatedVars,replaceInterpolatedVars} = require("./interpolate") const {getInterpolatedVars,replaceInterpolatedVars} = require("./interpolate")
const {createFormatter,Formatter} = require("./formatter") const {createFormatter,Formatter,FlexFormatter,createFlexFormatter} = require("./formatter")
const { toDate } = require("./datatypes/datetime") const { toDate } = require("./datatypes/datetime")
const { toNumber } = require("./datatypes/numeric") const { toNumber } = require("./datatypes/numeric")
const EventEmitter = require("./eventemitter") const EventEmitter = require("./eventemitter")
const inlineFormatters = require("./formatters") const inlineFormatters = require("./formatters")
const i18nScope = require("./scope") const i18nScope = require("./scope")
@ -158,12 +159,12 @@ const defaultLanguageSettings = {
} }
module.exports ={ module.exports ={
toDate,
toNumber,
isNumber, isNumber,
isNothing, isNothing,
isPlainObject, isPlainObject,
isFunction, isFunction,
toDate,
toNumber,
deepMerge, deepMerge,
deepMixin, deepMixin,
getInterpolatedVars, getInterpolatedVars,
@ -173,5 +174,7 @@ module.exports ={
i18nScope, i18nScope,
createFormatter, createFormatter,
Formatter, Formatter,
createFlexFormatter,
FlexFormatter,
getDataTypeName getDataTypeName
} }

View File

@ -228,6 +228,36 @@ function safeParseJson(str){
return JSON.parse(str) return JSON.parse(str)
} }
const DataTypes = ["String","Number","Boolean","Object","Array","Function","Error","Symbol","RegExp","Date","Null","Undefined","Set","Map","WeakSet","WeakMap"] 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 ={ module.exports ={
DataTypes, DataTypes,
@ -235,6 +265,9 @@ module.exports ={
isFunction, isFunction,
isNumber, isNumber,
isNothing, isNothing,
toNumber,
toDate,
toBoolean,
deepClone, deepClone,
deepMerge, deepMerge,
deepMixin, deepMixin,

View File

@ -332,192 +332,194 @@ scope.registerFormatters({
describe("翻译函数",()=>{ describe("翻译函数",()=>{
beforeEach(() => { beforeEach(() => {
scope.change("zh") scope.change("zh")
}); });
test("获取翻译内容中的插值变量",done=>{ test("获取翻译内容中的插值变量",done=>{
const results = getInterpolatedVars("中华人民共和国成立于{date | year(1,2) | time('a','b') | rel }年,首都是{city}市"); const results = getInterpolatedVars("中华人民共和国成立于{date | year(1,2) | time('a','b') | rel }年,首都是{city}市");
expect(results.length).toEqual(2); expect(results.length).toEqual(2);
// //
expect(results[0].name).toEqual("date"); expect(results[0].name).toEqual("date");
expect(results[0].formatters.length).toEqual(3); expect(results[0].formatters.length).toEqual(3);
// year(1,2) // year(1,2)
expect(results[0].formatters[0].name).toEqual("year"); expect(results[0].formatters[0].name).toEqual("year");
expect(results[0].formatters[0].args).toEqual([1,2]); expect(results[0].formatters[0].args).toEqual([1,2]);
// time('a','b') // time('a','b')
expect(results[0].formatters[1].name).toEqual("time"); expect(results[0].formatters[1].name).toEqual("time");
expect(results[0].formatters[1].args).toEqual(["a","b"]); expect(results[0].formatters[1].args).toEqual(["a","b"]);
// rel // rel
expect(results[0].formatters[2].name).toEqual("rel"); expect(results[0].formatters[2].name).toEqual("rel");
expect(results[0].formatters[2].args).toEqual([]); expect(results[0].formatters[2].args).toEqual([]);
expect(results[1].name).toEqual("city"); expect(results[1].name).toEqual("city");
expect(results[1].formatters.length).toEqual(0); expect(results[1].formatters.length).toEqual(0);
done() done()
}) })
test("获取翻译内容中定义了重复的插值变量",done=>{ test("获取翻译内容中定义了重复的插值变量",done=>{
const results = getInterpolatedVars("{a}{a}{a|x}{a|x}{a|x|y}{a|x|y}"); const results = getInterpolatedVars("{a}{a}{a|x}{a|x}{a|x|y}{a|x|y}");
expect(results.length).toEqual(3); expect(results.length).toEqual(3);
expect(results[0].name).toEqual("a"); expect(results[0].name).toEqual("a");
expect(results[0].formatters.length).toEqual(0); expect(results[0].formatters.length).toEqual(0);
expect(results[1].name).toEqual("a"); expect(results[1].name).toEqual("a");
expect(results[1].formatters.length).toEqual(1); expect(results[1].formatters.length).toEqual(1);
expect(results[1].formatters[0].name).toEqual("x"); expect(results[1].formatters[0].name).toEqual("x");
expect(results[1].formatters[0].args).toEqual([]); expect(results[1].formatters[0].args).toEqual([]);
expect(results[2].name).toEqual("a"); expect(results[2].name).toEqual("a");
expect(results[2].formatters.length).toEqual(2); expect(results[2].formatters.length).toEqual(2);
expect(results[2].formatters[0].name).toEqual("x"); expect(results[2].formatters[0].name).toEqual("x");
expect(results[2].formatters[0].args).toEqual([]); expect(results[2].formatters[0].args).toEqual([]);
expect(results[2].formatters[1].name).toEqual("y"); expect(results[2].formatters[1].name).toEqual("y");
expect(results[2].formatters[1].args).toEqual([]); expect(results[2].formatters[1].args).toEqual([]);
done() done()
}) })
test("替换翻译内容的位置插值变量",done=>{ test("替换翻译内容的位置插值变量",done=>{
expect(t("{}{}{}",1,2,3)).toBe("123"); expect(t("{}{}{}",1,2,3)).toBe("123");
expect(t("{a}{b}{c}",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)).toBe("123");
expect(t("{a|xxx}{b|dd}{c|}",1,2,3,4,5,6)).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{}"); expect(t("{ a|}{b|dd}{c|}{}",1,2,3)).toBe("123{}");
// 中文状态下true和false被转换成中文的"是"和"否" // 中文状态下true和false被转换成中文的"是"和"否"
expect(t("{}{}{}",1,"2",true)).toBe("12是"); expect(t("{}{}{}",1,"2",true)).toBe("12是");
expect(t("{|double}{}{}",1,"2",true)).toBe("22是"); expect(t("{|double}{}{}",1,"2",true)).toBe("22是");
done() done()
}) })
test("替换翻译内容的命名插值变量",done=>{ test("替换翻译内容的命名插值变量",done=>{
expect(t("{a}{b}{c}",{a:11,b:22,c:33})).toBe("112233"); 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"); expect(t("{a}{b}{c}{a}{b}{c}",{a:1,b:"2",c:3})).toBe("123123");
done() 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");
// padStart和trim格式化器只是字符串的原型方法不需要额外定义可以直接使用
expect(t("{a|padStart(10)}",{a:"123"})).toBe(" 123");
expect(t("{a|padStart(10)|trim}",{a:"123"})).toBe("123");
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|}",{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|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)}",{a:"123"})).toBe(" 123");
expect(t("{a|padStart(10)|trim}",{a:"123"})).toBe("123"); expect(t("{a|padStart(10)|trim}",{a:"123"})).toBe("123");
done() done()
}) })
test("命名插值变量使用格式化器",done=>{
test("切换到其他语言时的自动匹配同名格式化器",async ()=>{ // 提供无效的格式化器,直接忽略
expect(t("{a}",{a:true})).toBe("是"); expect(t("{a|x}{b|x|y}{c|}",{a:1,b:2,c:3})).toBe("123");
expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("《毛泽东选集》是毛泽东思想的重要载体"); expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126");
await scope.change("en") // 默认的字符串格式化器,不需要定义使用字符串方法
expect(t("{a}",{a:false})).toBe("False"); expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126");
expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("<毛泽东选集>是毛泽东思想的重要载体"); 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") test("切换到其他语言时的自动匹配同名格式化器",async ()=>{
expect(t("{a}",{a:true})).toBe("是");
expect(t("{value}",123)).toBe("123") expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("《毛泽东选集》是毛泽东思想的重要载体");
expect(t("{value | number}",123)).toBe("123") await scope.change("en")
expect(t("{value | number}",123456789)).toBe("123,456,789") expect(t("{a}",{a:false})).toBe("False");
expect(t("{value | number}",123456789.8888)).toBe("123,456,789.8888") expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("<毛泽东选集>是毛泽东思想的重要载体");
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 ()=>{
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+")
})
}) })