diff --git a/packages/runtime/src/__tests__/index.test.ts b/packages/runtime/src/__tests__/index.test.ts index a19615c..d2464bb 100644 --- a/packages/runtime/src/__tests__/index.test.ts +++ b/packages/runtime/src/__tests__/index.test.ts @@ -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((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((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((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((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 ") }) - - + 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 ") - }) - - test('空值格式化器',async () => { - expect(t("hello {|bookname|empty('空')}",undefined)).toBe("hello 《空》") - }) - -}) - -describe('内置格式化器', () => { - }) \ No newline at end of file diff --git a/packages/runtime/src/datatypes/chinese.ts b/packages/runtime/src/datatypes/chinese.ts index a3a8a1c..7685658 100644 --- a/packages/runtime/src/datatypes/chinese.ts +++ b/packages/runtime/src/datatypes/chinese.ts @@ -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((value: any, [isBig], config: any) => { return toChineseNumber(value, isBig) as string }, { params: ["isBig"] diff --git a/packages/runtime/src/datatypes/datetime.ts b/packages/runtime/src/datatypes/datetime.ts index 2172b54..731f504 100644 --- a/packages/runtime/src/datatypes/datetime.ts +++ b/packages/runtime/src/datatypes/datetime.ts @@ -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){ + return Formatter(function(this:any,value:any,[format]:any[],config:Record){ 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((value:any,[baseTime],config:any)=>{ + //const { units,now,before,base = Date.now() , after } = config + return relativeTime(value,baseTime,config) },{ normalize:toDate, params:["base"], diff --git a/packages/runtime/src/datatypes/numeric.ts b/packages/runtime/src/datatypes/numeric.ts index 9f2d177..f6d16cc 100644 --- a/packages/runtime/src/datatypes/numeric.ts +++ b/packages/runtime/src/datatypes/numeric.ts @@ -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(function(value:any,[precision,division],config:Record){ + return toCurrency(value, { division, precision},config) },{ normalize: toNumber, params:["precision","division"], diff --git a/packages/runtime/src/formatter.ts b/packages/runtime/src/formatter.ts index c9baa8b..66bc82a 100644 --- a/packages/runtime/src/formatter.ts +++ b/packages/runtime/src/formatter.ts @@ -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 | null, // 可选的,声明参数顺序,如果是变参的,则需要传入null - configKey?: string // 声明该格式化器在$config中的路径,支持简单的使用.的路径语法 +export interface CreateFormatterOptions { + normalize?: (value: string) => any // 对输入值进行规范化处理,如进行时间格式化时,为了提高更好的兼容性,支持数字时间戳/字符串/Date等,需要对输入值进行处理,如强制类型转换等 + params?: Record | null, // 可选的,声明参数顺序,如果是变参的,则需要传入null + configKey?: string // 声明该格式化器在$config中的路径,支持简单的使用.的路径语法 } -export function createFormatter(fn: IFormatter, options?: FormatterOptions, defaultParams?: Record) { +export function createFormatter(fn: VoerkaI18nFormatter, options?: CreateFormatterOptions, defaultParams?: Record) { 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) { + const $formatter = function (this: any, value: Value, args: Args,config:Record):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) { +export const createFlexFormatter = function(fn: VoerkaI18nFormatter, options: CreateFormatterOptions, defaultParams?: Record) { const opts = assignObject({ params: {} }, options) - const $flexFormatter = Formatter(function (this: any, value: VarValueType,args: string[],$config:Record ) { + const $flexFormatter = Formatter(function (this: any, value: any,args,config:Record ) { // 2. 从语言配置中读取默认参数 let finalParams = (options.params || {}).reduce((r: Record, 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 diff --git a/packages/runtime/src/formatters/default.ts b/packages/runtime/src/formatters/default.ts index 6a002a2..46dae9b 100644 --- a/packages/runtime/src/formatters/default.ts +++ b/packages/runtime/src/formatters/default.ts @@ -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(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(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((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" diff --git a/packages/runtime/src/formatters/index.ts b/packages/runtime/src/formatters/index.ts index 13230bd..032bb74 100644 --- a/packages/runtime/src/formatters/index.ts +++ b/packages/runtime/src/formatters/index.ts @@ -5,7 +5,7 @@ import enFormatters from "./en" import zhFormatters from "./zh" -import defaultFormatters from "./default" +import * as defaultFormatters from "./default" export default { "*":defaultFormatters, diff --git a/packages/runtime/src/types.ts b/packages/runtime/src/types.ts index cdacac5..4187a30 100644 --- a/packages/runtime/src/types.ts +++ b/packages/runtime/src/types.ts @@ -35,7 +35,7 @@ export interface VoerkaI18nLanguageDefine { export type VoerkaI18nFormatterConfigs = Record -export type VoerkaI18nFormatter = ((value: string,args: any[],config: VoerkI18nFormatterConfigs) => string) +export type VoerkaI18nFormatter = ((value: any,args: any[],config: VoerkI18nFormatterConfigs) => any) export type VoerkaI18nTypesFormatters=Partial> export type VoerkaI18nTypesFormatterConfig= Partial> export type VoerkaI18nTypesFormatterConfigs= Partial>>