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,6 +3,7 @@
* 处理中文数字和货币相关
*
*/
const { FlexFormatter } = require('../dist/index.cjs')
const { isNumber } = require('./utils')
const CN_DATETIME_UNITS = ["年","季度","月","周","日","小时","分钟","秒","毫秒","微秒"]
@ -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){
@ -89,10 +91,18 @@
return prefix+result+suffix
}
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,

View File

@ -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(".")
@ -51,7 +51,6 @@ function addSplitChars(str,bits=3){
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
toCurrency,
currencyFormatter
}

View File

@ -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
}

View File

@ -2,32 +2,26 @@
*
* 处理数字相关
*
* { value | number }
* { value | number('default') }
* { value | number('regular') }
* { value | number('big') }
*
*/
const { isNumber,toNumber } = require("../utils")
const { Formatter } = require("../formatter")
/**
* 转换为数字类型
*/
function toNumber(value,defualt=0) {
try {
if (isNumber(value)) {
return parseFloat(value)
} else {
return defualt
}
} catch {
return value
}
}
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,
numberFormartter
}

View File

@ -10,8 +10,6 @@
const { getByPath,isNumber,isFunction,isPlainObject,escapeRegexpStr,safeParseJson } = require("./utils")
const { toNumber } = require("./datatypes/numeric");
/**
使用正则表达式对原始文本内容进行解析匹配后得到的便以处理的数组
@ -334,40 +332,23 @@ 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<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
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

View File

@ -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
}

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 { 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)
}

View File

@ -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
}

View File

@ -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,

View File

@ -481,7 +481,7 @@ test("翻译复数支持",async ()=>{
expect(t("我有{}个朋友",3)).toBe("I have 3 friends");
expect(t("我有{}个朋友",4)).toBe("I have 4 friends");
})
test("日期时间格式化",async ()=>{
test("日期时间格式化",async ()=>{
let zhTranslatedResults = zhDatetimes.map(v=>t(v,NOW))
let p = diffArray(zhTranslatedResults,expectZhDatetimes)
expect(zhTranslatedResults).toStrictEqual(expectZhDatetimes)
@ -491,22 +491,25 @@ test("日期时间格式化器",async ()=>{
})
test("货币格式化器",async ()=>{
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 ()=>{
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")
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")
@ -514,9 +517,8 @@ test("日期时间格式化器",async ()=>{
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")
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+")
})