update formatters
This commit is contained in:
parent
ccad9d45c3
commit
ba9f9bfd49
@ -3,7 +3,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
const { toDate,toCurrency,formatDatetime,formatTime,Formatter } = require("../utils")
|
||||
const { toDate,toCurrency,toNumber,formatDatetime,formatTime,Formatter } = require("../utils")
|
||||
|
||||
// 日期格式化器
|
||||
// format取字符串"long","short","local","iso","gmt","utc"或者日期模块字符串
|
||||
@ -43,7 +43,17 @@ const dateFormatter = Formatter((value,format,$config)=>{
|
||||
params : ['format'],
|
||||
configKey: "datetime.date"
|
||||
})
|
||||
|
||||
// 季度格式化器 format= 0=短格式 1=长格式
|
||||
const mquarterFormatter = Formatter((value,format,$config)=>{
|
||||
const month = value.getMonth() + 1
|
||||
const quarter = Math.floor( ( month % 3 == 0 ? ( month / 3 ) : (month / 3 + 1 ) ))
|
||||
if(format<0 && format>1) format = 0
|
||||
return format==0 ? $config.shortNames[month] : (format==1 ? $config.shortNames[month] : month+1)
|
||||
},{
|
||||
normalize: toDate,
|
||||
params : ['format'],
|
||||
configKey: "datetime.quarter"
|
||||
})
|
||||
|
||||
// 月份格式化器 format可以取值0,1,2,也可以取字符串long,short,number
|
||||
const monthFormatter = Formatter((value,format,$config)=>{
|
||||
@ -104,15 +114,17 @@ const timeFormatter = Formatter((value,format,$config)=>{
|
||||
})
|
||||
|
||||
// 货币格式化器, CNY $13,456.00
|
||||
const currencyFormatter = Formatter((value, unit,prefix ,suffix, division,precision) =>{
|
||||
return toCurrency(value, { unit,division, prefix, precision,suffix })
|
||||
const currencyFormatter = Formatter((value, symbol,prefix ,suffix, division,precision) =>{
|
||||
return toCurrency(value, { symbol,division, prefix, precision,suffix })
|
||||
},{
|
||||
normalize: toNumber,
|
||||
params:["prefix","suffix", "division","precision"],
|
||||
params:["symbol","prefix","suffix", "division","precision"],
|
||||
configKey: "currency"
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
|
||||
|
||||
module.exports = {
|
||||
// 配置参数
|
||||
$config:{
|
||||
datetime : {
|
||||
@ -122,6 +134,10 @@ const currencyFormatter = Formatter((value, unit,prefix ,suffix, division,precis
|
||||
short : "MM/DD",
|
||||
format : "local"
|
||||
},
|
||||
quarter : {
|
||||
names : ["Q1","Q2","Q3","Q4"],
|
||||
shortNames : ["Q1","Q2","Q3","Q4"]
|
||||
},
|
||||
month:{
|
||||
names : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
||||
shortNames : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"],
|
||||
@ -137,9 +153,9 @@ const currencyFormatter = Formatter((value, unit,prefix ,suffix, division,precis
|
||||
short : "HH:mm:ss",
|
||||
format : 'local'
|
||||
},
|
||||
}
|
||||
},
|
||||
currency : {
|
||||
unit : "$", // 单位
|
||||
symbol : "$", // 符号
|
||||
prefix : "", // 前缀
|
||||
suffix : "", // 后缀
|
||||
division : 3, // ,分割位
|
||||
@ -150,14 +166,14 @@ const currencyFormatter = Formatter((value, unit,prefix ,suffix, division,precis
|
||||
precision : 2
|
||||
},
|
||||
empty:{
|
||||
//values : [], // 可选,定义空值,如果想让0,''也为空值,可以指定values=[0,'']
|
||||
escape : "", // 当空值时显示的备用值
|
||||
next : 'break' // 当空值时下一步的行为: break=中止;skip=跳过
|
||||
//values : [], // 可选,定义空值,如果想让0,''也为空值,可以指定values=[0,'']
|
||||
escape : "", // 当空值时显示的备用值
|
||||
next : 'break' // 当空值时下一步的行为: break=中止;skip=跳过
|
||||
},
|
||||
error : {
|
||||
//当错误时显示的内容,支持的插值变量有message=错误信息,error=错误类名,也可以是一个返回上面内容的同步函数
|
||||
escape : null, // 默认当错误时显示空内容
|
||||
next : 'break' // 当出错时下一步的行为: break=中止;skip=忽略
|
||||
next : 'break' // 当出错时下一步的行为: break=中止;skip=忽略
|
||||
},
|
||||
fileSize:{
|
||||
//brief: ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB","NB","DB"],
|
||||
|
@ -16,6 +16,11 @@ module.exports = {
|
||||
short : "MM/DD",
|
||||
format : 'YYYY年MM月DD日 HH点mm分ss秒'
|
||||
},
|
||||
quarter : {
|
||||
names : ["一季度","二季度","三季度","四季度"],
|
||||
shortNames : ["Q1","Q2","Q3","Q4"],
|
||||
format : 0 // 0-短格式,1-长格式
|
||||
},
|
||||
month:{
|
||||
names : CN_MONTH_NAMES,
|
||||
shortNames : CN_SHORT_MONTH_NAMES,
|
||||
@ -33,7 +38,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
currency : {
|
||||
unit : "¥",
|
||||
symbol : "¥",
|
||||
prefix : "",
|
||||
suffix : "元",
|
||||
division : 4,
|
||||
@ -49,9 +54,7 @@ module.exports = {
|
||||
Boolean : value =>value ? "是":"否"
|
||||
|
||||
},
|
||||
// 货币
|
||||
currency : (value,prefix = "¥",suffix="", division = 4, precision = 2) => toCurrency(value, { division, prefix, precision,suffix }),
|
||||
// 中文货币,big=true代表大写形式
|
||||
// 中文货币,big=true代表大写形式
|
||||
capitalizeCurrency:(value,big,unit="元",prefix,suffix)=>toChineseCurrency(value,{big,prefix,suffix,unit}),
|
||||
// 中文数字,如一千二百三十一
|
||||
number:(value,isBig)=>toChineseNumber(value,isBig)
|
||||
|
@ -386,23 +386,17 @@ function addDefaultFormatters(formatters){
|
||||
*
|
||||
*/
|
||||
function wrapperFormatters(scope,activeLanguage,formatters){
|
||||
let wrappedFormatters = []
|
||||
addDefaultFormatters(formatters)
|
||||
let wrappedFormatters = []
|
||||
for(let [name,args] of formatters){
|
||||
if(name){
|
||||
const func = getFormatter(scope,activeLanguage,name)
|
||||
if(isFunction(func)){
|
||||
let fn = (value) => {
|
||||
// 每一个格式式化器均支持若干输入参数,但是在使用时,可以支持可选参数
|
||||
// 比currency(value,prefix,suffix, division,precision)支持4个参数,但是在使用时支持可选参数
|
||||
// {value | currency} 或 {value | currency('元')} 或 {value | currency('元',"整")}
|
||||
// 为了让格式化器能比较方便地处理最后一个配置参数,当格式化器函数指定了paramCount参数来声明其支持的参数后
|
||||
// 在此就自动初始参数个数,这样在currency函数中,就可以使用这样的currency(value,prefix,suffix, division,precision,options)
|
||||
// 不管开发者使用时的输入参数数是多少均可以保证在currency函数中总是可以得到有效的options参数
|
||||
if(func.paramCount && args.length < func.paramCount ){
|
||||
args.push(...new Array(parseInt(func.paramCount)-args.length).fill(undefined))
|
||||
const func = getFormatter(scope,activeLanguage,name)
|
||||
if(isFunction(func)){
|
||||
const fn = (value) => {
|
||||
if(func.configurable){ // 如果格式化器函数是使用createFormatter创建的
|
||||
return func.call(scope,value,...args,scope.activeFormatterConfig)
|
||||
}else{ // 不可配置的格式化器不会传入格式化器配置
|
||||
return func.call(scope,value,...args)
|
||||
}
|
||||
return func.call(scope,value,...args,scope.activeFormatterOptions)
|
||||
}
|
||||
fn.$name = name
|
||||
wrappedFormatters.push(fn)
|
||||
@ -441,8 +435,9 @@ function getFormattedValue(scope,activeLanguage,formatters,value,template){
|
||||
if(defaultFormatter){
|
||||
return executeFormatter(value,[defaultFormatter],scope,template)
|
||||
}
|
||||
}
|
||||
value = executeFormatter(value,formatterFuncs,scope,template)
|
||||
}else{
|
||||
value = executeFormatter(value,formatterFuncs,scope,template)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
|
@ -40,10 +40,10 @@ module.exports = class i18nScope {
|
||||
if (!globalThis.VoerkaI18n) {
|
||||
const { I18nManager } = require("./");
|
||||
globalThis.VoerkaI18n = new I18nManager({
|
||||
debug: this._debug,
|
||||
debug : this._debug,
|
||||
defaultLanguage: this.defaultLanguage,
|
||||
activeLanguage: this.activeLanguage,
|
||||
languages: options.languages,
|
||||
activeLanguage : this.activeLanguage,
|
||||
languages : options.languages,
|
||||
});
|
||||
}
|
||||
this._global = globalThis.VoerkaI18n;
|
||||
@ -64,7 +64,7 @@ module.exports = class i18nScope {
|
||||
get global() { return this._global;} // 引用全局VoerkaI18n配置,注册后自动引用
|
||||
get formatters() { return this._formatters;} // 当前作用域的所有格式化器定义 {<语言名称>: {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () => {}}}
|
||||
get activeFormatters() {return this._activeFormatters} // 当前作用域激活的格式化器定义 {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () = >{}}
|
||||
get activeFormatterOptions(){return this._activeFormatterOptions} // 当前格式化器合并后的配置参数,参数已经合并了全局格式化器中的参数
|
||||
get activeFormatterConfig(){return this._activeFormatterConfig} // 当前格式化器合并后的配置参数,参数已经合并了全局格式化器中的参数
|
||||
|
||||
/**
|
||||
* 在全局注册作用域当前作用域
|
||||
@ -119,12 +119,12 @@ module.exports = class i18nScope {
|
||||
* @param {*} formatters ={"*",zh:{...},en:{...}}
|
||||
* @returns
|
||||
*/
|
||||
registerFormatters(formatters,isGlobal=false) {
|
||||
Object.entries(formatters).forEach(([language,fns]=>{
|
||||
registerFormatters(formatters,asGlobal=false) {
|
||||
Object.entries(formatters).forEach(([language,fns])=>{
|
||||
Object.entries(fns).forEach(([name,formatter])=>{
|
||||
this.registerFormatter(name,formatter,{language})
|
||||
this.registerFormatter(name,formatter,{language,global:asGlobal})
|
||||
})
|
||||
}))
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 注册默认文本信息加载器
|
||||
@ -222,7 +222,7 @@ module.exports = class i18nScope {
|
||||
if(this.debug) console.error(`Error while generate <${language}> formatter options: `,e)
|
||||
if(!options) options = this._activeFormatters.$config || {}
|
||||
}
|
||||
return this._activeFormatterOptions = options
|
||||
return this._activeFormatterConfig = options
|
||||
}
|
||||
/**
|
||||
* 刷新当前语言包
|
||||
|
@ -138,7 +138,7 @@ function toDate(value) {
|
||||
function toNumber(value,defualt=0) {
|
||||
try {
|
||||
if (isNumber(value)) {
|
||||
return parseInt(value)
|
||||
return parseFloat(value)
|
||||
} else {
|
||||
return defualt
|
||||
}
|
||||
@ -156,7 +156,7 @@ function toNumber(value,defualt=0) {
|
||||
* @param {*} precision 小数点精确到几位,0-自动
|
||||
* @returns
|
||||
*/
|
||||
function toCurrency(value,{unit="",division=3,prefix="",precision=0,suffix=""}={}){
|
||||
function toCurrency(value,{symbol="",division=3,prefix="",precision=0,suffix=""}={}){
|
||||
let [wholeValue,decimalValue] = String(value).split(".")
|
||||
let result = []
|
||||
for(let i=0;i<wholeValue.length;i++){
|
||||
@ -169,7 +169,7 @@ function toNumber(value,defualt=0) {
|
||||
}
|
||||
result.push(`.${decimalValue}`)
|
||||
}
|
||||
return `${prefix}${unit}${result.join("")}${suffix}`
|
||||
return `${prefix}${symbol}${result.join("")}${suffix}`
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,6 +253,7 @@ function formatDatetime(value,templ="YYYY/MM/DD HH:mm:ss"){
|
||||
vars.forEach(([key,value])=>result = replaceAll(result,key,value))
|
||||
return result
|
||||
}
|
||||
|
||||
function formatTime(value,templ="HH:mm:ss"){
|
||||
const v = toDate(value)
|
||||
const hourNum = v.getHours()
|
||||
@ -348,7 +349,7 @@ function replaceAll(str,findValue,replaceValue){
|
||||
configKey : null // 声明该格式化器在$config中的路径,支持简单的使用.的路径语法
|
||||
})
|
||||
|
||||
// 最后一个参数是传入activeFormatterOptions参数
|
||||
// 最后一个参数是传入activeFormatterConfig参数
|
||||
const wrappedFn = function(value,...args){
|
||||
let finalValue = value
|
||||
// 1. 输入值规范处理,主要是进行类型转换,确保输入的数据类型及相关格式的正确性,提高数据容错性
|
||||
@ -357,18 +358,18 @@ function replaceAll(str,findValue,replaceValue){
|
||||
finalValue = opts.normalize(finalValue)
|
||||
}catch{}
|
||||
}
|
||||
// 2. 读取activeFormatterOptions
|
||||
let activeFormatterOpts = args.length>0 ? args[args.length-1] : {}
|
||||
if(!isPlainObject( activeFormatterOpts)) activeFormatterOpts ={}
|
||||
// 2. 读取activeFormatterConfig
|
||||
let activeFormatterConfigs = args.length>0 ? args[args.length-1] : {}
|
||||
if(!isPlainObject( activeFormatterConfigs)) activeFormatterConfigs ={}
|
||||
// 3. 从当前语言的激活语言中读取配置参数
|
||||
const activeConfig =Object.assign({},defaultParams,getByPath(activeFormatterOpts,opts.configKey,{}))
|
||||
let finalArgs = opts.params.map(param=>getByPath(activeConfig,param,undefined))
|
||||
const formatterConfig =Object.assign({},defaultParams,getByPath(activeFormatterConfigs,opts.configKey,{}))
|
||||
let finalArgs = opts.params.map(param=>getByPath(formatterConfig,param,undefined))
|
||||
// 4. 将翻译函数执行格式化器时传入的参数覆盖默认参数
|
||||
for(let i =0; i<finalArgs.length-1;i++){
|
||||
if(i>=args.length-1) break // 最后一参数是配置
|
||||
if(args[i]!==undefined) finalArgs[i] = args[i]
|
||||
}
|
||||
return fn(finalValue,...finalArgs,activeFormatterOpts)
|
||||
return fn(finalValue,...finalArgs,activeFormatterConfigs)
|
||||
}
|
||||
wrappedFn.configurable = true // 当函数是可配置时才在最后一个参数中传入$config
|
||||
return wrappedFn
|
||||
|
@ -1,5 +1,5 @@
|
||||
const {i18nScope, translate, getInterpolatedVars } = require('../packages/runtime/index')
|
||||
const dayjs = require('dayjs');
|
||||
const { i18nScope, translate, getInterpolatedVars } = require('../packages/runtime/dist/runtime.cjs')
|
||||
|
||||
const loaders = {
|
||||
zh:{
|
||||
@ -12,7 +12,7 @@ const loaders = {
|
||||
1:"hello",
|
||||
2:"Now is {}",
|
||||
3:"I was born in {year}, now is {age} years old",
|
||||
4:["I have no friends","I have one friends","I have two friends","I have {} friends"],
|
||||
4:["I have no friends","I have one friends","I have two friends","I have {} friends"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,10 +29,11 @@ const formatters = {
|
||||
book:(v)=>`<${v}>`,
|
||||
},
|
||||
}
|
||||
|
||||
const idMap = {
|
||||
1:"你好",
|
||||
2:"现在是{}",
|
||||
3:"我出生于{year}年,今年{age}岁"
|
||||
3:"我出生于{year}年,今年{age}岁",
|
||||
4:"我有{}个朋友"
|
||||
}
|
||||
const languages = [
|
||||
@ -64,7 +65,7 @@ scope.registerFormatters({
|
||||
"*":{
|
||||
sum : (v,n=1)=>v+n,
|
||||
double: (v)=>v*2,
|
||||
upper : (v)=>v.toUpperCase(),
|
||||
upper : (v)=>v.toUpperCase()
|
||||
}
|
||||
},true)
|
||||
|
||||
@ -207,22 +208,22 @@ test("命名插值翻译文本内容",done=>{
|
||||
|
||||
test("当没有对应的语言翻译时",done=>{
|
||||
expect(t("我是中国人")).toBe("我是中国人");
|
||||
changeLanguage("en")
|
||||
scope.change("en")
|
||||
expect(t("我是中国人")).toBe("我是中国人");
|
||||
done()
|
||||
})
|
||||
|
||||
|
||||
test("切换到未知语言",done=>{
|
||||
test("切换到未知语言时回退到默认语言",done=>{
|
||||
expect(t("我是中国人")).toBe("我是中国人");
|
||||
changeLanguage("en")
|
||||
scope.change("xn")
|
||||
expect(t("我是中国人")).toBe("我是中国人");
|
||||
done()
|
||||
})
|
||||
|
||||
|
||||
test("翻译复数支持",done=>{
|
||||
changeLanguage("en")
|
||||
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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user