This commit is contained in:
wxzhang 2023-04-13 22:04:27 +08:00
parent e060827dc1
commit d945c2092d
8 changed files with 255 additions and 261 deletions

View File

@ -87,241 +87,241 @@ const formatters ={
let scope:VoerkaI18nScope;
beforeAll(async ()=>{
return new Promise((resolve)=>{
scope = new VoerkaI18nScope({
id: "test",
languages,
messages,
formatters,
callback:()=>{
resolve()
}
})
})
})
beforeEach(async ()=>{
await scope.change("zh")
})
describe("VoerkaI18nScope", () => {
test("成功创建实例", () => {
expect(scope).toBeInstanceOf(VoerkaI18nScope)
expect(scope.activeLanguage).toBe("zh")
expect(scope.defaultLanguage).toBe("zh")
expect(scope.messages).toEqual(messages)
expect(scope.default).toEqual(zhMessages)
expect(scope.current).toEqual(zhMessages)
expect(scope.idMap).toEqual(idMap)
// 全局管理器
expect(scope.global).toBeInstanceOf(VoerkaI18nManager)
})
test("切换语言", () => {
return new Promise<void>((resolve)=>{
scope.on((language:string) => {
expect(language).toBe("en")
expect(scope.activeLanguage).toBe("en")
expect(scope.defaultLanguage).toBe("zh")
expect(scope.messages).toEqual(messages)
expect(scope.default).toEqual(zhMessages)
expect(scope.current).toEqual(enMessages)
expect(scope.idMap).toEqual(idMap)
resolve()
describe("所有测试", () => {
beforeAll(async ()=>{
return new Promise((resolve)=>{
scope = new VoerkaI18nScope({
id: "test",
languages,
messages,
formatters,
callback:()=>{
resolve()
}
})
scope.change("en")
})
})
test("切换到不存在的语言", async () => {
try{
await scope.change("xn")
}catch(e){
expect(e).toBeInstanceOf(InvalidLanguageError)
}
beforeEach(async ()=>{
await scope.change("zh")
})
test("指定了默认信息加载器时,切换到不存在的语言时从远程加载", async () => {
scope.global.registerDefaultLoader(async function(newLanguage:string,curScope){
expect(newLanguage).toBe("de")
expect(curScope).toBe(scope)
return {
hello:"[DE]hello"
}
describe("VoerkaI18nScope", () => {
test("成功创建实例", () => {
expect(scope).toBeInstanceOf(VoerkaI18nScope)
expect(scope.activeLanguage).toBe("zh")
expect(scope.defaultLanguage).toBe("zh")
expect(scope.messages).toEqual(messages)
expect(scope.default).toEqual(zhMessages)
expect(scope.current).toEqual(zhMessages)
// 全局管理器
expect(scope.global).toBeInstanceOf(VoerkaI18nManager)
})
test("切换语言", () => {
return new Promise<void>((resolve)=>{
scope.on((language:string) => {
expect(language).toBe("en")
expect(scope.activeLanguage).toBe("en")
expect(scope.defaultLanguage).toBe("zh")
expect(scope.messages).toEqual(messages)
expect(scope.default).toEqual(zhMessages)
expect(scope.current).toEqual(enMessages)
resolve()
})
scope.change("en")
})
})
await scope.change("de")
expect((scope.current as any)['hello']).toEqual("[DE]hello")
})
test("全局切换语言", () => {
return new Promise<void>((resolve)=>{
let event = 0
scope.on((language:string) => {
expect(language).toBe("en")
expect(scope.activeLanguage).toBe("en")
expect(scope.defaultLanguage).toBe("zh")
expect(scope.messages).toEqual(messages)
expect(scope.default).toEqual(zhMessages)
expect(scope.current).toEqual(enMessages)
expect(scope.idMap).toEqual(idMap)
event++
if(event==2) resolve()
test("切换到不存在的语言", async () => {
try{
await scope.change("xn")
}catch(e){
expect(e).toBeInstanceOf(InvalidLanguageError)
}
})
test("指定了默认信息加载器时,切换到不存在的语言时从远程加载", async () => {
scope.global.registerDefaultLoader(async function(newLanguage:string,curScope){
expect(newLanguage).toBe("de")
expect(curScope).toBe(scope)
return {
hello:"[DE]hello"
}
})
VoerkaI18n.on((language:string) => {
expect(language).toBe("en")
expect(VoerkaI18n.activeLanguage).toBe("en")
expect(VoerkaI18n.defaultLanguage).toBe("zh")
event++
if(event==2) resolve()
await scope.change("de")
expect((scope.current as any)['hello']).toEqual("[DE]hello")
})
test("全局切换语言", () => {
return new Promise<void>((resolve)=>{
let event = 0
scope.on((language:string) => {
expect(language).toBe("en")
expect(scope.activeLanguage).toBe("en")
expect(scope.defaultLanguage).toBe("zh")
expect(scope.messages).toEqual(messages)
expect(scope.default).toEqual(zhMessages)
expect(scope.current).toEqual(enMessages)
expect(scope.idMap).toEqual(idMap)
event++
if(event==2) resolve()
})
VoerkaI18n.on((language:string) => {
expect(language).toBe("en")
expect(VoerkaI18n.activeLanguage).toBe("en")
expect(VoerkaI18n.defaultLanguage).toBe("zh")
event++
if(event==2) resolve()
})
VoerkaI18n.change("en")
})
VoerkaI18n.change("en")
})
test("多个Scope", async () => {
let scope1 = new VoerkaI18nScope({
languages,
idMap: {},
messages: {},
formatters: {},
})
let scope2 = new VoerkaI18nScope({
languages,
idMap: {},
messages: {},
formatters: {},
})
})
})
describe("格式化化配置与参数", () => {
test("格式化器参数", async () => {
expect(scope.formatters).toBeInstanceOf(VoerkaI18nFormatterRegistry)
expect(scope.formatters.activeLanguage).toBe("zh")
expect(scope.formatters.formatters).toEqual(formatters)
expect(scope.formatters.types).toBe(zhFormatters.$types)
})
test("查找格式化器", async () => {
expect(scope.formatters.get("first")).toBe(formatters.zh.first)
await scope.change("en")
expect(scope.formatters.get("first")).toBe(formatters.en.first)
})
test("合并后的格式化器配置", async () => {
let fallbackLanguage = scope.getLanguage(scope.activeLanguage)?.fallback
const globalFormatters = inlineFormatters
let scopeConfig = mergeFormattersConfigs([
(fallbackLanguage! in globalFormatters) ? (globalFormatters as any)?.[fallbackLanguage!].$config:{},
globalFormatters.zh.$config,
(fallbackLanguage! in formatters) ? (formatters as any)?.[fallbackLanguage!]?.$config:{},
formatters.zh.$config
])
expect(scope.formatters.config).toEqual(scopeConfig)
//
await scope.change("en")
fallbackLanguage = scope.getLanguage(scope.activeLanguage)?.fallback
scopeConfig = mergeFormattersConfigs([
(fallbackLanguage! in globalFormatters) ? (globalFormatters as any)?.[fallbackLanguage!].$config:{},
globalFormatters.en.$config,
(fallbackLanguage! in formatters) ? (formatters as any)?.[fallbackLanguage!]?.$config:{},
formatters.en.$config
])
expect(scope.formatters.config).toEqual(scopeConfig)
})
})
test("多个Scope", async () => {
let scope1 = new VoerkaI18nScope({
languages,
idMap: {},
messages: {},
formatters: {},
describe('翻译函数', () => {
let t:VoerkaI18nTranslate
beforeAll(() => {
t = scope.t
})
let scope2 = new VoerkaI18nScope({
languages,
idMap: {},
messages: {},
formatters: {},
test('基本翻译',async () => {
expect(t("你好")).toBe("你好")
expect(t("我叫{name},今年{age}岁","张三",12)).toBe("我叫张三,今年12岁")
expect(t("我叫{name},今年{age}岁",["张三",12])).toBe("我叫张三,今年12岁")
expect(t("我叫{name},今年{age}岁",{name:"张三",age:12})).toBe("我叫张三,今年12岁")
await scope.change("en")
expect(t("你好")).toBe("hello")
expect(t("我叫{name},今年{age}岁","tom",12)).toBe("My name is tom,Now 12 years old year")
expect(t("我叫{name},今年{age}岁",["tom",12])).toBe("My name is tom,Now 12 years old year")
expect(t("我叫{name},今年{age}岁",{name:"tom",age:12})).toBe("My name is tom,Now 12 years old year")
expect(t("中国")).toBe("china")
})
test('基本复数翻译',async () => {
expect(t("我有{}部车",0)).toBe("我没有车")
expect(t("我有{}部车",1)).toBe("我有一部车")
expect(t("我有{}部车",2)).toBe("我有两部车")
expect(t("我有{}部车",3)).toBe("我有3部车")
expect(t("我有{}部车",100)).toBe("我有100部车")
await scope.change("en")
expect(t("我有{}部车",0)).toBe("I don't have car")
expect(t("我有{}部车",1)).toBe("I have a car")
expect(t("我有{}部车",2)).toBe("I have two cars")
expect(t("我有{}部车",3)).toBe("I have 3 cars")
expect(t("我有{}部车",100)).toBe("I have 100 cars")
})
})
describe('插值变量格式化器', () => {
let t:VoerkaI18nTranslate
beforeAll(() => {
t = scope.t
// 注册格式化器,注册为所有语言
scope.registerFormatter("add", (value,args,config) => {
return String(Number(value) + (Number(args.length==0 ? 1 : args[0])))
});
scope.formatters.updateConfig("zh",{
bookname:{
beginChar:"《",
endChar:"》"
}
});
scope.formatters.updateConfig("en",{
bookname:{
beginChar:"<",
endChar:">"
}
});
// 注册格式化器,注册为所有语言
scope.registerFormatter("bookname", (value,args,config) => {
let { beginChar = "<",endChar=">" } = Object.assign({},(config as any)?.bookname)
if(args.length==1){
beginChar = endChar = args[0]
}else if(args.length>=2){
beginChar = args[0]
endChar = args[1]
}
return beginChar + value + endChar
})
})
test('格式化器',async () => {
expect(t("我的工资是每月{|add}元",1000)).toBe("我的工资是每月1001元")
expect(t("我的工资是每月{|add()}元",1000)).toBe("我的工资是每月1001元")
expect(t("我的工资是每月{|add(2)}元",1000)).toBe("我的工资是每月1002元")
expect(t("我的工资是每月{|add|add()|add(2)}元",1000)).toBe("我的工资是每月1004元")
})
test('bookname式化器',async () => {
expect(t("hello {|bookname}","tom")).toBe("hello 《tom》")
expect(t("hello {|bookname('#')}","tom")).toBe("hello #tom#")
expect(t("hello {|bookname('#','!')}","tom")).toBe("hello #tom!")
expect(t("hello {|bookname|bookname|bookname}","tom")).toBe("hello 《《《tom》》》")
await scope.change("en")
expect(t("hello {|bookname}","tom")).toBe("hello <tom>")
})
test('空值格式化器',async () => {
expect(t("hello {|bookname|empty('空')}",undefined)).toBe("hello 《空》")
})
})
})
describe("格式化化配置与参数", () => {
describe('内置格式化器', () => {
test("格式化器参数", async () => {
expect(scope.formatters).toBeInstanceOf(VoerkaI18nFormatterRegistry)
expect(scope.formatters.activeLanguage).toBe("zh")
expect(scope.formatters.formatters).toEqual(formatters)
expect(scope.formatters.types).toBe(zhFormatters.$types)
})
test("查找格式化器", async () => {
expect(scope.formatters.get("first")).toBe(formatters.zh.first)
await scope.change("en")
expect(scope.formatters.get("first")).toBe(formatters.en.first)
})
test("合并后的格式化器配置", async () => {
let fallbackLanguage = scope.getLanguage(scope.activeLanguage)?.fallback
const globalFormatters = inlineFormatters
let scopeConfig = mergeFormattersConfigs([
(fallbackLanguage! in globalFormatters) ? (globalFormatters as any)?.[fallbackLanguage!].$config:{},
globalFormatters.zh.$config,
(fallbackLanguage! in formatters) ? (formatters as any)?.[fallbackLanguage!]?.$config:{},
formatters.zh.$config
])
expect(scope.formatters.config).toEqual(scopeConfig)
//
await scope.change("en")
fallbackLanguage = scope.getLanguage(scope.activeLanguage)?.fallback
scopeConfig = mergeFormattersConfigs([
(fallbackLanguage! in globalFormatters) ? (globalFormatters as any)?.[fallbackLanguage!].$config:{},
globalFormatters.en.$config,
(fallbackLanguage! in formatters) ? (formatters as any)?.[fallbackLanguage!]?.$config:{},
formatters.en.$config
])
expect(scope.formatters.config).toEqual(scopeConfig)
})
})
describe('翻译函数', () => {
let t:VoerkaI18nTranslate
beforeAll(() => {
t = scope.t
})
test('基本翻译',async () => {
expect(t("你好")).toBe("你好")
expect(t("我叫{name},今年{age}岁","张三",12)).toBe("我叫张三,今年12岁")
expect(t("我叫{name},今年{age}岁",["张三",12])).toBe("我叫张三,今年12岁")
expect(t("我叫{name},今年{age}岁",{name:"张三",age:12})).toBe("我叫张三,今年12岁")
await scope.change("en")
expect(t("你好")).toBe("hello")
expect(t("我叫{name},今年{age}岁","tom",12)).toBe("My name is tom,Now 12 years old year")
expect(t("我叫{name},今年{age}岁",["tom",12])).toBe("My name is tom,Now 12 years old year")
expect(t("我叫{name},今年{age}岁",{name:"tom",age:12})).toBe("My name is tom,Now 12 years old year")
expect(t("中国")).toBe("china")
})
test('基本复数翻译',async () => {
expect(t("我有{}部车",0)).toBe("我没有车")
expect(t("我有{}部车",1)).toBe("我有一部车")
expect(t("我有{}部车",2)).toBe("我有两部车")
expect(t("我有{}部车",3)).toBe("我有3部车")
expect(t("我有{}部车",100)).toBe("我有100部车")
await scope.change("en")
expect(t("我有{}部车",0)).toBe("I don't have car")
expect(t("我有{}部车",1)).toBe("I have a car")
expect(t("我有{}部车",2)).toBe("I have two cars")
expect(t("我有{}部车",3)).toBe("I have 3 cars")
expect(t("我有{}部车",100)).toBe("I have 100 cars")
})
})
describe('插值变量格式化器', () => {
let t:VoerkaI18nTranslate
beforeAll(() => {
t = scope.t
// 注册格式化器,注册为所有语言
scope.registerFormatter("add", (value,args,config) => {
return String(Number(value) + (Number(args.length==0 ? 1 : args[0])))
});
scope.formatters.updateConfig("zh",{
bookname:{
beginChar:"《",
endChar:"》"
}
});
scope.formatters.updateConfig("en",{
bookname:{
beginChar:"<",
endChar:">"
}
});
// 注册格式化器,注册为所有语言
scope.registerFormatter("bookname", (value,args,config) => {
let { beginChar = "<",endChar=">" } = Object.assign({},(config as any)?.bookname)
if(args.length==1){
beginChar = endChar = args[0]
}else if(args.length>=2){
beginChar = args[0]
endChar = args[1]
}
return beginChar + value + endChar
})
})
test('格式化器',async () => {
expect(t("我的工资是每月{|add}元",1000)).toBe("我的工资是每月1001元")
expect(t("我的工资是每月{|add()}元",1000)).toBe("我的工资是每月1001元")
expect(t("我的工资是每月{|add(2)}元",1000)).toBe("我的工资是每月1002元")
expect(t("我的工资是每月{|add|add()|add(2)}元",1000)).toBe("我的工资是每月1004元")
})
test('bookname式化器',async () => {
expect(t("hello {|bookname}","tom")).toBe("hello 《tom》")
expect(t("hello {|bookname('#')}","tom")).toBe("hello #tom#")
expect(t("hello {|bookname('#','!')}","tom")).toBe("hello #tom!")
expect(t("hello {|bookname|bookname|bookname}","tom")).toBe("hello 《《《tom》》》")
await scope.change("en")
expect(t("hello {|bookname}","tom")).toBe("hello <tom>")
})
test('空值格式化器',async () => {
expect(t("hello {|bookname|empty('空')}",undefined)).toBe("hello 《空》")
})
})
describe('内置格式化器', () => {
})

View File

@ -5,12 +5,12 @@
*/
import { FlexFormatter, IFormatter } from '../formatter'
import { FlexFormatter, Formatter } from '../formatter'
import { toChineseNumber } from "flex-tools/chinese/toChineseNumber"
import { toChineseCurrency } from "flex-tools/chinese/toChineseCurrency"
export const chineseNumberFormatter = Formatter((value: any, [isBig]:[isBig: boolean], $config) => {
export const chineseNumberFormatter = Formatter<any,[isBig: boolean]>((value: any, [isBig], config: any) => {
return toChineseNumber(value, isBig) as string
}, {
params: ["isBig"]

View File

@ -4,14 +4,14 @@
*/
import { toDate } from '../utils'
import { IFormatter } from '../formatter';
import { formatDateTime } from "flex-tools/misc/formatDateTime"
import { relativeTime } from "flex-tools/misc/relativeTime"
import { assignObject } from "flex-tools/object/assignObject"
import { isFunction } from "flex-tools/typecheck/isFunction"
import { Formatter } from '../formatter'
function formatTime(value:number ,template="HH:mm:ss"){
function formatTime(value:number ,[template]="HH:mm:ss"){
return formatDateTime(value,template,{})
}
@ -21,8 +21,8 @@ function formatTime(value:number ,template="HH:mm:ss"){
*
* 1. format参数
* 2. format参数取值可以是若干预设的值long,short等
* 3. format值时$config[configKey]$config[configKey][format]
* 4. !(format in $config[configKey])format值是一个模板字符串
* 3. format值时config[configKey]config[configKey][format]
* 4. !(format in config[configKey])format值是一个模板字符串
* 5. format in presets, presets[format ](value)=>{....}
*
**/
@ -30,15 +30,15 @@ export type FormatterTransformer = (value:any,format:string)=>string
export function createDateTimeFormatter(options={},transformer:FormatterTransformer){
let opts = assignObject({presets:{}},options)
return Formatter(function(this:any,value:any,[format]:any[],$config:Record<string,any>){
return Formatter(function(this:any,value:any,[format]:any[],config:Record<string,any>){
if((format in opts.presets) && isFunction(opts.presets[format])){
return opts.presets[format](value)
}else if((format in $config)){
format = $config[format]
}else if((format in config)){
format = config[format]
}else if(format == "number"){
return value
}
try{// this指向的是activeFormatter.$config
try{// this指向的是activeFormatter.config
return format==null ? value : transformer.call(this,value,format)
}catch(e){
return value
@ -50,7 +50,7 @@ export function createDateTimeFormatter(options={},transformer:FormatterTransfor
/**
*
* - format取值local,long,short,iso,gmt,utc,<模板字符串>
* - $config.datetime.date.format指定
* - config.datetime.date.format指定
*/
export const dateFormatter = createDateTimeFormatter({
normalize: toDate,
@ -104,7 +104,7 @@ export const weekdayFormatter = createDateTimeFormatter({
/**
*
* - format取值local,long,short,timestamp,<模板字符串>
* - $config.datetime.time.format指定
* - config.datetime.time.format指定
*/
export const timeFormatter = createDateTimeFormatter({
normalize : toDate,
@ -121,9 +121,9 @@ export const timeFormatter = createDateTimeFormatter({
* @param {*} value
* @param {*} baseTime
*/
export const relativeTimeFormatter = Formatter((value:any,[baseTime]:[Date],$config:any)=>{
//const { units,now,before,base = Date.now() , after } = $config
return relativeTime(value, $config)
export const relativeTimeFormatter = Formatter<any,[Date]>((value:any,[baseTime],config:any)=>{
//const { units,now,before,base = Date.now() , after } = config
return relativeTime(value,baseTime,config)
},{
normalize:toDate,
params:["base"],

View File

@ -9,12 +9,12 @@
*
*/
import { toNumber } from "../utils"
import { IFormatter } from "../formatter"
import { toCurrency } from "./currency"
import { VoerkaI18nFormatter } from '../types';
import { Formatter } from "../formatter";
export const numberFormartter = Formatter(function(value:any,[precision,division]:[number,number],$config:any){
return toCurrency(value, { division, precision},$config)
export const numberFormartter = Formatter<any,any[]>(function(value:any,[precision,division],config:Record<string,any>){
return toCurrency(value, { division, precision},config)
},{
normalize: toNumber,
params:["precision","division"],

View File

@ -16,7 +16,7 @@ import { isFunction } from "flex-tools/typecheck/isFunction"
import { isPlainObject } from "flex-tools/typecheck/isPlainObject"
import { safeParseJson } from "flex-tools/object/safeParseJson"
import { assignObject } from "flex-tools/object/assignObject"
import { VoerkaI18nFormatterConfigs } from './types';
import { VoerkaI18nFormatterConfigs, VoerkaI18nFormatter, Primitive } from './types';
/**
使便
@ -271,18 +271,14 @@ function parseFormaterParams(strParams: string): any[] {
* @returns
*/
export type VarValueType = string | Error | undefined | null
export type IFormatter = (this: any, value: VarValueType, args: any[],config:VoerkaI18nFormatterConfigs) => string
export interface FormatterOptions {
normalize?: (value: string) => any // 对输入值进行规范化处理,如进行时间格式化时,为了提高更好的兼容性,支持数字时间戳/字符串/Date等需要对输入值进行处理如强制类型转换等
params?: Record<string, any> | null, // 可选的声明参数顺序如果是变参的则需要传入null
configKey?: string // 声明该格式化器在$config中的路径支持简单的使用.的路径语法
export interface CreateFormatterOptions {
normalize?: (value: string) => any // 对输入值进行规范化处理,如进行时间格式化时,为了提高更好的兼容性,支持数字时间戳/字符串/Date等需要对输入值进行处理如强制类型转换等
params?: Record<string, any> | null, // 可选的声明参数顺序如果是变参的则需要传入null
configKey?: string // 声明该格式化器在$config中的路径支持简单的使用.的路径语法
}
export function createFormatter(fn: IFormatter, options?: FormatterOptions, defaultParams?: Record<string, any>) {
export function createFormatter<Value=any,Args extends any[] = any[],Return=any>(fn: VoerkaI18nFormatter, options?: CreateFormatterOptions, defaultParams?: Record<string, any>) {
let opts = assignObject({
normalize: null, // 对输入值进行规范化处理,如进行时间格式化时,为了提高更好的兼容性,支持数字时间戳/字符串/Date等需要对输入值进行处理如强制类型转换等
params: null, // 可选的声明参数顺序如果是变参的则需要传入null
@ -291,7 +287,7 @@ export function createFormatter(fn: IFormatter, options?: FormatterOptions, defa
// 最后一个参数是传入activeFormatterConfig参数
// 并且格式化器的this指向的是activeFormatterConfig
const $formatter = function (this: any, value: string, args: any[],$config:Record<string,any>) {
const $formatter = function (this: any, value: Value, args: Args,config:Record<string,any>):Return {
let finalValue = value
// 1. 输入值规范处理,主要是进行类型转换,确保输入的数据类型及相关格式的正确性,提高数据容错性
if (isFunction(opts.normalize)) {
@ -312,7 +308,6 @@ export function createFormatter(fn: IFormatter, options?: FormatterOptions, defa
})
// 4. 将翻译函数执行格式化器时传入的参数覆盖默认参数
for (let i = 0; i < finalArgs.length; i++) {
if (i == args.length - 1) break // 最后一参数是配置
if (args[i] !== undefined) finalArgs[i] = args[i]
}
}
@ -339,14 +334,14 @@ export function createFormatter(fn: IFormatter, options?: FormatterOptions, defa
* @param {*} options
* @param {*} defaultParams
*/
export const createFlexFormatter = function (fn: IFormatter, options: FormatterOptions, defaultParams?: Record<string, any>) {
export const createFlexFormatter = function<Value=any,Args extends any[]=any[],Return=any>(fn: VoerkaI18nFormatter, options: CreateFormatterOptions, defaultParams?: Record<string, any>) {
const opts = assignObject({
params: {}
}, options)
const $flexFormatter = Formatter(function (this: any, value: VarValueType,args: string[],$config:Record<string,any> ) {
const $flexFormatter = Formatter<Value,Args,Return>(function (this: any, value: any,args,config:Record<string,any> ) {
// 2. 从语言配置中读取默认参数
let finalParams = (options.params || {}).reduce((r: Record<string, any>, name: string) => {
r[name] = $config[name] == undefined ? (defaultParams || {})[name] : $config[name]
r[name] = config[name] == undefined ? (defaultParams || {})[name] : config[name]
return r
}, {})
// 3. 从格式化器中传入的参数具有最高优先级,覆盖默认参数
@ -357,13 +352,12 @@ export const createFlexFormatter = function (fn: IFormatter, options: FormatterO
if (args[i] !== undefined) finalParams[opts.params[i]] = args[i]
}
}
return fn.call(this, value, finalParams, $config)
return fn.call(this, value, finalParams, config)
}, { ...options, params: null }) // 变参工式化器需要指定params=null
return $flexFormatter
}
export const Formatter = createFormatter
export const FlexFormatter = createFlexFormatter

View File

@ -1,7 +1,7 @@
import { assignObject } from 'flex-tools/object/assignObject';
import { VoerkaI18nFormatterConfigs } from '../types';
import { toNumber } from "../utils"
import { IFormatter, VarValueType,Formatter } from "../formatter"
import { Formatter } from "../formatter"
/**
*
@ -39,7 +39,7 @@ export function dict(key:string, values:any) {
* @paran {String} next true/false,break,skip,break
* @param {*} config
*/
export const empty = Formatter(function(value:VarValueType,[escapeValue,next]:[escapeValue:any,next: 'break' | 'ignore'],config:VoerkaI18nFormatterConfigs){
export const empty = Formatter<any,[escapeValue:any,next: 'break' | 'ignore']>(function(value:any,[escapeValue,next],config:VoerkaI18nFormatterConfigs){
let opts = assignObject({escape:"",next:'break',values:[]},config)
if(escapeValue!=undefined) opts.escape = escapeValue
let emptyValues = [undefined,null]
@ -72,10 +72,10 @@ export const empty = Formatter(function(value:VarValueType,[escapeValue,next]:[e
* @param {*} config
* @returns
*/
export const error = Formatter(function(value:string,escapeValue:any,next:'break' | 'ignore',$config:VoerkaI18nFormatterConfigs){
export const error = Formatter<any,[escapeValue:any,next:'break' | 'ignore']>(function(value,[escapeValue,next],config:VoerkaI18nFormatterConfigs){
if(typeof(value)=='object' && (value instanceof Error)){
try{
let opts = assignObject({escape:null,next:'break'},$config)
let opts = assignObject({escape:null,next:'break'},config)
if(escapeValue!=undefined) opts.escape = escapeValue
if(next!=undefined) opts.next = next
return {
@ -141,7 +141,7 @@ const FILE_SIZE_WHOLE_UNITS = ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "
* @param {*} brief
* @param {*} options
*/
export const filesize= Formatter((value:string,unit:string,brief:boolean=true,$config:VoerkaI18nFormatterConfigs)=>{
export const filesize= Formatter<any,[unit:string,brief:boolean]>((value:string,[unit,brief],config:VoerkaI18nFormatterConfigs)=>{
let v = toNumber(value)
let unitIndex
if(unit==undefined || unit=="auto"){
@ -151,13 +151,13 @@ const FILE_SIZE_WHOLE_UNITS = ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "
unitIndex =["B","BYTE","BYTES"].includes(unit) ? 0 : FILE_SIZE_BRIEF_UNITS.indexOf(unit)
}
if(unitIndex<0 || unitIndex>=FILE_SIZE_BRIEF_UNITS.length) unitIndex= 0
let result = (unitIndex == 0 ? v : v / FILE_SIZE_SECTIONS[unitIndex]).toFixed($config.precision)
let result = (unitIndex == 0 ? v : v / FILE_SIZE_SECTIONS[unitIndex]).toFixed(config.precision)
if( unitIndex>0 && (v % FILE_SIZE_SECTIONS[unitIndex])!==0) result = result+"+"
// 去除尾部的0
while(["0","."].includes(result[result.length-1])){
result = result.substring(0, result.length-2)
}
return brief ? `${result} ${$config.brief[unitIndex]}` : `${result} ${$config.whole[unitIndex]}`
return brief ? `${result} ${config.brief[unitIndex]}` : `${result} ${config.whole[unitIndex]}`
},{
params:["unit","brief"],
configKey:"fileSize"

View File

@ -5,7 +5,7 @@
import enFormatters from "./en"
import zhFormatters from "./zh"
import defaultFormatters from "./default"
import * as defaultFormatters from "./default"
export default {
"*":defaultFormatters,

View File

@ -35,7 +35,7 @@ export interface VoerkaI18nLanguageDefine {
export type VoerkaI18nFormatterConfigs = Record<string, any>
export type VoerkaI18nFormatter = ((value: string,args: any[],config: VoerkI18nFormatterConfigs) => string)
export type VoerkaI18nFormatter = ((value: any,args: any[],config: VoerkI18nFormatterConfigs) => any)
export type VoerkaI18nTypesFormatters=Partial<Record<SupportedDateTypes, VoerkaI18nFormatter>>
export type VoerkaI18nTypesFormatterConfig= Partial<Record<string, any>>
export type VoerkaI18nTypesFormatterConfigs= Partial<Record<SupportedDateTypes | string, Record<string,any>>>