diff --git a/packages/apps/vueapp/src/components/formatters.vue b/packages/apps/vueapp/src/components/formatters.vue index 6196e54..f4722c5 100644 --- a/packages/apps/vueapp/src/components/formatters.vue +++ b/packages/apps/vueapp/src/components/formatters.vue @@ -1,7 +1,7 @@ - diff --git a/packages/apps/vueapp/src/languages/en.js b/packages/apps/vueapp/src/languages/en.js index 69048cc..3d30cae 100644 --- a/packages/apps/vueapp/src/languages/en.js +++ b/packages/apps/vueapp/src/languages/en.js @@ -4,5 +4,26 @@ export default { "3": "Welcome the great rejuvenation of the Chinese nation", "4": "Founded in {}", "5": "Capital: Beijing", - "6": "VoerkaI18n多语言解决方案 " + "6": "VoerkaI18n多语言解决方案 ", + "7": "Now is { value | date }", + "8": "Now is { value | shortdate }", + "9": "Now is { value | time }", + "10": "Now is { value | shorttime }", + "11": "Now is { value | year }", + "12": "Now is { value | month }", + "13": "Now is { value | day }", + "14": "Now is { value | weekdayValue }", + "15": "Now is { value | weekday }", + "16": "Now is { value | shortWeekday }", + "17": "Now is { value | monthName }", + "18": "Now is { value | shorMonthName }", + "19": "Now is { value | hour }", + "20": "Now is { value | hour12 }", + "21": "Now is { value | minute }", + "22": "Now is { value | second }", + "23": "Now is { value | millisecond }", + "24": "Now is { value | timestamp }", + "25": "Price: { value | currency }", + "26": "Price: { value | currency(\"==", + "27": "Price: { value | capitalizeCurrency }" } \ No newline at end of file diff --git a/packages/apps/vueapp/src/languages/idMap.js b/packages/apps/vueapp/src/languages/idMap.js index ad23985..a5a6e00 100644 --- a/packages/apps/vueapp/src/languages/idMap.js +++ b/packages/apps/vueapp/src/languages/idMap.js @@ -4,5 +4,26 @@ export default { "迎接中华民族的伟大复兴": 3, "成立于{}年": 4, "首都:北京": 5, - "VoerkaI18n多语言解决方案 ": 6 + "VoerkaI18n多语言解决方案 ": 6, + "现在是{ value | date }": 7, + "现在是{ value | shortdate }": 8, + "现在是{ value | time }": 9, + "现在是{ value | shorttime }": 10, + "现在是{ value | year }": 11, + "现在是{ value | month }": 12, + "现在是{ value | day }": 13, + "现在是{ value | weekdayValue }": 14, + "现在是{ value | weekday }": 15, + "现在是{ value | shortWeekday }": 16, + "现在是{ value | monthName }": 17, + "现在是{ value | shorMonthName }": 18, + "现在是{ value | hour }": 19, + "现在是{ value | hour12 }": 20, + "现在是{ value | minute }": 21, + "现在是{ value | second }": 22, + "现在是{ value | millisecond }": 23, + "现在是{ value | timestamp }": 24, + "商品价格:{ value | currency }": 25, + "商品价格:{ value | currency(\"==": 26, + "商品价格:{ value | capitalizeCurrency }": 27 } \ No newline at end of file diff --git a/packages/apps/vueapp/src/languages/translates/default.json b/packages/apps/vueapp/src/languages/translates/default.json index 9588cb0..383a115 100644 --- a/packages/apps/vueapp/src/languages/translates/default.json +++ b/packages/apps/vueapp/src/languages/translates/default.json @@ -34,5 +34,131 @@ "$file": [ "App.vue" ] + }, + "现在是{ value | date }": { + "en": "Now is { value | date }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | shortdate }": { + "en": "Now is { value | shortdate }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | time }": { + "en": "Now is { value | time }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | shorttime }": { + "en": "Now is { value | shorttime }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | year }": { + "en": "Now is { value | year }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | month }": { + "en": "Now is { value | month }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | day }": { + "en": "Now is { value | day }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | weekdayValue }": { + "en": "Now is { value | weekdayValue }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | weekday }": { + "en": "Now is { value | weekday }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | shortWeekday }": { + "en": "Now is { value | shortWeekday }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | monthName }": { + "en": "Now is { value | monthName }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | shorMonthName }": { + "en": "Now is { value | shorMonthName }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | hour }": { + "en": "Now is { value | hour }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | hour12 }": { + "en": "Now is { value | hour12 }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | minute }": { + "en": "Now is { value | minute }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | second }": { + "en": "Now is { value | second }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | millisecond }": { + "en": "Now is { value | millisecond }", + "$file": [ + "components\\formatters.vue" + ] + }, + "现在是{ value | timestamp }": { + "en": "Now is { value | timestamp }", + "$file": [ + "components\\formatters.vue" + ] + }, + "商品价格:{ value | currency }": { + "en": "Price: { value | currency }", + "$file": [ + "components\\formatters.vue" + ] + }, + "商品价格:{ value | currency(\"==": { + "en": "Price: { value | currency(\"==", + "$file": [ + "components\\formatters.vue" + ] + }, + "商品价格:{ value | capitalizeCurrency }": { + "en": "Price: { value | capitalizeCurrency }", + "$file": [ + "components\\formatters.vue" + ] } } \ No newline at end of file diff --git a/packages/cli/init.command.js b/packages/cli/init.command.js index 242495a..8f94053 100644 --- a/packages/cli/init.command.js +++ b/packages/cli/init.command.js @@ -12,6 +12,7 @@ const { findModuleType } = require("@voerkai18n/utils") const createLogger = require("logsets") const logger = createLogger() + function getLanguageList(langs,defaultLanguage){ try{ const available_languages = require("./available_languages") @@ -21,12 +22,12 @@ function getLanguageList(langs,defaultLanguage){ if(langIndex > -1 ){ return { name:lng, - title:available_languages[defaultLanguage][langIndex].title + title:available_languages[defaultLanguage][langIndex].title } }else{ return { name:lng, - title:lng + title:lng } } }) diff --git a/packages/runtime/cnutils.js b/packages/runtime/cnutils.js new file mode 100644 index 0000000..0305c5a --- /dev/null +++ b/packages/runtime/cnutils.js @@ -0,0 +1,104 @@ +/** + * + * 处理中文数字和货币相关 + * + */ +const { isNumber } = require('./utils') + +const CN_WEEK_DAYS = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"] +const CN_SHORT_WEEK_DAYS =["日","一","二","三","四","五","六"] +const CN_MONTH_NAMES= ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"] +const CN_SHORT_MONTH_NAMES = ["一","二","三","四","五","六","七","八","九","十","十一","十二"] + + const CN_NUMBER_DIGITS = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"] + const CN_NUMBER_UNITS = ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '兆', '十', '百', '千', '京', '十', '百', '千', '垓'] + const CN_NUMBER_BIG_DIGITS = ["零", '壹', '貳', '參', '肆', '伍', '陸', '柒', '捌', '玖'] + const CN_NUMBER_BIG_UNITS = ['', '拾', '佰', '仟', '萬', '拾', '佰', '仟', '億', '拾', '佰', '仟', '兆', '拾', '佰', '仟', '京', '拾', '佰', '仟', '垓'] + + + /** + * + * 将数字转换为中文数字 + * + * 注意会忽略掉小数点后面的数字 + * + * @param {*} value 数字 + * @param {*} isBig 是否大写数字 + * @returns + */ +function toChineseNumber(value,isBig) { + if(!isNumber(value)) return value; + let [wholeValue,decimalValue] = String(value).split(".") // 处理小数点 + const DIGITS = isBig ? CN_NUMBER_BIG_DIGITS : CN_NUMBER_DIGITS + const UNITS = isBig ? CN_NUMBER_BIG_UNITS : CN_NUMBER_UNITS + let result = '' + if(wholeValue.length==1) return DIGITS[parseInt(wholeValue)] + for(let i=wholeValue.length-1; i>=0; i--){ + let bit = parseInt(wholeValue[i]) + let digit = DIGITS[bit] + let unit = UNITS[wholeValue.length-i-1] + if(bit==0){ + let preBit =i< wholeValue.length ? parseInt(wholeValue[i+1]) : null// 上一位 + let isKeyBits = ((wholeValue.length-i-1) % 4)==0 + if(preBit && preBit!=0 && !isKeyBits) result = "零" + result + if(isKeyBits) result = UNITS[wholeValue.length-i-1] + result + }else{ + result=`${digit}${unit}` + result + } + } + if(isBig){ + result = result.replace("垓京","垓") + .replace("京兆","京") + .replace("兆億","兆") + .replace("億萬","億") + .replace("萬仟","萬") + }else{ + result = result.replace("垓京","垓") + .replace("京兆","京") + .replace("兆亿","兆") + .replace("亿万","亿") + .replace("万千","万") + if(result.startsWith("一十")) result=result.substring(1) + } + return result // 中文数字忽略小数部分 + } + + function toChineseBigNumber(value) { + return toChineseNumber(value,true) + } + /** + * 转换为中文大写货币 + * @param {*} value + * @param {*} division 分割符号位数,3代表每3个数字添加一个,号 + * @param {*} prefix 前缀 + * @param {*} suffix 后缀 + * @param {*} precision 小数点精确到几位 + */ +function toChineseCurrency(value,{big=false,prefix="",unit="元",suffix=""}={}){ + let [wholeValue,decimalValue] = String(value).split(".") + let result + if(big){ + result = toChineseBigNumber(wholeValue)+unit + }else{ + result = toChineseNumber(wholeValue)+unit + } + if(decimalValue){ + if(decimalValue[0]) result =result+ CN_NUMBER_DIGITS[parseInt(decimalValue[0])]+"角" + if(decimalValue[1]) result =result+ CN_NUMBER_DIGITS[parseInt(decimalValue[1])]+"分" + } + return prefix+result+suffix +} + + module.exports ={ + toChineseCurrency, + toChineseNumber, + toChineseBigNumber, + CN_WEEK_DAYS, + CN_SHORT_WEEK_DAYS, + CN_MONTH_NAMES, + CN_SHORT_MONTH_NAMES, + CN_NUMBER_DIGITS, + CN_NUMBER_UNITS, + CN_NUMBER_BIG_DIGITS, + CN_NUMBER_BIG_UNITS +} \ No newline at end of file diff --git a/packages/runtime/formatters.js b/packages/runtime/formatters.js deleted file mode 100644 index 8714c09..0000000 --- a/packages/runtime/formatters.js +++ /dev/null @@ -1,224 +0,0 @@ -/** - * 内置的格式化器 - * - */ - -const { isNumber } = require("./utils") - -/** - * 字典格式化器 - * 根据输入data的值,返回后续参数匹配的结果 - * dict(data,,,,,,,...) - * - * - * dict(1,1,"one",2,"two",3,"three",4,"four") == "one" - * dict(2,1,"one",2,"two",3,"three",4,"four") == "two" - * dict(3,1,"one",2,"two",3,"three",4,"four") == "three" - * dict(4,1,"one",2,"two",3,"three",4,"four") == "four" - * // 无匹配时返回原始值 - * dict(5,1,"one",2,"two",3,"three",4,"four") == 5 - * // 无匹配时并且后续参数个数是奇数,则返回最后一个参数 - * dict(5,1,"one",2,"two",3,"three",4,"four","more") == "more" - * - * 在翻译中使用 - * I have { value | dict(1,"one",2,"two",3,"three",4,"four")} apples - * - * @param {*} value - * @param {...any} args - * @returns - */ -function dict(value, ...args) { - for (let i = 0; i < args.length; i += 2) { - if (args[i] === value) { - return args[i + 1] - } - } - if (args.length > 0 && (args.length % 2 !== 0)) return args[args.length - 1] - return value -} - - -/** - * 格式化日期 - * 将值转换为Date类型 - * @param {*} value - */ -function toDate(value) { - try { - return value instanceof Date ? value : new Date(value) - } catch { - return value - } -} - -function toNumber(value,defualt=0) { - try { - if (isNumber(value)) { - return parseInt(value) - } else { - return defualt - } - } catch { - return value - } -} - -const CHINESE_DIGITS = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"] -const CHINESE_UNITS = ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '兆', '十', '百', '千', '京', '十', '百', '千', '垓'] -const CHINESE_BIG_DIGITS = ["零", '壹', '貳', '參', '肆', '伍', '陸', '柒', '捌', '玖'] -const CHINESE_BIG_UNITS = ['', '拾', '佰', '仟', '萬', '拾', '佰', '仟', '億', '拾', '佰', '仟', '兆', '拾', '佰', '仟', '京', '拾', '佰', '仟', '垓'] - -/** - * - * 将数字转换为中文数字 - * - * 注意会忽略掉小数点后面的数字 - * - * @param {*} value 数字 - * @param {*} isBig 是否大写数字 - * @returns - */ -function toChineseNumber(value,isBig) { - if(!isNumber(value)) return value; - let [wholeValue,decimalValue] = String(value).split(".") // 处理小数点 - const DIGITS = isBig ? CHINESE_BIG_DIGITS : CHINESE_DIGITS - const UNITS = isBig ? CHINESE_BIG_UNITS : CHINESE_UNITS - let result = '' - if(wholeValue.length==1) return DIGITS[parseInt(wholeValue)] - for(let i=wholeValue.length-1; i>=0; i--){ - let bit = parseInt(wholeValue[i]) - let digit = DIGITS[bit] - let unit = UNITS[wholeValue.length-i-1] - if(bit==0){ - let preBit =i< wholeValue.length ? parseInt(wholeValue[i+1]) : null// 上一位 - let isKeyBits = ((wholeValue.length-i-1) % 4)==0 - if(preBit && preBit!=0 && !isKeyBits) result = "零" + result - if(isKeyBits) result = UNITS[wholeValue.length-i-1] + result - }else{ - result=`${digit}${unit}` + result - } - } - if(isBig){ - result = result.replace("垓京","垓") - .replace("京兆","京") - .replace("兆億","兆") - .replace("億萬","億") - .replace("萬仟","萬") - }else{ - result = result.replace("垓京","垓") - .replace("京兆","京") - .replace("兆亿","兆") - .replace("亿万","亿") - .replace("万千","万") - if(result.startsWith("一十")) result=result.substring(1) - } - return result // 中文数字忽略小数部分 -} - - -/** - * 转换为货币 - * @param {*} value - * @param {*} division 分割符号位数,3代表每3个数字添加一个,号 - * @param {*} unit 货币单位 - * @param {*} precision 小数点精确到几位 - * @returns - */ -function toCurrency(value,{division=3,unit="",precision=2}={}){ - let [wholeValue,decimalValue] = String(value).split(".") - let result = [unit] - for(let i=0;i0) result.push(",") - result.push(wholeValue[i]) - } - if(decimalValue){ - result.push(`.${decimalValue}`) - } - return result.join("") -} - -/** - * 转换为中文大写货币 - * - * - * - * @param {*} value - * @param {*} division 分割符号位数,3代表每3个数字添加一个,号 - * @param {*} unit 货币单位 - * @param {*} precision 小数点精确到几位 - */ -function toChineseCurrency(value,padding){ - let [wholeValue,decimalValue] = String(value).split(".") - let result = `¥${toChineseNumber(wholeValue,true)}元` - if(padding){ - if(decimalValue){ - decimalValue=decimalValue.padEnd(2,"0") - }else{ - decimalValue="00" - } - } - if(decimalValue){ - if(decimalValue[0]) result=result+`${toChineseNumber(decimalValue[0],true)}角` - if(decimalValue[1]) result=result+`${toChineseNumber(decimalValue[1],true)}分` - } - return result -} - - -module.exports = { - "*": { - $types: { - Date: value => {value=toDate(value);return `${value.getFullYear()}/${value.getMonth() + 1}/${value.getDate()} ${value.getHours()}:${value.getMinutes()}:${value.getSeconds()}`} - }, - // 日期 - date : value => {value=toDate(value);return `${value.getFullYear()}/${value.getMonth() + 1}/${value.getDate()}`}, - shortdate : value => {value=toDate(value);return `${value.getFullYear()}/${value.getMonth() + 1}/${value.getDate()}`}, - time : value => {value=toDate(value);return `${value.getHours()}:${value.getMinutes()}:${value.getSeconds()}`}, - shorttime : value => {value=toDate(value);return `${value.getHours()}:${value.getMinutes()}:${value.getSeconds()}`}, - year : value => toDate(value).getFullYear(), - month : value => toDate(value).getMonth() + 1, - day : value => toDate(value).getDate(), - weekdayValue : value => toDate(value).getDay(), - weekday : value => ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][toDate(value).getDay()], - shortWeekday : value => ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur"][toDate(value).getDay()], - monthName : value => ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][toDate(value).getMonth()] - shorMonthName: value => ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"][toDate(value).getMonth()] - // 时间 - hour : value => toDate(value).getHours(), - hour12 : value => toDate(value).getHours()>12 : toDate(value).getHours()-12 : toDate(value).getHours(), - minute : value => toDate(value).getMinutes(), - second : value => toDate(value).getSeconds(), - millisecond : value => toDate(value).getMilliseconds(), - timestamp : value => toDate(value).getTime(), - // 数字 - number : (value) => toNumber(value), - - // 货币 - currency: (value,unit="$",division=3,precision=2) => toCurrency(value,{division,unit,precision}), - - capital: value=>value, - dict, - error : (value, tips = 'ERROR') => value instanceof Error ? tips : value, - empty : (value) => value - }, - zh: { - $types: { - Date: value => `${value.getFullYear()}年${value.getMonth() + 1}月${value.getDate()}日 ${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒` - }, - // 日期 - date : value => `${value.getFullYear()}年${value.getMonth() + 1}月${value.getDate()}日`, - weekday : value => ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"][value.getDay()], - shortWeekDay : value => ["日","一","二","三","四","五","六"][value.getDay()] - monthName : value => ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"][value.getMonth()] - shorMonthName: value => ["一","二","三","四","五","六","七","八","九","十","十一","十二"][value.getMonth()] - // 时间 - time : value => `${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒` - - // 数字 - number : (value,isBig=false) => toChineseNumber(value,isBig), // 转换为中文数字 - - // 货币 - currency: (value,unit="¥",division=4,precision=2) => toCurrency(value,{division,unit,precision}), - }, - en: { } -} \ No newline at end of file diff --git a/packages/runtime/formatters/common.js b/packages/runtime/formatters/common.js new file mode 100644 index 0000000..07b22fa --- /dev/null +++ b/packages/runtime/formatters/common.js @@ -0,0 +1,40 @@ + /** + * 字典格式化器 + * 根据输入data的值,返回后续参数匹配的结果 + * dict(data,,,,,,,...) + * + * + * dict(1,1,"one",2,"two",3,"three",4,"four") == "one" + * dict(2,1,"one",2,"two",3,"three",4,"four") == "two" + * dict(3,1,"one",2,"two",3,"three",4,"four") == "three" + * dict(4,1,"one",2,"two",3,"three",4,"four") == "four" + * // 无匹配时返回原始值 + * dict(5,1,"one",2,"two",3,"three",4,"four") == 5 + * // 无匹配时并且后续参数个数是奇数,则返回最后一个参数 + * dict(5,1,"one",2,"two",3,"three",4,"four","more") == "more" + * + * 在翻译中使用 + * I have { value | dict(1,"one",2,"two",3,"three",4,"four")} apples + * + * 为什么不使用 {value | dict({1:"one",2:"two",3:"three",4:"four"})}的形式更加自然? + * + * 因为我们是采用正则表达式来对格式化器的语法进行解释的,目前无法支持复杂的数据类型,只能支持简单的形式 + * + * + * @param {*} value + * @param {...any} args + * @returns + */ + function dict(value, ...args) { + for (let i = 0; i < args.length; i += 2) { + if (args[i] === value) { + return args[i + 1] + } + } + if (args.length > 0 && (args.length % 2 !== 0)) return args[args.length - 1] + return value + } + + module.exports = { + dict + } \ No newline at end of file diff --git a/packages/runtime/formatters/en.js b/packages/runtime/formatters/en.js new file mode 100644 index 0000000..4650d38 --- /dev/null +++ b/packages/runtime/formatters/en.js @@ -0,0 +1,40 @@ +/** + * 日期时间格式化器 + * + */ + + const { toDate,toCurrency } = require("../utils") + + module.exports = { + $types: { + Date : value => { const d = toDate(value); return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()} ${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}` }, + Null : value =>"", + Undefined: value =>"", + Error : value => "ERROR" + }, + // 日期 + date : value => { const d = toDate(value); return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}` }, + shortdate : value => { const d = toDate(value); return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}` }, + time : value => { const d = toDate(value); return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}` }, + shorttime : value => { const d = toDate(value); return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}` }, + year : value => toDate(value).getFullYear(), + month : value => toDate(value).getMonth() + 1, + day : value => toDate(value).getDate(), + weekdayValue : value => toDate(value).getDay(), + weekday : value => ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][toDate(value).getDay()], + shortWeekday : value => ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur"][toDate(value).getDay()], + monthName : value => ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][toDate(value).getMonth()], + shorMonthName : value => ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"][toDate(value).getMonth()], + // 时间 + hour : value => toDate(value).getHours(), + hour12 : value => {const hour = toDate(value).getHours(); return hour > 12 ? hour - 12 : thour}, + minute : value => toDate(value).getMinutes(), + second : value => toDate(value).getSeconds(), + millisecond : value => toDate(value).getMilliseconds(), + timestamp : value => toDate(value).getTime(), + // 货币 + // 常规货币形式 $111,233.33 + currency: (value, prefix = "$",suffix="", division = 3,precision = 2) => toCurrency(value, { division, prefix, precision,suffix }), + // 数字,如,使用分割符 + number: (value, division = 3,precision = 0) => toCurrency(value, { division, precision}) +} \ No newline at end of file diff --git a/packages/runtime/formatters/index.js b/packages/runtime/formatters/index.js new file mode 100644 index 0000000..024c658 --- /dev/null +++ b/packages/runtime/formatters/index.js @@ -0,0 +1,15 @@ +/** + * 内置的格式化器 + */ + +const enFormatters = require("./en") +const zhFormatters = require("./zh") +const commonFormatters = require("./common") + +module.exports = { + "*":{ + ...enFormatters, + ...commonFormatters + }, + zh:zhFormatters +} \ No newline at end of file diff --git a/packages/runtime/formatters/zh.js b/packages/runtime/formatters/zh.js new file mode 100644 index 0000000..5559341 --- /dev/null +++ b/packages/runtime/formatters/zh.js @@ -0,0 +1,28 @@ +/** + * 简体中文格式化器 + * + */ + + const { toChineseCurrency,toChineseNumber,CN_WEEK_DAYS,CN_SHORT_WEEK_DAYS, CN_MONTH_NAMES, CN_SHORT_MONTH_NAMES} = require("../cnutils") + const { toDate, toCurrency } = require("../utils") + + +module.exports = {// 简体中文 + $types: { + Date: value => {const d = toDate(value);return `${d.getFullYear()}年${d.getMonth() + 1}月${d.getDate()}日 ${d.getHours()}点${d.getMinutes()}分${d.getSeconds()}秒`} + }, + // 日期 + date : value => `${value.getFullYear()}年${value.getMonth() + 1}月${value.getDate()}日`, + weekday : value => CN_WEEK_DAYS[toDate(value).getDay()], + shortWeekDay : value => CN_SHORT_WEEK_DAYS[toDate(value).getDay()], + monthName : value => CN_MONTH_NAMES[toDate(value).getMonth()], + shorMonthName: value => CN_SHORT_MONTH_NAMES[toDate(value).getMonth()], + // 时间 + time : value =>{const d = toDate(value);return `${d.getHours()}点${d.getMinutes()}分${d.getSeconds()}秒`}, + // 货币 + currency : (value,prefix = "¥",suffix="", division = 4, precision = 2) => toCurrency(value, { division, prefix, precision,suffix }), + // 中文货币,big=true代表大写形式 + capitalizeCurrency:(value,big,unit="元",prefix,suffix)=>toChineseCurrency(value,{big,prefix,suffix,unit}), + // 中文数字,如一千二百三十一 + number:(value,isBig)=>toChineseNumber(value,isBig) +} \ No newline at end of file diff --git a/packages/runtime/index.js b/packages/runtime/index.js index 1655fea..d741f77 100644 --- a/packages/runtime/index.js +++ b/packages/runtime/index.js @@ -428,7 +428,10 @@ const defaultLanguageSettings = { {name:"zh",title:"中文",default:true}, {name:"en",title:"英文"} ], - formatters:inlineFormatters + formatters:inlineFormatters, + datetime:{ + + }, } function isMessageId(content){ @@ -643,16 +646,18 @@ function translate(message) { * registerFormatters(name,value=>{...},{langauge:"en"}) // 适用于en语言 * @param {*} formatters + language : 声明该格式化器适用语言 + isGlobal : 注册到全局 */ - registerFormatter(name,formatter,{language="*"}={}){ + registerFormatter(name,formatter,{language="*",isGlobal}={}){ if(!typeof(formatter)==="function" || typeof(name)!=="string"){ throw new TypeError("Formatter must be a function") - } + } if(DataTypes.includes(name)){ this.formatters[language].$types[name] = formatter }else{ this.formatters[language][name] = formatter - } + } } /** * 注册默认文本信息加载器 @@ -673,6 +678,27 @@ function translate(message) { }catch{} } +} +/** + * 创建格式化器 + * @param {*} fn + * @param {*} options = { + * erorr:(e)=>{...} //执行出错时返回值 + * empty:()=>{...} // 当空值时的返回值 * + * } + * + */ +function createFormatter(fn,options){ + if(isPlainObject(options)) fn._options = options + return fn.bind(fn._options) +} + +/** + * 扩展格式化器 + * @param {*} fn + */ +function extendFormatter(fn){ + } module.exports ={ diff --git a/packages/runtime/scope.js b/packages/runtime/scope.js index c79dbef..37dc7bb 100644 --- a/packages/runtime/scope.js +++ b/packages/runtime/scope.js @@ -8,7 +8,7 @@ module.exports = class i18nScope { this._id = options.id || (new Date().getTime().toString()+parseInt(Math.random()*1000)) this._languages = options.languages // 当前作用域的语言列表 this._defaultLanguage = options.defaultLanguage || "zh" // 默认语言名称 - this._activeLanguage = options.activeLanguage // 当前语言名称 + this._activeLanguage = options.activeLanguage // 当前语言名称 this._default = options.default // 默认语言包 this._messages = options.messages // 当前语言包 this._idMap = options.idMap // 消息id映射列表 @@ -54,7 +54,7 @@ module.exports = class i18nScope { get idMap(){return this._idMap} // 当前作用域的格式化函数列表 get formatters(){return this._formatters} - // 当前作用域支持的语言 + // 当前作用域支持的语言列表[{name,title,fallback}] get languages(){return this._languages} // 异步加载语言文件的函数列表 get loaders(){return this._loaders} @@ -63,21 +63,37 @@ module.exports = class i18nScope { set global(value){this._global = value} /** * 在全局注册作用域 - * @param {*} callback 当注册 + * @param {*} callback 注册成功后的回调 */ register(callback){ if(!typeof(callback)==="function") callback = ()=>{} this.global.register(this).then(callback).catch(callback) } - registerFormatter(name,formatter,{language="*"}={}){ + /** + * 注册格式化器 + * 格式化器是一个简单的同步函数value=>{...},用来对输入进行格式化后返回结果 + * + * registerFormatters(name,value=>{...}) // 适用于所有语言 + * registerFormatters(name,value=>{...},{langauge:"zh"}) // 适用于cn语言 + * registerFormatters(name,value=>{...},{langauge:"en"}) // 适用于en语言 + + * @param {*} formatters + language : 声明该格式化器适用语言 + isGlobal : 注册到全局 + */ + registerFormatter(name,formatter,{language="*",isGlobal}={}){ if(!typeof(formatter)==="function" || typeof(name)!=="string"){ throw new TypeError("Formatter must be a function") } - if(DataTypes.includes(name)){ - this.formatters[language].$types[name] = formatter + if(isGlobal){ + this.global.registerFormatter(name,formatter,{language}) }else{ - this.formatters[language][name] = formatter - } + if(DataTypes.includes(name)){ + this.formatters[language].$types[name] = formatter + }else{ + this.formatters[language][name] = formatter + } + } } /** * 注册默认文本信息加载器 diff --git a/packages/runtime/utils.js b/packages/runtime/utils.js index 1d41169..c7f1af1 100644 --- a/packages/runtime/utils.js +++ b/packages/runtime/utils.js @@ -42,29 +42,30 @@ } } - /** - * 简单进行对象合并 + * 深度合并对象 * - * options={ - * array:0 , // 数组合并策略,0-替换,1-合并,2-去重合并 - * } + * 注意: + * - 不会对数组成员进行再次遍历 + * - 不能处理循环引入 * * @param {*} toObj * @param {*} formObj - * @returns 合并后的对象 + * @param {*} options + * array : 数组合并策略,0-替换,1-合并,2-去重合并 + * mixin : 是否采用混入方式来,=false, 则会创建新对象并返回 */ function deepMerge(toObj,formObj,options={}){ - let results = Object.assign({},toObj) + let results = options.mixin ? toObj : Object.assign({},toObj) Object.entries(formObj).forEach(([key,value])=>{ if(key in results){ if(typeof value === "object" && value !== null){ if(Array.isArray(value)){ - if(options.array === 0){ + if(options.array === 0){//替换 results[key] = value - }else if(options.array === 1){ + }else if(options.array === 1){//合并 results[key] = [...results[key],...value] - }else if(options.array === 2){ + }else if(options.array === 2){//去重合并 results[key] = [...new Set([...results[key],...value])] } }else{ @@ -80,6 +81,10 @@ function deepMerge(toObj,formObj,options={}){ return results } + +function deepMixin(toObj,formObj,options={}){ + return deepMerge(toObj,formObj,{...options,mixin:true}) +} /** * 获取指定变量类型名称 @@ -99,14 +104,78 @@ function deepMerge(toObj,formObj,options={}){ if(typeof(v)==="function") return "Function" return v.constructor && v.constructor.name; }; +/** + * 格式化日期 + * 将值转换为Date类型 + * @param {*} value + */ +function toDate(value) { + try { + return value instanceof Date ? value : new Date(value) + } catch { + return value + } +} +/** + * 转换为数字类型 + */ +function toNumber(value,defualt=0) { + try { + if (isNumber(value)) { + return parseInt(value) + } else { + return defualt + } + } catch { + return value + } +} +/** + * 转换为货币格式 + * + * @param {*} value 可以是数字也可以是字符串 + * @param {*} division 分割符号位数,3代表每3个数字添加一个,号 + * @param {*} prefix 前缀,货币单位 + * @param {*} suffix 前缀,货币单位 + * @param {*} precision 小数点精确到几位,0-自动 + * @returns + */ + function toCurrency(value,{division=3,prefix="",precision=0,suffix=""}={}){ + let [wholeValue,decimalValue] = String(value).split(".") + let result = [] + for(let i=0;i0) result.push(",") + result.push(wholeValue[i]) + } + if(decimalValue){ + if(precision>0){ + decimalValue = String(parseFloat(`0.${decimalValue}`).toFixed(precision)).split(".")[1] + } + result.push(`.${decimalValue}`) + } + return prefix + result.join("") + suffix +} +/** + * 返回value相对rel的相对时间 + * + * 如:12分钟前, 6秒前, 1小时 + * + * + * + */ +function relativeTime(value, rel){ - +} module.exports ={ isPlainObject, isNumber, deepMerge, - getDataTypeName + deepMixin, + getDataTypeName, + toDate, + toNumber, + toCurrency } \ No newline at end of file