update typescript for react
This commit is contained in:
parent
5b12aaa7f4
commit
5904297e35
@ -8,8 +8,11 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/runtime-corejs3": "^7.20.7",
|
||||||
"@voerkai18n/react": "workspace:^1.0.0",
|
"@voerkai18n/react": "workspace:^1.0.0",
|
||||||
|
"@voerkai18n/runtime": "workspace:^1.1.9",
|
||||||
"@voerkai18n/vite": "workspace:^1.0.7",
|
"@voerkai18n/vite": "workspace:^1.0.7",
|
||||||
|
"core-js": "^3.27.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2"
|
"react-dom": "^17.0.2"
|
||||||
},
|
},
|
||||||
|
@ -4,15 +4,15 @@ import './App.css'
|
|||||||
import "./main"
|
import "./main"
|
||||||
import Banner from './components/Banner'
|
import Banner from './components/Banner'
|
||||||
import LanguageConfigurator from "./components/LanguageConfigurator.jsx"
|
import LanguageConfigurator from "./components/LanguageConfigurator.jsx"
|
||||||
import { useVoerkaI18n } from "@voerkai18n/react";
|
import { VoerkaI18nProvider,useVoerkaI18n } from "@voerkai18n/react";
|
||||||
|
import { i18nScope } from "./languages"
|
||||||
|
|
||||||
|
function RootLayout(){
|
||||||
function App() {
|
const { t } = useVoerkaI18n();
|
||||||
const { activeLanguage, changeLanguage, languages } = useVoerkaI18n();
|
return (
|
||||||
return (
|
<div className="App">
|
||||||
<div className="App">
|
|
||||||
<header className="App-header">
|
<header className="App-header">
|
||||||
<div>{t("Voerkai1n是一个功能强大设计精良的国际化解决方案")}</div>
|
<div>{t("Voerkai1n是一个功能强大设计精良的国际化解决方案")}</div>
|
||||||
<LanguageConfigurator/>
|
<LanguageConfigurator/>
|
||||||
<div>
|
<div>
|
||||||
<Banner memo={t("这是一个测试")} />
|
<Banner memo={t("这是一个测试")} />
|
||||||
@ -25,8 +25,17 @@ function App() {
|
|||||||
学习VoerkaI18n
|
学习VoerkaI18n
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<button onClick={()=>setLanguage('en')}>ddddd</button>
|
||||||
</header>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<VoerkaI18nProvider scope={i18nScope}>
|
||||||
|
<RootLayout/>
|
||||||
|
</VoerkaI18nProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { useState } from 'react'
|
import { useVoerkaI18n } from '@voerkai18n/react'
|
||||||
|
import React,{ useState } from 'react'
|
||||||
|
|
||||||
function Banner( props ) {
|
function Banner( props ) {
|
||||||
|
const { t } = useVoerkaI18n()
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>{t("一字一世界,一笔一乾坤,汉字是这个星球上最美的语言")}</h2>
|
<h2>{t("一字一世界,一笔一乾坤,汉字是这个星球上最美的语言")}</h2>
|
||||||
@ -9,4 +11,4 @@ function Banner( props ) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Banner
|
export default React.memo(Banner)
|
||||||
|
@ -2,10 +2,10 @@ import { useState } from "react";
|
|||||||
import { useVoerkaI18n } from "@voerkai18n/react"
|
import { useVoerkaI18n } from "@voerkai18n/react"
|
||||||
|
|
||||||
function LanguageConfigurator(props) {
|
function LanguageConfigurator(props) {
|
||||||
const { activeLanguage, changeLanguage, languages } = useVoerkaI18n();
|
const { language, changeLanguage, languages,t } = useVoerkaI18n();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>{t("当前语言")}:{ activeLanguage }</div>
|
<div>{t("当前语言")}:{ language }</div>
|
||||||
<div>
|
<div>
|
||||||
{languages.map((lang) => {
|
{languages.map((lang) => {
|
||||||
return (
|
return (
|
||||||
|
113
packages/apps/reactapp/src/languages/formatters/en.js
Normal file
113
packages/apps/reactapp/src/languages/formatters/en.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
格式化器用来对翻译文本内容中的插值变量进行处理
|
||||||
|
|
||||||
|
如何编写格式器请参阅官网!
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// import { Formatter,FlexFormatter } from "./runtime"
|
||||||
|
export default {
|
||||||
|
// global : true, // 简单地设置为true,代表当前所有格式化器均注册到全局,false只在当前scope生效
|
||||||
|
// global : { // 仅将里面的格式化器注册到全局
|
||||||
|
// $config:{... }
|
||||||
|
// xxxx : value => { ... },
|
||||||
|
// xxxx : (value,$config) => { ... },
|
||||||
|
// xxxx : (value,...args,$config) => { ... },
|
||||||
|
// xxxx : Formatter(value,...args,$config) => { ... },
|
||||||
|
// xxxx : FlexFormatter(value,params,$config) => { ... },
|
||||||
|
//}, // 是否注册到全局,false只在当前scope生效
|
||||||
|
// 直接对内置格式化器进行配置,请参阅官网文档
|
||||||
|
// $config:{
|
||||||
|
// datetime : {
|
||||||
|
// units : ["Year","Quarter","Month","Week","Day","Hour","Minute","Second","Millisecond","Microsecond"],
|
||||||
|
// date :{
|
||||||
|
// long : 'YYYY/MM/DD HH:mm:ss',
|
||||||
|
// short : "YYYY/MM/DD",
|
||||||
|
// format : "local"
|
||||||
|
// },
|
||||||
|
// quarter : {
|
||||||
|
// long : ["First Quarter","Second Quarter","Third Quarter","Fourth Quarter"],
|
||||||
|
// short : ["Q1","Q2","Q3","Q4"],
|
||||||
|
// format : "short"
|
||||||
|
// },
|
||||||
|
// month:{
|
||||||
|
// long : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
||||||
|
// short : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"],
|
||||||
|
// format : "long" // 0-长名称,1-短名称,2-数字
|
||||||
|
// },
|
||||||
|
// weekday:{
|
||||||
|
// long : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
||||||
|
// short : ["Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"],
|
||||||
|
// format : "long", // 0-长名称,1-短名称,2-数字
|
||||||
|
// },
|
||||||
|
// time : {
|
||||||
|
// long : "HH:mm:ss",
|
||||||
|
// short : "HH:mm:ss",
|
||||||
|
// format : 'local'
|
||||||
|
// },
|
||||||
|
// timeSlots : {
|
||||||
|
// slots : [12],
|
||||||
|
// lowerCases : ["am","pm"],
|
||||||
|
// upperCases : ["AM","PM"]
|
||||||
|
// },
|
||||||
|
// relativeTime : {
|
||||||
|
// units : ["seconds","minutes","hours","days","weeks","months","years"],
|
||||||
|
// now : "Now",
|
||||||
|
// before : "{value} {unit} ago",
|
||||||
|
// after : "after {value} {unit}"
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// currency : {
|
||||||
|
// default : "{symbol}{value}{unit}",
|
||||||
|
// long : "{prefix} {symbol}{value}{unit}{suffix}",
|
||||||
|
// short : "{symbol}{value}{unit}",
|
||||||
|
// custom : "{prefix} {symbol}{value}{unit}{suffix}",
|
||||||
|
// format : "default",
|
||||||
|
// //--
|
||||||
|
// units : [""," thousands"," millions"," billions"," trillions"], //千,百万,十亿,万亿
|
||||||
|
// radix : 3, // 进制,即三位一进,中文是4位一进
|
||||||
|
// symbol : "$", // 符号
|
||||||
|
// prefix : "USD", // 前缀
|
||||||
|
// suffix : "", // 后缀
|
||||||
|
// division : 3, // ,分割位
|
||||||
|
// precision : 2, // 精度
|
||||||
|
|
||||||
|
// },
|
||||||
|
// number : {
|
||||||
|
// division : 3, // , 分割位,3代表每3位添加一个,
|
||||||
|
// precision : 0 // 精度,即保留小数点位置,0代表不限
|
||||||
|
// },
|
||||||
|
// empty:{
|
||||||
|
// //values : [], // 可选,定义空值,如果想让0,''也为空值,可以指定values=[0,'']
|
||||||
|
// escape : "", // 当空值时显示的备用值
|
||||||
|
// next : 'break' // 当空值时下一步的行为: break=中止;skip=跳过
|
||||||
|
// },
|
||||||
|
// error : {
|
||||||
|
// //当错误时显示的内容,支持的插值变量有message=错误信息,error=错误类名,也可以是一个返回上面内容的同步函数
|
||||||
|
// escape : null, // 默认当错误时显示空内容
|
||||||
|
// next : 'break' // 当出错时下一步的行为: break=中止;skip=忽略
|
||||||
|
// },
|
||||||
|
// fileSize:{
|
||||||
|
// brief : ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB","NB","DB"],
|
||||||
|
// whole : ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "TeraBytes", "PetaBytes", "ExaBytes", "ZetaBytes", "YottaBytes","DoggaBytes"],
|
||||||
|
// precision: 2 // 小数精度
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// 改变特定数据类型的默认格式化器
|
||||||
|
// $types:{
|
||||||
|
// Date : dateFormatter,
|
||||||
|
// Null : value =>"",
|
||||||
|
// Undefined: value =>"",
|
||||||
|
// Error : value => "ERROR",
|
||||||
|
// Boolean : value =>value ? "True":"False",
|
||||||
|
// Number : numberFormartter
|
||||||
|
// }
|
||||||
|
// 以下可以自定义编写格式化器
|
||||||
|
// xxxx : value => { ... },
|
||||||
|
// xxxx : (value,$config) => { ... },
|
||||||
|
// xxxx : (value,...args,$config) => { ... },
|
||||||
|
// xxxx : Formatter(value,...args,$config) => { ... },
|
||||||
|
// xxxx : FlexFormatter(value,params,$config) => { ... },
|
||||||
|
}
|
113
packages/apps/reactapp/src/languages/formatters/zh.js
Normal file
113
packages/apps/reactapp/src/languages/formatters/zh.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
格式化器用来对翻译文本内容中的插值变量进行处理
|
||||||
|
|
||||||
|
如何编写格式器请参阅官网!
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// import { Formatter,FlexFormatter } from "./runtime"
|
||||||
|
export default {
|
||||||
|
// global : true, // 简单地设置为true,代表当前所有格式化器均注册到全局,false只在当前scope生效
|
||||||
|
// global : { // 仅将里面的格式化器注册到全局
|
||||||
|
// $config:{... }
|
||||||
|
// xxxx : value => { ... },
|
||||||
|
// xxxx : (value,$config) => { ... },
|
||||||
|
// xxxx : (value,...args,$config) => { ... },
|
||||||
|
// xxxx : Formatter(value,...args,$config) => { ... },
|
||||||
|
// xxxx : FlexFormatter(value,params,$config) => { ... },
|
||||||
|
//}, // 是否注册到全局,false只在当前scope生效
|
||||||
|
// 直接对内置格式化器进行配置,请参阅官网文档
|
||||||
|
// $config:{
|
||||||
|
// datetime : {
|
||||||
|
// units : ["Year","Quarter","Month","Week","Day","Hour","Minute","Second","Millisecond","Microsecond"],
|
||||||
|
// date :{
|
||||||
|
// long : 'YYYY/MM/DD HH:mm:ss',
|
||||||
|
// short : "YYYY/MM/DD",
|
||||||
|
// format : "local"
|
||||||
|
// },
|
||||||
|
// quarter : {
|
||||||
|
// long : ["First Quarter","Second Quarter","Third Quarter","Fourth Quarter"],
|
||||||
|
// short : ["Q1","Q2","Q3","Q4"],
|
||||||
|
// format : "short"
|
||||||
|
// },
|
||||||
|
// month:{
|
||||||
|
// long : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
||||||
|
// short : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"],
|
||||||
|
// format : "long" // 0-长名称,1-短名称,2-数字
|
||||||
|
// },
|
||||||
|
// weekday:{
|
||||||
|
// long : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
||||||
|
// short : ["Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"],
|
||||||
|
// format : "long", // 0-长名称,1-短名称,2-数字
|
||||||
|
// },
|
||||||
|
// time : {
|
||||||
|
// long : "HH:mm:ss",
|
||||||
|
// short : "HH:mm:ss",
|
||||||
|
// format : 'local'
|
||||||
|
// },
|
||||||
|
// timeSlots : {
|
||||||
|
// slots : [12],
|
||||||
|
// lowerCases : ["am","pm"],
|
||||||
|
// upperCases : ["AM","PM"]
|
||||||
|
// },
|
||||||
|
// relativeTime : {
|
||||||
|
// units : ["seconds","minutes","hours","days","weeks","months","years"],
|
||||||
|
// now : "Now",
|
||||||
|
// before : "{value} {unit} ago",
|
||||||
|
// after : "after {value} {unit}"
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// currency : {
|
||||||
|
// default : "{symbol}{value}{unit}",
|
||||||
|
// long : "{prefix} {symbol}{value}{unit}{suffix}",
|
||||||
|
// short : "{symbol}{value}{unit}",
|
||||||
|
// custom : "{prefix} {symbol}{value}{unit}{suffix}",
|
||||||
|
// format : "default",
|
||||||
|
// //--
|
||||||
|
// units : [""," thousands"," millions"," billions"," trillions"], //千,百万,十亿,万亿
|
||||||
|
// radix : 3, // 进制,即三位一进,中文是4位一进
|
||||||
|
// symbol : "$", // 符号
|
||||||
|
// prefix : "USD", // 前缀
|
||||||
|
// suffix : "", // 后缀
|
||||||
|
// division : 3, // ,分割位
|
||||||
|
// precision : 2, // 精度
|
||||||
|
|
||||||
|
// },
|
||||||
|
// number : {
|
||||||
|
// division : 3, // , 分割位,3代表每3位添加一个,
|
||||||
|
// precision : 0 // 精度,即保留小数点位置,0代表不限
|
||||||
|
// },
|
||||||
|
// empty:{
|
||||||
|
// //values : [], // 可选,定义空值,如果想让0,''也为空值,可以指定values=[0,'']
|
||||||
|
// escape : "", // 当空值时显示的备用值
|
||||||
|
// next : 'break' // 当空值时下一步的行为: break=中止;skip=跳过
|
||||||
|
// },
|
||||||
|
// error : {
|
||||||
|
// //当错误时显示的内容,支持的插值变量有message=错误信息,error=错误类名,也可以是一个返回上面内容的同步函数
|
||||||
|
// escape : null, // 默认当错误时显示空内容
|
||||||
|
// next : 'break' // 当出错时下一步的行为: break=中止;skip=忽略
|
||||||
|
// },
|
||||||
|
// fileSize:{
|
||||||
|
// brief : ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB","NB","DB"],
|
||||||
|
// whole : ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "TeraBytes", "PetaBytes", "ExaBytes", "ZetaBytes", "YottaBytes","DoggaBytes"],
|
||||||
|
// precision: 2 // 小数精度
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// 改变特定数据类型的默认格式化器
|
||||||
|
// $types:{
|
||||||
|
// Date : dateFormatter,
|
||||||
|
// Null : value =>"",
|
||||||
|
// Undefined: value =>"",
|
||||||
|
// Error : value => "ERROR",
|
||||||
|
// Boolean : value =>value ? "True":"False",
|
||||||
|
// Number : numberFormartter
|
||||||
|
// }
|
||||||
|
// 以下可以自定义编写格式化器
|
||||||
|
// xxxx : value => { ... },
|
||||||
|
// xxxx : (value,$config) => { ... },
|
||||||
|
// xxxx : (value,...args,$config) => { ... },
|
||||||
|
// xxxx : Formatter(value,...args,$config) => { ... },
|
||||||
|
// xxxx : FlexFormatter(value,params,$config) => { ... },
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
import messageIds from "./idMap.js"
|
import messageIds from "./idMap.js" // 语言ID映射文件
|
||||||
import runtime from "./runtime.js"
|
import runtime from "@voerkai18n/runtime"
|
||||||
const { translate,i18nScope } = runtime
|
const { translate,VoerkaI18nScope } = runtime
|
||||||
|
import defaultFormatters from "./formatters/zh"
|
||||||
import formatters from "./formatters.js"
|
const activeFormatters = defaultFormatters
|
||||||
import defaultMessages from "./zh.js"
|
import defaultMessages from "./zh.js"
|
||||||
const activeMessages = defaultMessages
|
const activeMessages = defaultMessages
|
||||||
|
|
||||||
@ -24,18 +24,25 @@ const scopeSettings = {
|
|||||||
"activeLanguage": "zh",
|
"activeLanguage": "zh",
|
||||||
"namespaces": {}
|
"namespaces": {}
|
||||||
}
|
}
|
||||||
|
const formatters = {
|
||||||
|
'zh' : defaultFormatters,
|
||||||
|
'en' : ()=>import("./formatters/en.js")
|
||||||
|
}
|
||||||
|
// 语言包加载器
|
||||||
|
const loaders = {
|
||||||
|
"en" : ()=>import("./en.js")
|
||||||
|
}
|
||||||
|
|
||||||
// 语言作用域
|
// 语言作用域
|
||||||
const scope = new i18nScope({
|
const scope = new VoerkaI18nScope({
|
||||||
...scopeSettings, // languages,defaultLanguage,activeLanguage,namespaces,formatters
|
...scopeSettings, // languages,defaultLanguage,activeLanguage,namespaces,formatters
|
||||||
id: "reactapp", // 当前作用域的id,自动取当前工程的package.json的name
|
id : "reactapp", // 当前作用域的id,自动取当前工程的package.json的name
|
||||||
default: defaultMessages, // 默认语言包
|
debug : false, // 是否在控制台输出高度信息
|
||||||
messages : activeMessages, // 当前语言包
|
default : defaultMessages, // 默认语言包
|
||||||
idMap:messageIds, // 消息id映射列表
|
messages : activeMessages, // 当前语言包
|
||||||
formatters, // 当前作用域的格式化函数列表
|
idMap : messageIds, // 消息id映射列表
|
||||||
loaders:{
|
formatters, // 扩展自定义格式化器
|
||||||
"en" : ()=>import("./en.js")
|
loaders // 语言包加载器
|
||||||
}
|
|
||||||
})
|
})
|
||||||
// 翻译函数
|
// 翻译函数
|
||||||
const scopedTtranslate = translate.bind(scope)
|
const scopedTtranslate = translate.bind(scope)
|
||||||
|
@ -1,936 +0,0 @@
|
|||||||
/**
|
|
||||||
* 判断是否是JSON对象
|
|
||||||
* @param {*} obj
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function isPlainObject$1(obj){
|
|
||||||
if (typeof obj !== 'object' || obj === null) return false;
|
|
||||||
var proto = Object.getPrototypeOf(obj);
|
|
||||||
if (proto === null) return true;
|
|
||||||
var baseProto = proto;
|
|
||||||
|
|
||||||
while (Object.getPrototypeOf(baseProto) !== null) {
|
|
||||||
baseProto = Object.getPrototypeOf(baseProto);
|
|
||||||
}
|
|
||||||
return proto === baseProto;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNumber$1(value){
|
|
||||||
return !isNaN(parseInt(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 简单进行对象合并
|
|
||||||
*
|
|
||||||
* options={
|
|
||||||
* array:0 , // 数组合并策略,0-替换,1-合并,2-去重合并
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @param {*} toObj
|
|
||||||
* @param {*} formObj
|
|
||||||
* @returns 合并后的对象
|
|
||||||
*/
|
|
||||||
function deepMerge$1(toObj,formObj,options={}){
|
|
||||||
let results = 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){
|
|
||||||
results[key] = value;
|
|
||||||
}else if(options.array === 1){
|
|
||||||
results[key] = [...results[key],...value];
|
|
||||||
}else if(options.array === 2){
|
|
||||||
results[key] = [...new Set([...results[key],...value])];
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
results[key] = deepMerge$1(results[key],value,options);
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
results[key] = value;
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
results[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定变量类型名称
|
|
||||||
* getDataTypeName(1) == Number
|
|
||||||
* getDataTypeName("") == String
|
|
||||||
* getDataTypeName(null) == Null
|
|
||||||
* getDataTypeName(undefined) == Undefined
|
|
||||||
* getDataTypeName(new Date()) == Date
|
|
||||||
* getDataTypeName(new Error()) == Error
|
|
||||||
*
|
|
||||||
* @param {*} v
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function getDataTypeName$1(v){
|
|
||||||
if (v === null) return 'Null'
|
|
||||||
if (v === undefined) return 'Undefined'
|
|
||||||
if(typeof(v)==="function") return "Function"
|
|
||||||
return v.constructor && v.constructor.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var utils ={
|
|
||||||
isPlainObject: isPlainObject$1,
|
|
||||||
isNumber: isNumber$1,
|
|
||||||
deepMerge: deepMerge$1,
|
|
||||||
getDataTypeName: getDataTypeName$1
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 简单的事件触发器
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
var eventemitter = class EventEmitter{
|
|
||||||
constructor(){
|
|
||||||
this._callbacks = [];
|
|
||||||
}
|
|
||||||
on(callback){
|
|
||||||
if(this._callbacks.includes(callback)) return
|
|
||||||
this._callbacks.push(callback);
|
|
||||||
}
|
|
||||||
off(callback){
|
|
||||||
for(let i=0;i<this._callbacks.length;i++){
|
|
||||||
if(this._callbacks[i]===callback ){
|
|
||||||
this._callbacks.splice(i,1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offAll(){
|
|
||||||
this._callbacks = [];
|
|
||||||
}
|
|
||||||
async emit(...args){
|
|
||||||
if(Promise.allSettled){
|
|
||||||
await Promise.allSettled(this._callbacks.map(cb=>cb(...args)));
|
|
||||||
}else {
|
|
||||||
await Promise.all(this._callbacks.map(cb=>cb(...args)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var scope = class i18nScope {
|
|
||||||
constructor(options={},callback){
|
|
||||||
// 每个作用域都有一个唯一的id
|
|
||||||
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._default = options.default; // 默认语言包
|
|
||||||
this._messages = options.messages; // 当前语言包
|
|
||||||
this._idMap = options.idMap; // 消息id映射列表
|
|
||||||
this._formatters = options.formatters; // 当前作用域的格式化函数列表
|
|
||||||
this._loaders = options.loaders; // 异步加载语言文件的函数列表
|
|
||||||
this._global = null; // 引用全局VoerkaI18n配置,注册后自动引用
|
|
||||||
// 主要用来缓存格式化器的引用,当使用格式化器时可以直接引用,避免检索
|
|
||||||
this.$cache={
|
|
||||||
activeLanguage : null,
|
|
||||||
typedFormatters: {},
|
|
||||||
formatters : {},
|
|
||||||
};
|
|
||||||
// 如果不存在全局VoerkaI18n实例,说明当前Scope是唯一或第一个加载的作用域,
|
|
||||||
// 则使用当前作用域来初始化全局VoerkaI18n实例
|
|
||||||
if(!globalThis.VoerkaI18n){
|
|
||||||
const { I18nManager } = runtime;
|
|
||||||
globalThis.VoerkaI18n = new I18nManager({
|
|
||||||
defaultLanguage: this.defaultLanguage,
|
|
||||||
activeLanguage : this.activeLanguage,
|
|
||||||
languages: options.languages,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.global = globalThis.VoerkaI18n;
|
|
||||||
// 正在加载语言包标识
|
|
||||||
this._loading=false;
|
|
||||||
// 在全局注册作用域
|
|
||||||
this.register(callback);
|
|
||||||
}
|
|
||||||
// 作用域
|
|
||||||
get id(){return this._id}
|
|
||||||
// 默认语言名称
|
|
||||||
get defaultLanguage(){return this._defaultLanguage}
|
|
||||||
// 默认语言名称
|
|
||||||
get activeLanguage(){return this._activeLanguage}
|
|
||||||
// 默认语言包
|
|
||||||
get default(){return this._default}
|
|
||||||
// 当前语言包
|
|
||||||
get messages(){return this._messages}
|
|
||||||
// 消息id映射列表
|
|
||||||
get idMap(){return this._idMap}
|
|
||||||
// 当前作用域的格式化函数列表
|
|
||||||
get formatters(){return this._formatters}
|
|
||||||
// 异步加载语言文件的函数列表
|
|
||||||
get loaders(){return this._loaders}
|
|
||||||
// 引用全局VoerkaI18n配置,注册后自动引用
|
|
||||||
get global(){return this._global}
|
|
||||||
set global(value){this._global = value;}
|
|
||||||
/**
|
|
||||||
* 在全局注册作用域
|
|
||||||
* @param {*} callback 当注册
|
|
||||||
*/
|
|
||||||
register(callback){
|
|
||||||
if(!typeof(callback)==="function") callback = ()=>{};
|
|
||||||
this.global.register(this).then(callback).catch(callback);
|
|
||||||
}
|
|
||||||
registerFormatter(name,formatter,{language="*"}={}){
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 回退到默认语言
|
|
||||||
*/
|
|
||||||
_fallback(){
|
|
||||||
this._messages = this._default;
|
|
||||||
this._activeLanguage = this.defaultLanguage;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 刷新当前语言包
|
|
||||||
* @param {*} newLanguage
|
|
||||||
*/
|
|
||||||
async refresh(newLanguage){
|
|
||||||
this._loading = Promise.resolve();
|
|
||||||
if(!newLanguage) newLanguage = this.activeLanguage;
|
|
||||||
// 默认语言,默认语言采用静态加载方式,只需要简单的替换即可
|
|
||||||
if(newLanguage === this.defaultLanguage){
|
|
||||||
this._messages = this._default;
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 非默认语言需要异步加载语言包文件,加载器是一个异步函数
|
|
||||||
// 如果没有加载器,则无法加载语言包,因此回退到默认语言
|
|
||||||
const loader = this.loaders[newLanguage];
|
|
||||||
if(typeof(loader) === "function"){
|
|
||||||
try{
|
|
||||||
this._messages = (await loader()).default;
|
|
||||||
this._activeLanguage = newLanguage;
|
|
||||||
}catch(e){
|
|
||||||
console.warn(`Error while loading language <${newLanguage}> on i18nScope(${this.id}): ${e.message}`);
|
|
||||||
this._fallback();
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
this._fallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 以下方法引用全局VoerkaI18n实例的方法
|
|
||||||
get on(){return this.global.on.bind(this.global)}
|
|
||||||
get off(){return this.global.off.bind(this.global)}
|
|
||||||
get offAll(){return this.global.offAll.bind(this.global)}
|
|
||||||
get change(){
|
|
||||||
return this.global.change.bind(this.global)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 内置的格式化器
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典格式化器
|
|
||||||
* 根据输入data的值,返回后续参数匹配的结果
|
|
||||||
* dict(data,<value1>,<result1>,<value2>,<result1>,<value3>,<result1>,...)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
|
|
||||||
var formatters = {
|
|
||||||
"*":{
|
|
||||||
$types:{
|
|
||||||
Date:(value)=>value.toLocaleString()
|
|
||||||
},
|
|
||||||
time:(value)=> value.toLocaleTimeString(),
|
|
||||||
shorttime:(value)=> value.toLocaleTimeString(),
|
|
||||||
date: (value)=> value.toLocaleDateString(),
|
|
||||||
dict, //字典格式化器
|
|
||||||
},
|
|
||||||
zh:{
|
|
||||||
$types:{
|
|
||||||
Date:(value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日 ${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`
|
|
||||||
},
|
|
||||||
shortime:(value)=> value.toLocaleTimeString(),
|
|
||||||
time:(value)=>`${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`,
|
|
||||||
date: (value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日`,
|
|
||||||
shortdate: (value)=> `${value.getFullYear()}-${value.getMonth()+1}-${value.getDate()}`,
|
|
||||||
currency:(value)=>`${value}元`,
|
|
||||||
},
|
|
||||||
en:{
|
|
||||||
currency:(value)=>{
|
|
||||||
return `$${value}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const { getDataTypeName,isNumber,isPlainObject,deepMerge } = utils;
|
|
||||||
const EventEmitter = eventemitter;
|
|
||||||
const i18nScope = scope;
|
|
||||||
let inlineFormatters = formatters; // 内置格式化器
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 用来提取字符里面的插值变量参数 , 支持管道符 { var | formatter | formatter }
|
|
||||||
// 不支持参数: let varWithPipeRegexp = /\{\s*(?<varname>\w+)?(?<formatters>(\s*\|\s*\w*\s*)*)\s*\}/g
|
|
||||||
|
|
||||||
// 支持参数: { var | formatter(x,x,..) | formatter }
|
|
||||||
let varWithPipeRegexp = /\{\s*(?<varname>\w+)?(?<formatters>(\s*\|\s*\w*(\(.*\)){0,1}\s*)*)\s*\}/g;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 考虑到通过正则表达式进行插件的替换可能较慢,因此提供一个简单方法来过滤掉那些
|
|
||||||
* 不需要进行插值处理的字符串
|
|
||||||
* 原理很简单,就是判断一下是否同时具有{和}字符,如果有则认为可能有插值变量,如果没有则一定没有插件变量,则就不需要进行正则匹配
|
|
||||||
* 从而可以减少不要的正则匹配
|
|
||||||
* 注意:该方法只能快速判断一个字符串不包括插值变量
|
|
||||||
* @param {*} str
|
|
||||||
* @returns {boolean} true=可能包含插值变量,
|
|
||||||
*/
|
|
||||||
function hasInterpolation(str){
|
|
||||||
return str.includes("{") && str.includes("}")
|
|
||||||
}
|
|
||||||
const DataTypes$1 = ["String","Number","Boolean","Object","Array","Function","Error","Symbol","RegExp","Date","Null","Undefined","Set","Map","WeakSet","WeakMap"];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
通过正则表达式对原始文本内容进行解析匹配后得到的
|
|
||||||
formatters="| aaa(1,1) | bbb "
|
|
||||||
|
|
||||||
需要统一解析为
|
|
||||||
|
|
||||||
[
|
|
||||||
[aaa,[1,1]], // [formatter'name,[args,...]]
|
|
||||||
[bbb,[]],
|
|
||||||
]
|
|
||||||
|
|
||||||
formatters="| aaa(1,1,"dddd") | bbb "
|
|
||||||
|
|
||||||
目前对参数采用简单的split(",")来解析,因为无法正确解析aaa(1,1,"dd,,dd")形式的参数
|
|
||||||
在此场景下基本够用了,如果需要支持更复杂的参数解析,可以后续考虑使用正则表达式来解析
|
|
||||||
|
|
||||||
@returns [[<formatterName>,[<arg>,<arg>,...]]]
|
|
||||||
*/
|
|
||||||
function parseFormatters(formatters){
|
|
||||||
if(!formatters) return []
|
|
||||||
// 1. 先解析为 ["aaa()","bbb"]形式
|
|
||||||
let result = formatters.trim().substr(1).trim().split("|").map(r=>r.trim());
|
|
||||||
|
|
||||||
// 2. 解析格式化器参数
|
|
||||||
return result.map(formatter=>{
|
|
||||||
let firstIndex = formatter.indexOf("(");
|
|
||||||
let lastIndex = formatter.lastIndexOf(")");
|
|
||||||
if(firstIndex!==-1 && lastIndex!==-1){ // 带参数的格式化器
|
|
||||||
const argsContent = formatter.substr(firstIndex+1,lastIndex-firstIndex-1).trim();
|
|
||||||
let args = argsContent=="" ? [] : argsContent.split(",").map(arg=>{
|
|
||||||
arg = arg.trim();
|
|
||||||
if(!isNaN(parseInt(arg))){
|
|
||||||
return parseInt(arg) // 数字
|
|
||||||
}else if((arg.startsWith('\"') && arg.endsWith('\"')) || (arg.startsWith('\'') && arg.endsWith('\'')) ){
|
|
||||||
return arg.substr(1,arg.length-2) // 字符串
|
|
||||||
}else if(arg.toLowerCase()==="true" || arg.toLowerCase()==="false"){
|
|
||||||
return arg.toLowerCase()==="true" // 布尔值
|
|
||||||
}else if((arg.startsWith('{') && arg.endsWith('}')) || (arg.startsWith('[') && arg.endsWith(']'))){
|
|
||||||
try{
|
|
||||||
return JSON.parse(arg)
|
|
||||||
}catch(e){
|
|
||||||
return String(arg)
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
return String(arg)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return [formatter.substr(0,firstIndex),args]
|
|
||||||
}else {// 不带参数的格式化器
|
|
||||||
return [formatter,[]]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提取字符串中的插值变量
|
|
||||||
* // [
|
|
||||||
// {
|
|
||||||
name:<变量名称>,formatters:[{name:<格式化器名称>,args:[<参数>,<参数>,....]]}],<匹配字符串>],
|
|
||||||
// ....
|
|
||||||
//
|
|
||||||
* @param {*} str
|
|
||||||
* @param {*} isFull =true 保留所有插值变量 =false 进行去重
|
|
||||||
* @returns {Array}
|
|
||||||
* [
|
|
||||||
* {
|
|
||||||
* name:"<变量名称>",
|
|
||||||
* formatters:[
|
|
||||||
* {name:"<格式化器名称>",args:[<参数>,<参数>,....]},
|
|
||||||
* {name:"<格式化器名称>",args:[<参数>,<参数>,....]},
|
|
||||||
* ],
|
|
||||||
* match:"<匹配字符串>"
|
|
||||||
* },
|
|
||||||
* ...
|
|
||||||
* ]
|
|
||||||
*/
|
|
||||||
function getInterpolatedVars(str){
|
|
||||||
let vars = [];
|
|
||||||
forEachInterpolatedVars(str,(varName,formatters,match)=>{
|
|
||||||
let varItem = {
|
|
||||||
name:varName,
|
|
||||||
formatters:formatters.map(([formatter,args])=>{
|
|
||||||
return {
|
|
||||||
name:formatter,
|
|
||||||
args:args
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
match:match
|
|
||||||
};
|
|
||||||
if(vars.findIndex(varDef=>((varDef.name===varItem.name) && (varItem.formatters.toString() == varDef.formatters.toString())))===-1){
|
|
||||||
vars.push(varItem);
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
});
|
|
||||||
return vars
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 遍历str中的所有插值变量传递给callback,将callback返回的结果替换到str中对应的位置
|
|
||||||
* @param {*} str
|
|
||||||
* @param {Function(<变量名称>,[formatters],match[0])} callback
|
|
||||||
* @returns 返回替换后的字符串
|
|
||||||
*/
|
|
||||||
function forEachInterpolatedVars(str,callback,options={}){
|
|
||||||
let result=str, match;
|
|
||||||
let opts = Object.assign({
|
|
||||||
replaceAll:true, // 是否替换所有插值变量,当使用命名插值时应置为true,当使用位置插值时应置为false
|
|
||||||
},options);
|
|
||||||
varWithPipeRegexp.lastIndex=0;
|
|
||||||
while ((match = varWithPipeRegexp.exec(result)) !== null) {
|
|
||||||
const varname = match.groups.varname || "";
|
|
||||||
// 解析格式化器和参数 = [<formatterName>,[<formatterName>,[<arg>,<arg>,...]]]
|
|
||||||
const formatters = parseFormatters(match.groups.formatters);
|
|
||||||
if(typeof(callback)==="function"){
|
|
||||||
try{
|
|
||||||
if(opts.replaceAll){
|
|
||||||
result=result.replaceAll(match[0],callback(varname,formatters,match[0]));
|
|
||||||
}else {
|
|
||||||
result=result.replace(match[0],callback(varname,formatters,match[0]));
|
|
||||||
}
|
|
||||||
}catch{// callback函数可能会抛出异常,如果抛出异常,则中断匹配过程
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
varWithPipeRegexp.lastIndex=0;
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetScopeCache(scope,activeLanguage=null){
|
|
||||||
scope.$cache = {activeLanguage,typedFormatters:{},formatters:{}};
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 取得指定数据类型的默认格式化器
|
|
||||||
*
|
|
||||||
* 可以为每一个数据类型指定一个默认的格式化器,当传入插值变量时,
|
|
||||||
* 会自动调用该格式化器来对值进行格式化转换
|
|
||||||
|
|
||||||
const formatters = {
|
|
||||||
"*":{
|
|
||||||
$types:{...} // 在所有语言下只作用于特定数据类型的格式化器
|
|
||||||
}, // 在所有语言下生效的格式化器
|
|
||||||
zh:{
|
|
||||||
$types:{
|
|
||||||
[数据类型]:(value)=>{...},
|
|
||||||
},
|
|
||||||
[格式化器名称]:(value)=>{...},
|
|
||||||
[格式化器名称]:(value)=>{...},
|
|
||||||
[格式化器名称]:(value)=>{...},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
* @param {*} scope
|
|
||||||
* @param {*} activeLanguage
|
|
||||||
* @param {*} dataType 数字类型
|
|
||||||
* @returns {Function} 格式化函数
|
|
||||||
*/
|
|
||||||
function getDataTypeDefaultFormatter(scope,activeLanguage,dataType){
|
|
||||||
if(!scope.$cache) resetScopeCache(scope);
|
|
||||||
if(scope.$cache.activeLanguage === activeLanguage) {
|
|
||||||
if(dataType in scope.$cache.typedFormatters) return scope.$cache.typedFormatters[dataType]
|
|
||||||
}else {// 当语言切换时清空缓存
|
|
||||||
resetScopeCache(scope,activeLanguage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先在当前作用域中查找,再在全局查找
|
|
||||||
const targets = [scope.formatters,scope.global.formatters];
|
|
||||||
for(const target of targets){
|
|
||||||
if(!target) continue
|
|
||||||
// 优先在当前语言的$types中查找
|
|
||||||
if((activeLanguage in target) && isPlainObject(target[activeLanguage].$types)){
|
|
||||||
let formatters = target[activeLanguage].$types;
|
|
||||||
if(dataType in formatters && typeof(formatters[dataType])==="function"){
|
|
||||||
return scope.$cache.typedFormatters[dataType] = formatters[dataType]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 在所有语言的$types中查找
|
|
||||||
if(("*" in target) && isPlainObject(target["*"].$types)){
|
|
||||||
let formatters = target["*"].$types;
|
|
||||||
if(dataType in formatters && typeof(formatters[dataType])==="function"){
|
|
||||||
return scope.$cache.typedFormatters[dataType] = formatters[dataType]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定名称的格式化器函数
|
|
||||||
* @param {*} scope
|
|
||||||
* @param {*} activeLanguage
|
|
||||||
* @param {*} name 格式化器名称
|
|
||||||
* @returns {Function} 格式化函数
|
|
||||||
*/
|
|
||||||
function getFormatter(scope,activeLanguage,name){
|
|
||||||
// 缓存格式化器引用,避免重复检索
|
|
||||||
if(!scope.$cache) resetScopeCache(scope);
|
|
||||||
if(scope.$cache.activeLanguage === activeLanguage) {
|
|
||||||
if(name in scope.$cache.formatters) return scope.$cache.formatters[name]
|
|
||||||
}else {// 当语言切换时清空缓存
|
|
||||||
resetScopeCache(scope,activeLanguage);
|
|
||||||
}
|
|
||||||
// 先在当前作用域中查找,再在全局查找
|
|
||||||
const targets = [scope.formatters,scope.global.formatters];
|
|
||||||
for(const target of targets){
|
|
||||||
// 优先在当前语言查找
|
|
||||||
if(activeLanguage in target){
|
|
||||||
let formatters = target[activeLanguage] || {};
|
|
||||||
if((name in formatters) && typeof(formatters[name])==="function") return scope.$cache.formatters[name] = formatters[name]
|
|
||||||
}
|
|
||||||
// 在所有语言的$types中查找
|
|
||||||
let formatters = target["*"] || {};
|
|
||||||
if((name in formatters) && typeof(formatters[name])==="function") return scope.$cache.formatters[name] = formatters[name]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行格式化器并返回结果
|
|
||||||
* @param {*} value
|
|
||||||
* @param {*} formatters 多个格式化器顺序执行,前一个输出作为下一个格式化器的输入
|
|
||||||
*/
|
|
||||||
function executeFormatter(value,formatters){
|
|
||||||
if(formatters.length===0) return value
|
|
||||||
let result = value;
|
|
||||||
try{
|
|
||||||
for(let formatter of formatters){
|
|
||||||
if(typeof(formatter) === "function") {
|
|
||||||
result = formatter(result);
|
|
||||||
}else {// 如果碰到无效的格式化器,则跳过过续的格式化器
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}catch(e){
|
|
||||||
console.error(`Error while execute i18n formatter for ${value}: ${e.message} ` );
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 将 [[格式化器名称,[参数,参数,...]],[格式化器名称,[参数,参数,...]]]格式化器转化为
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param {*} scope
|
|
||||||
* @param {*} activeLanguage
|
|
||||||
* @param {*} formatters
|
|
||||||
*/
|
|
||||||
function buildFormatters(scope,activeLanguage,formatters){
|
|
||||||
let results = [];
|
|
||||||
for(let formatter of formatters){
|
|
||||||
if(formatter[0]){
|
|
||||||
const func = getFormatter(scope,activeLanguage,formatter[0]);
|
|
||||||
if(typeof(func)==="function"){
|
|
||||||
results.push((v)=>{
|
|
||||||
return func(v,...formatter[1])
|
|
||||||
});
|
|
||||||
}else {
|
|
||||||
// 格式化器无效或者没有定义时,查看当前值是否具有同名的原型方法,如果有则执行调用
|
|
||||||
// 比如padStart格式化器是String的原型方法,不需要配置就可以直接作为格式化器调用
|
|
||||||
results.push((v)=>{
|
|
||||||
if(typeof(v[formatter[0]])==="function"){
|
|
||||||
return v[formatter[0]].call(v,...formatter[1])
|
|
||||||
}else {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将value经过格式化器处理后返回
|
|
||||||
* @param {*} scope
|
|
||||||
* @param {*} activeLanguage
|
|
||||||
* @param {*} formatters
|
|
||||||
* @param {*} value
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function getFormattedValue(scope,activeLanguage,formatters,value){
|
|
||||||
// 1. 取得格式化器函数列表
|
|
||||||
const formatterFuncs = buildFormatters(scope,activeLanguage,formatters);
|
|
||||||
// 2. 查找每种数据类型默认格式化器,并添加到formatters最前面,默认数据类型格式化器优先级最高
|
|
||||||
const defaultFormatter = getDataTypeDefaultFormatter(scope,activeLanguage,getDataTypeName(value));
|
|
||||||
if(defaultFormatter){
|
|
||||||
formatterFuncs.splice(0,0,defaultFormatter);
|
|
||||||
}
|
|
||||||
// 3. 执行格式化器
|
|
||||||
value = executeFormatter(value,formatterFuncs);
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符串可以进行变量插值替换,
|
|
||||||
* replaceInterpolatedVars("<模板字符串>",{变量名称:变量值,变量名称:变量值,...})
|
|
||||||
* replaceInterpolatedVars("<模板字符串>",[变量值,变量值,...])
|
|
||||||
* replaceInterpolatedVars("<模板字符串>",变量值,变量值,...])
|
|
||||||
*
|
|
||||||
- 当只有两个参数并且第2个参数是{}时,将第2个参数视为命名变量的字典
|
|
||||||
replaceInterpolatedVars("this is {a}+{b},{a:1,b:2}) --> this is 1+2
|
|
||||||
- 当只有两个参数并且第2个参数是[]时,将第2个参数视为位置参数
|
|
||||||
replaceInterpolatedVars"this is {}+{}",[1,2]) --> this is 1+2
|
|
||||||
- 普通位置参数替换
|
|
||||||
replaceInterpolatedVars("this is {a}+{b}",1,2) --> this is 1+2
|
|
||||||
-
|
|
||||||
this == scope == { formatters: {}, ... }
|
|
||||||
* @param {*} template
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function replaceInterpolatedVars(template,...args) {
|
|
||||||
const scope = this;
|
|
||||||
// 当前激活语言
|
|
||||||
const activeLanguage = scope.global.activeLanguage;
|
|
||||||
|
|
||||||
// 没有变量插值则的返回原字符串
|
|
||||||
if(args.length===0 || !hasInterpolation(template)) return template
|
|
||||||
|
|
||||||
// ****************************变量插值****************************
|
|
||||||
if(args.length===1 && isPlainObject(args[0])){
|
|
||||||
// 读取模板字符串中的插值变量列表
|
|
||||||
// [[var1,[formatter,formatter,...],match],[var2,[formatter,formatter,...],match],...}
|
|
||||||
let varValues = args[0];
|
|
||||||
return forEachInterpolatedVars(template,(varname,formatters)=>{
|
|
||||||
let value = (varname in varValues) ? varValues[varname] : '';
|
|
||||||
return getFormattedValue(scope,activeLanguage,formatters,value)
|
|
||||||
})
|
|
||||||
}else {
|
|
||||||
// ****************************位置插值****************************
|
|
||||||
// 如果只有一个Array参数,则认为是位置变量列表,进行展开
|
|
||||||
const params=(args.length===1 && Array.isArray(args[0])) ? [...args[0]] : args;
|
|
||||||
if(params.length===0) return template // 没有变量则不需要进行插值处理,返回原字符串
|
|
||||||
let i = 0;
|
|
||||||
return forEachInterpolatedVars(template,(varname,formatters)=>{
|
|
||||||
if(params.length>i){
|
|
||||||
return getFormattedValue(scope,activeLanguage,formatters,params[i++])
|
|
||||||
}else {
|
|
||||||
throw new Error() // 抛出异常,停止插值处理
|
|
||||||
}
|
|
||||||
},{replaceAll:false})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认语言配置
|
|
||||||
const defaultLanguageSettings = {
|
|
||||||
defaultLanguage: "zh",
|
|
||||||
activeLanguage: "zh",
|
|
||||||
languages:[
|
|
||||||
{name:"zh",title:"中文",default:true},
|
|
||||||
{name:"en",title:"英文"}
|
|
||||||
],
|
|
||||||
formatters:inlineFormatters
|
|
||||||
};
|
|
||||||
|
|
||||||
function isMessageId(content){
|
|
||||||
return parseInt(content)>0
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 根据值的单数和复数形式,从messages中取得相应的消息
|
|
||||||
*
|
|
||||||
* @param {*} messages 复数形式的文本内容 = [<=0时的内容>,<=1时的内容>,<=2时的内容>,...]
|
|
||||||
* @param {*} value
|
|
||||||
*/
|
|
||||||
function getPluraMessage(messages,value){
|
|
||||||
try{
|
|
||||||
if(Array.isArray(messages)){
|
|
||||||
return messages.length > value ? messages[value] : messages[messages.length-1]
|
|
||||||
}else {
|
|
||||||
return messages
|
|
||||||
}
|
|
||||||
}catch{
|
|
||||||
return Array.isArray(messages) ? messages[0] : messages
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function escape(str){
|
|
||||||
return str.replaceAll(/\\(?![trnbvf'"]{1})/g,"\\\\")
|
|
||||||
.replaceAll("\t","\\t")
|
|
||||||
.replaceAll("\n","\\n")
|
|
||||||
.replaceAll("\b","\\b")
|
|
||||||
.replaceAll("\r","\\r")
|
|
||||||
.replaceAll("\f","\\f")
|
|
||||||
.replaceAll("\'","\\'")
|
|
||||||
.replaceAll('\"','\\"')
|
|
||||||
.replaceAll('\v','\\v')
|
|
||||||
}
|
|
||||||
function unescape(str){
|
|
||||||
return str
|
|
||||||
.replaceAll("\\t","\t")
|
|
||||||
.replaceAll("\\n","\n")
|
|
||||||
.replaceAll("\\b","\b")
|
|
||||||
.replaceAll("\\r","\r")
|
|
||||||
.replaceAll("\\f","\f")
|
|
||||||
.replaceAll("\\'","\'")
|
|
||||||
.replaceAll('\\"','\"')
|
|
||||||
.replaceAll('\\v','\v')
|
|
||||||
.replaceAll(/\\\\(?![trnbvf'"]{1})/g,"\\")
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 翻译函数
|
|
||||||
*
|
|
||||||
* translate("要翻译的文本内容") 如果默认语言是中文,则不会进行翻译直接返回
|
|
||||||
* translate("I am {} {}","man") == I am man 位置插值
|
|
||||||
* translate("I am {p}",{p:"man"}) 字典插值
|
|
||||||
* translate("total {$count} items", {$count:1}) //复数形式
|
|
||||||
* translate("total {} {} {} items",a,b,c) // 位置变量插值
|
|
||||||
*
|
|
||||||
* this===scope 当前绑定的scope
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function translate(message) {
|
|
||||||
const scope = this;
|
|
||||||
const activeLanguage = scope.global.activeLanguage;
|
|
||||||
let content = message;
|
|
||||||
let vars=[]; // 插值变量列表
|
|
||||||
let pluralVars= []; // 复数变量
|
|
||||||
let pluraValue = null; // 复数值
|
|
||||||
if(!typeof(message)==="string") return message
|
|
||||||
try{
|
|
||||||
// 1. 预处理变量: 复数变量保存至pluralVars中 , 变量如果是Function则调用
|
|
||||||
if(arguments.length === 2 && isPlainObject(arguments[1])){
|
|
||||||
Object.entries(arguments[1]).forEach(([name,value])=>{
|
|
||||||
if(typeof(value)==="function"){
|
|
||||||
try{
|
|
||||||
vars[name] = value();
|
|
||||||
}catch(e){
|
|
||||||
vars[name] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 以$开头的视为复数变量
|
|
||||||
if(name.startsWith("$") && typeof(vars[name])==="number") pluralVars.push(name);
|
|
||||||
});
|
|
||||||
vars = [arguments[1]];
|
|
||||||
}else if(arguments.length >= 2){
|
|
||||||
vars = [...arguments].splice(1).map((arg,index)=>{
|
|
||||||
try{
|
|
||||||
arg = typeof(arg)==="function" ? arg() : arg;
|
|
||||||
// 位置参数中以第一个数值变量为复数变量
|
|
||||||
if(isNumber(arg)) pluraValue = parseInt(arg);
|
|
||||||
}catch(e){ }
|
|
||||||
return arg
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 3. 取得翻译文本模板字符串
|
|
||||||
if(activeLanguage === scope.defaultLanguage){
|
|
||||||
// 2.1 从默认语言中取得翻译文本模板字符串
|
|
||||||
// 如果当前语言就是默认语言,不需要查询加载,只需要做插值变换即可
|
|
||||||
// 当源文件运用了babel插件后会将原始文本内容转换为msgId
|
|
||||||
// 如果是msgId则从scope.default中读取,scope.default=默认语言包={<id>:<message>}
|
|
||||||
if(isMessageId(content)){
|
|
||||||
content = scope.default[content] || message;
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
// 2.2 从当前语言包中取得翻译文本模板字符串
|
|
||||||
// 如果没有启用babel插件将源文本转换为msgId,需要先将文本内容转换为msgId
|
|
||||||
// JSON.stringify在进行转换时会将\t\n\r转换为\\t\\n\\r,这样在进行匹配时就出错
|
|
||||||
let msgId = isMessageId(content) ? content : scope.idMap[escape(content)];
|
|
||||||
content = scope.messages[msgId] || content;
|
|
||||||
content = Array.isArray(content) ? content.map(v=>unescape(v)) : unescape(content);
|
|
||||||
}
|
|
||||||
// 2. 处理复数
|
|
||||||
// 经过上面的处理,content可能是字符串或者数组
|
|
||||||
// content = "原始文本内容" || 复数形式["原始文本内容","原始文本内容"....]
|
|
||||||
// 如果是数组说明要启用复数机制,需要根据插值变量中的某个变量来判断复数形式
|
|
||||||
if(Array.isArray(content) && content.length>0){
|
|
||||||
// 如果存在复数命名变量,只取第一个复数变量
|
|
||||||
if(pluraValue!==null){ // 启用的是位置插值,pluraIndex=第一个数字变量的位置
|
|
||||||
content = getPluraMessage(content,pluraValue);
|
|
||||||
}else if(pluralVar.length>0){
|
|
||||||
content = getPluraMessage(content,parseInt(vars(pluralVar[0])));
|
|
||||||
}else { // 如果找不到复数变量,则使用第一个内容
|
|
||||||
content = content[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 进行插值处理
|
|
||||||
if(vars.length==0){
|
|
||||||
return content
|
|
||||||
}else {
|
|
||||||
return replaceInterpolatedVars.call(scope,content,...vars)
|
|
||||||
}
|
|
||||||
}catch(e){
|
|
||||||
return content // 出错则返回原始文本
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 多语言管理类
|
|
||||||
*
|
|
||||||
* 当导入编译后的多语言文件时(import("./languages")),会自动生成全局实例VoerkaI18n
|
|
||||||
*
|
|
||||||
* VoerkaI18n.languages // 返回支持的语言列表
|
|
||||||
* VoerkaI18n.defaultLanguage // 默认语言
|
|
||||||
* VoerkaI18n.language // 当前语言
|
|
||||||
* VoerkaI18n.change(language) // 切换到新的语言
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* VoerkaI18n.on("change",(language)=>{}) // 注册语言切换事件
|
|
||||||
* VoerkaI18n.off("change",(language)=>{})
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
class I18nManager extends EventEmitter{
|
|
||||||
constructor(settings={}){
|
|
||||||
super();
|
|
||||||
if(I18nManager.instance!=null){
|
|
||||||
return I18nManager.instance;
|
|
||||||
}
|
|
||||||
I18nManager.instance = this;
|
|
||||||
this._settings = deepMerge(defaultLanguageSettings,settings);
|
|
||||||
this._scopes=[];
|
|
||||||
return I18nManager.instance;
|
|
||||||
}
|
|
||||||
get settings(){ return this._settings }
|
|
||||||
get scopes(){ return this._scopes }
|
|
||||||
// 当前激活语言
|
|
||||||
get activeLanguage(){ return this._settings.activeLanguage}
|
|
||||||
// 默认语言
|
|
||||||
get defaultLanguage(){ return this._settings.defaultLanguage}
|
|
||||||
// 支持的语言列表
|
|
||||||
get languages(){ return this._settings.languages}
|
|
||||||
// 内置格式化器
|
|
||||||
get formatters(){ return inlineFormatters }
|
|
||||||
/**
|
|
||||||
* 切换语言
|
|
||||||
*/
|
|
||||||
async change(value){
|
|
||||||
value=value.trim();
|
|
||||||
if(this.languages.findIndex(lang=>lang.name === value)!==-1){
|
|
||||||
// 通知所有作用域刷新到对应的语言包
|
|
||||||
await this._refreshScopes(value);
|
|
||||||
this._settings.activeLanguage = value;
|
|
||||||
/// 触发语言切换事件
|
|
||||||
await this.emit(value);
|
|
||||||
}else {
|
|
||||||
throw new Error("Not supported language:"+value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 当切换语言时调用此方法来加载更新语言包
|
|
||||||
* @param {*} newLanguage
|
|
||||||
*/
|
|
||||||
async _refreshScopes(newLanguage){
|
|
||||||
// 并发执行所有作用域语言包的加载
|
|
||||||
try{
|
|
||||||
const scopeRefreshers = this._scopes.map(scope=>{
|
|
||||||
return scope.refresh(newLanguage)
|
|
||||||
});
|
|
||||||
if(Promise.allSettled){
|
|
||||||
await Promise.allSettled(scopeRefreshers);
|
|
||||||
}else {
|
|
||||||
await Promise.all(scopeRefreshers);
|
|
||||||
}
|
|
||||||
}catch(e){
|
|
||||||
console.warn("Error while refreshing i18n scopes:",e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 注册一个新的作用域
|
|
||||||
*
|
|
||||||
* 每一个库均对应一个作用域,每个作用域可以有多个语言包,且对应一个翻译函数
|
|
||||||
* 除了默认语言外,其他语言采用动态加载的方式
|
|
||||||
*
|
|
||||||
* @param {*} scope
|
|
||||||
*/
|
|
||||||
async register(scope){
|
|
||||||
if(!(scope instanceof i18nScope)){
|
|
||||||
throw new TypeError("Scope must be an instance of I18nScope")
|
|
||||||
}
|
|
||||||
this._scopes.push(scope);
|
|
||||||
await scope.refresh(this.activeLanguage);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 注册全局格式化器
|
|
||||||
* 格式化器是一个简单的同步函数value=>{...},用来对输入进行格式化后返回结果
|
|
||||||
*
|
|
||||||
* registerFormatters(name,value=>{...}) // 适用于所有语言
|
|
||||||
* registerFormatters(name,value=>{...},{langauge:"zh"}) // 适用于cn语言
|
|
||||||
* registerFormatters(name,value=>{...},{langauge:"en"}) // 适用于en语言
|
|
||||||
|
|
||||||
* @param {*} formatters
|
|
||||||
*/
|
|
||||||
registerFormatter(name,formatter,{language="*"}={}){
|
|
||||||
if(!typeof(formatter)==="function" || typeof(name)!=="string"){
|
|
||||||
throw new TypeError("Formatter must be a function")
|
|
||||||
}
|
|
||||||
if(DataTypes$1.includes(name)){
|
|
||||||
this.formatters[language].$types[name] = formatter;
|
|
||||||
}else {
|
|
||||||
this.formatters[language][name] = formatter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var runtime ={
|
|
||||||
getInterpolatedVars,
|
|
||||||
replaceInterpolatedVars,
|
|
||||||
I18nManager,
|
|
||||||
translate,
|
|
||||||
i18nScope,
|
|
||||||
defaultLanguageSettings,
|
|
||||||
getDataTypeName,
|
|
||||||
isNumber,
|
|
||||||
isPlainObject
|
|
||||||
};
|
|
||||||
|
|
||||||
export { runtime as default };
|
|
@ -1,3 +1,2 @@
|
|||||||
|
|
||||||
|
|
||||||
console.log(t("中华民族伟大复兴"))
|
|
@ -2,12 +2,11 @@ import React,{ } from 'react'
|
|||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import "./languages"
|
// import "./languages"
|
||||||
|
|
||||||
|
|
||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
), document.getElementById('root')
|
), document.getElementById('root')
|
||||||
)
|
)
|
||||||
|
@ -7,7 +7,7 @@ import Voerkai18nPlugin from "@voerkai18n/vite"
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
Inspect(), // localhost:3000/__inspect/
|
Inspect(), // localhost:3000/__inspect/
|
||||||
Voerkai18nPlugin({ debug: true }),
|
// Voerkai18nPlugin({ debug: true }),
|
||||||
react()
|
react()
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
{{if moduleType === "esm"}}
|
{{if moduleType === "esm"}}
|
||||||
import messageIds from "./idMap.js" // 语言ID映射文件
|
import messageIds from "./idMap.js" // 语言ID映射文件
|
||||||
import { translate,VoerkaI18nScope } from "@voerkai18n/runtime"
|
import runtime from "@voerkai18n/runtime"
|
||||||
|
const { translate,VoerkaI18nScope } = runtime
|
||||||
|
import defaultFormatters from "./formatters/{{defaultLanguage}}"
|
||||||
{{if defaultLanguage === activeLanguage}}const activeFormatters = defaultFormatters{{else}}import activeFormatters from "@voerkai18n/runtime/formatters/{{activeLanguage}}.js"{{/if}}
|
{{if defaultLanguage === activeLanguage}}const activeFormatters = defaultFormatters{{else}}import activeFormatters from "@voerkai18n/runtime/formatters/{{activeLanguage}}.js"{{/if}}
|
||||||
import defaultMessages from "./{{defaultLanguage}}.js"
|
import defaultMessages from "./{{defaultLanguage}}.js"
|
||||||
{{if defaultLanguage === activeLanguage}}const activeMessages = defaultMessages{{else}}import activeMessages from "./{{activeLanguage}}.js"{{/if}}
|
{{if defaultLanguage === activeLanguage}}const activeMessages = defaultMessages{{else}}import activeMessages from "./{{activeLanguage}}.js"{{/if}}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import messageIds from "./idMap" // 语言ID映射文件
|
import messageIds from "./idMap" // 语言ID映射文件
|
||||||
import { translate,VoerkaI18nScope } from "@voerkai18n/runtime"
|
import runtime from "@voerkai18n/runtime"
|
||||||
|
const { translate,VoerkaI18nScope } = runtime
|
||||||
import defaultFormatters from "./formatters/{{defaultLanguage}}" // 默认语言格式化器
|
import defaultFormatters from "./formatters/{{defaultLanguage}}" // 默认语言格式化器
|
||||||
{{if defaultLanguage === activeLanguage}}const activeFormatters = defaultFormatters{{else}}import activeFormatters from "@voerkai18n/runtime/formatters/{{activeLanguage}}"{{/if}}
|
{{if defaultLanguage === activeLanguage}}const activeFormatters = defaultFormatters{{else}}import activeFormatters from "@voerkai18n/runtime/formatters/{{activeLanguage}}"{{/if}}
|
||||||
import defaultMessages from "./{{defaultLanguage}}"
|
import defaultMessages from "./{{defaultLanguage}}"
|
||||||
|
17
packages/react/index.d.ts
vendored
17
packages/react/index.d.ts
vendored
@ -1,7 +1,14 @@
|
|||||||
|
import type {VoerkaI18nSupportedLanguages,VoerkaI18nTranslate,VoerkaI18nScope} from "@voerkai18n/runtime"
|
||||||
|
import type React from "react"
|
||||||
|
|
||||||
|
export type useVoerkaI18n = ()=>{
|
||||||
export var useVoerkaI18n:()=>{
|
language:string
|
||||||
activeLanguage:string
|
|
||||||
changeLanguage:(newLanguage:string)=>Promise<void>
|
changeLanguage:(newLanguage:string)=>Promise<void>
|
||||||
languages:VoerkaI18nSupportedLanguages
|
languages:VoerkaI18nSupportedLanguages,
|
||||||
}
|
t:VoerkaI18nTranslate
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type VoerkaI18nProvider = React.FC<React.PropsWithChildren & {
|
||||||
|
scope:VoerkaI18nScope
|
||||||
|
}>
|
@ -1,39 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MyComponent(){
|
|
||||||
* const { activeLanguage, changeLanguage } = useVoerkaI18n()
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export function useVoerkaI18n() {
|
|
||||||
|
|
||||||
if(!globalThis.VoerkaI18n){
|
|
||||||
console.warn("useI18nContext is not provided, use default i18nContext")
|
|
||||||
}
|
|
||||||
|
|
||||||
const [activeLanguage, setLanguage ] = useState(VoerkaI18n.activeLanguage);
|
|
||||||
|
|
||||||
async function changeLanguage(newLanguage) {
|
|
||||||
return VoerkaI18n.change(newLanguage)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
function onChangeLanguage(newLanguage) {
|
|
||||||
setLanguage(newLanguage)
|
|
||||||
}
|
|
||||||
VoerkaI18n.on(onChangeLanguage)
|
|
||||||
return () => {
|
|
||||||
VoerkaI18n.off(onChangeLanguage)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
activeLanguage,
|
|
||||||
changeLanguage,
|
|
||||||
languages:VoerkaI18n.languages,
|
|
||||||
}
|
|
||||||
}
|
|
84
packages/react/index.jsx
Normal file
84
packages/react/index.jsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import React, { useState, useEffect,useContext,useCallback} from 'react';
|
||||||
|
|
||||||
|
export const VoerkaI18nContext = React.createContext({
|
||||||
|
languages:null,
|
||||||
|
language:'zh',
|
||||||
|
changeLanguage:() => {},
|
||||||
|
t:()=>{}
|
||||||
|
})
|
||||||
|
VoerkaI18nContext.displayName = 'VoerkaI18nProvider'
|
||||||
|
|
||||||
|
|
||||||
|
export function VoerkaI18nProvider(props){
|
||||||
|
const { scope } = props
|
||||||
|
const [language, setLanguage ] = useState(VoerkaI18n.activeLanguage);
|
||||||
|
useEffect(() => {
|
||||||
|
function onChangeLanguage(newLanguage) {
|
||||||
|
setLanguage(newLanguage)
|
||||||
|
}
|
||||||
|
VoerkaI18n.on(onChangeLanguage)
|
||||||
|
return () => {
|
||||||
|
VoerkaI18n.off(onChangeLanguage)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const changeLanguage = useCallback((newLanguage) => {
|
||||||
|
VoerkaI18n.change(newLanguage).then((lng) => {
|
||||||
|
setLanguage(lng)
|
||||||
|
})
|
||||||
|
},[language])
|
||||||
|
return (
|
||||||
|
<VoerkaI18nContext.Provider value={{
|
||||||
|
language,
|
||||||
|
changeLanguage,
|
||||||
|
languages:VoerkaI18n.languages,
|
||||||
|
t:scope.t
|
||||||
|
}}>
|
||||||
|
{props.children}
|
||||||
|
</VoerkaI18nContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useVoerkaI18n() {
|
||||||
|
return useContext(VoerkaI18nContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MyComponent(){
|
||||||
|
* const { activeLanguage, changeLanguage } = useVoerkaI18n()
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// export function useVoerkaI18n() {
|
||||||
|
|
||||||
|
// if(!globalThis.VoerkaI18n){
|
||||||
|
// console.warn("useI18nContext is not provided, use default i18nContext")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const [activeLanguage, setLanguage ] = useState(VoerkaI18n.activeLanguage);
|
||||||
|
|
||||||
|
// async function changeLanguage(newLanguage) {
|
||||||
|
// return VoerkaI18n.change(newLanguage)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// function onChangeLanguage(newLanguage) {
|
||||||
|
// setLanguage(newLanguage)
|
||||||
|
// }
|
||||||
|
// VoerkaI18n.on(onChangeLanguage)
|
||||||
|
// return () => {
|
||||||
|
// VoerkaI18n.off(onChangeLanguage)
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// activeLanguage,
|
||||||
|
// changeLanguage,
|
||||||
|
// languages:VoerkaI18n.languages,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
|||||||
"name": "@voerkai18n/react",
|
"name": "@voerkai18n/react",
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"description": "React支持,提供语言切换等功能",
|
"description": "React支持,提供语言切换等功能",
|
||||||
"main": "index.js",
|
"main": "index.jsx",
|
||||||
"typings": "index.d.ts",
|
"typings": "index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
@ -11,10 +11,13 @@
|
|||||||
"author": "wxzhang",
|
"author": "wxzhang",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^17.0.2"
|
"@voerkai18n/runtime": "latest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@voerkai18n/autopublish": "workspace:^1.0.2"
|
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^17.0.2"
|
||||||
},
|
},
|
||||||
"lastPublish": "2023-01-10T17:31:25+08:00"
|
"lastPublish": "2023-01-10T17:31:25+08:00"
|
||||||
}
|
}
|
19
packages/runtime/index.d.ts
vendored
19
packages/runtime/index.d.ts
vendored
@ -38,9 +38,7 @@ declare global {
|
|||||||
fallback?: string
|
fallback?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VoerkaI18nSupportedLanguages {
|
|
||||||
[key: string]: VoerkaI18nLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
export type VoerkI18nFormatter = (value: string, ...args: any[]) => string
|
export type VoerkI18nFormatter = (value: string, ...args: any[]) => string
|
||||||
export type VoerkI18nFormatterConfigs = Record<string, any>
|
export type VoerkI18nFormatterConfigs = Record<string, any>
|
||||||
@ -73,7 +71,13 @@ declare global {
|
|||||||
export var VoerkaI18n: VoerkaI18nManager
|
export var VoerkaI18n: VoerkaI18nManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface VoerkaI18nTranslate {
|
||||||
|
(message: string, ...args: (string | Function)[]): string
|
||||||
|
(message: string, vars?: Record<string, any>): string
|
||||||
|
}
|
||||||
|
export interface VoerkaI18nSupportedLanguages {
|
||||||
|
[key: string]: VoerkaI18nLanguage
|
||||||
|
}
|
||||||
export class VoerkaI18nScope {
|
export class VoerkaI18nScope {
|
||||||
constructor(options: VoerkaVoerkaI18nScopeOptions, callback?: Function)
|
constructor(options: VoerkaVoerkaI18nScopeOptions, callback?: Function)
|
||||||
get id(): string // 作用域唯一id
|
get id(): string // 作用域唯一id
|
||||||
@ -89,7 +93,8 @@ export class VoerkaI18nScope {
|
|||||||
get formatters(): VoerkI18nFormatters // 当前作用域的所有格式化器定义 {<语言名称>: {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () => {}}}
|
get formatters(): VoerkI18nFormatters // 当前作用域的所有格式化器定义 {<语言名称>: {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () => {}}}
|
||||||
get activeFormatters(): VoerkI18nFormatters // 当前作用域激活的格式化器定义 {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () = >{}}
|
get activeFormatters(): VoerkI18nFormatters // 当前作用域激活的格式化器定义 {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () = >{}}
|
||||||
get activeFormatterConfig(): VoerkI18nFormatterConfigs // 当前格式化器合并后的配置参数,参数已经合并了全局格式化器中的参数
|
get activeFormatterConfig(): VoerkI18nFormatterConfigs // 当前格式化器合并后的配置参数,参数已经合并了全局格式化器中的参数
|
||||||
|
get t(): VoerkaI18nTranslate
|
||||||
|
get translate(): VoerkaI18nTranslate
|
||||||
/**
|
/**
|
||||||
* 在全局注册作用域当前作用域
|
* 在全局注册作用域当前作用域
|
||||||
* @param {*} callback 注册成功后的回调
|
* @param {*} callback 注册成功后的回调
|
||||||
@ -149,8 +154,8 @@ export var Formatter: CreateFormatterType
|
|||||||
export type CreateFlexFormatterType = (fn: Function, options: CreateFormatterOptions, defaultParams: Record<string, any>) => FormatterDefine
|
export type CreateFlexFormatterType = (fn: Function, options: CreateFormatterOptions, defaultParams: Record<string, any>) => FormatterDefine
|
||||||
export var createFlexFormatter: CreateFlexFormatterType
|
export var createFlexFormatter: CreateFlexFormatterType
|
||||||
export var FlexFormatter: CreateFlexFormatterType
|
export var FlexFormatter: CreateFlexFormatterType
|
||||||
export var getDataTypeName:(value:any) => string
|
export var getDataTypeName: (value: any) => string
|
||||||
export var toDate: (value: any) => Date | number
|
export var toDate: (value: any) => Date | number
|
||||||
export var toNumber: (value: any,defaultValue:number) => number
|
export var toNumber: (value: any, defaultValue: number) => number
|
||||||
export var toBoolean: (value: any) => boolean
|
export var toBoolean: (value: any) => boolean
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ const defaultLanguageSettings = {
|
|||||||
await this._refreshScopes(language) // 通知所有作用域刷新到对应的语言包
|
await this._refreshScopes(language) // 通知所有作用域刷新到对应的语言包
|
||||||
this._settings.activeLanguage = language
|
this._settings.activeLanguage = language
|
||||||
await this.emit(language) // 触发语言切换事件
|
await this.emit(language) // 触发语言切换事件
|
||||||
|
return language
|
||||||
}else{
|
}else{
|
||||||
throw new Error("Not supported language:"+language)
|
throw new Error("Not supported language:"+language)
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "rollup -c",
|
"build": "rollup -c"
|
||||||
"release": "pnpm autopublish"
|
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"import": "./dist/index.esm.js",
|
"import": "./dist/index.esm.js",
|
||||||
@ -21,6 +20,12 @@
|
|||||||
},
|
},
|
||||||
"author": "wxzhang",
|
"author": "wxzhang",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime-corejs3":"latest",
|
||||||
|
"core-js":"3.21",
|
||||||
|
"@babel/runtime":"^7.17.8"
|
||||||
|
},
|
||||||
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.17.6",
|
"@babel/cli": "^7.17.6",
|
||||||
"@babel/core": "^7.17.5",
|
"@babel/core": "^7.17.5",
|
||||||
@ -30,7 +35,6 @@
|
|||||||
"@rollup/plugin-babel": "^5.3.1",
|
"@rollup/plugin-babel": "^5.3.1",
|
||||||
"@rollup/plugin-commonjs": "^21.0.2",
|
"@rollup/plugin-commonjs": "^21.0.2",
|
||||||
"@rollup/plugin-node-resolve": "^13.1.3",
|
"@rollup/plugin-node-resolve": "^13.1.3",
|
||||||
"@voerkai18n/autopublish": "workspace:^1.0.2",
|
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"rollup": "^2.69.0",
|
"rollup": "^2.69.0",
|
||||||
|
@ -12,6 +12,8 @@ export default [
|
|||||||
{
|
{
|
||||||
file: 'dist/index.esm.js',
|
file: 'dist/index.esm.js',
|
||||||
format:"esm",
|
format:"esm",
|
||||||
|
exports:"default",
|
||||||
|
esModule:"if-default-prop",
|
||||||
sourcemap:true
|
sourcemap:true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -29,28 +31,8 @@ export default [
|
|||||||
exclude: 'node_modules/**'
|
exclude: 'node_modules/**'
|
||||||
}),
|
}),
|
||||||
clear({targets:["dist"]}),
|
clear({targets:["dist"]}),
|
||||||
terser()
|
// terser()
|
||||||
],
|
],
|
||||||
external:["@babel/runtime"]
|
external:["@babel/runtime"]
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// input: './index.js',
|
|
||||||
// output: [
|
|
||||||
// {
|
|
||||||
// file: 'dist/runtime.cjs',
|
|
||||||
// exports:"auto",
|
|
||||||
// format:"cjs",
|
|
||||||
// sourcemap:true
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// file: 'dist/runtime.mjs',
|
|
||||||
// exports:"default",
|
|
||||||
// format:"esm",
|
|
||||||
// sourcemap:true
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// plugins:[
|
|
||||||
// commonjs()
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
]
|
]
|
@ -1,4 +1,5 @@
|
|||||||
const { DataTypes,isPlainObject, isFunction, getByPath, deepMixin,deepClone } = require("./utils");
|
const { DataTypes,isPlainObject, isFunction, getByPath, deepMixin,deepClone } = require("./utils");
|
||||||
|
const { translate } = require("./translate")
|
||||||
|
|
||||||
module.exports = class VoerkaI18nScope {
|
module.exports = class VoerkaI18nScope {
|
||||||
constructor(options = {}, callback) {
|
constructor(options = {}, callback) {
|
||||||
@ -32,6 +33,7 @@ module.exports = class VoerkaI18nScope {
|
|||||||
languages : options.languages,
|
languages : options.languages,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this._t = translate.bind(this)
|
||||||
this._global = globalThis.VoerkaI18n;
|
this._global = globalThis.VoerkaI18n;
|
||||||
this._initFormatters(this.activeLanguage) // 初始化活动的格式化器
|
this._initFormatters(this.activeLanguage) // 初始化活动的格式化器
|
||||||
this._mergePatchedMessages(); // 从本地缓存中读取并合并补丁语言包
|
this._mergePatchedMessages(); // 从本地缓存中读取并合并补丁语言包
|
||||||
@ -51,7 +53,8 @@ module.exports = class VoerkaI18nScope {
|
|||||||
get formatters() { return this._formatters;} // 当前作用域的所有格式化器定义 {<语言名称>: {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () => {}}}
|
get formatters() { return this._formatters;} // 当前作用域的所有格式化器定义 {<语言名称>: {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () => {}}}
|
||||||
get activeFormatters() {return this._activeFormatters} // 当前作用域激活的格式化器定义 {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () = >{}}
|
get activeFormatters() {return this._activeFormatters} // 当前作用域激活的格式化器定义 {$types,$config,[格式化器名称]: () = >{},[格式化器名称]: () = >{}}
|
||||||
get activeFormatterConfig(){return this._activeFormatterConfig} // 当前格式化器合并后的配置参数,参数已经合并了全局格式化器中的参数
|
get activeFormatterConfig(){return this._activeFormatterConfig} // 当前格式化器合并后的配置参数,参数已经合并了全局格式化器中的参数
|
||||||
|
get translate(){return this._t}
|
||||||
|
get t(){return this._t}
|
||||||
/**
|
/**
|
||||||
* 对输入的语言配置进行处理
|
* 对输入的语言配置进行处理
|
||||||
* - 将en配置为默认回退语言
|
* - 将en配置为默认回退语言
|
||||||
|
52
pnpm-lock.yaml
generated
52
pnpm-lock.yaml
generated
@ -65,24 +65,30 @@ importers:
|
|||||||
packages/apps/app:
|
packages/apps/app:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@voerkai18n/cli': workspace:^1.0.6
|
'@voerkai18n/cli': workspace:^1.0.6
|
||||||
'@voerkai18n/runtime': ^1.0.0
|
'@voerkai18n/runtime': workspace:^1.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@voerkai18n/cli': link:../../cli
|
'@voerkai18n/cli': link:../../cli
|
||||||
'@voerkai18n/runtime': link:../../runtime
|
'@voerkai18n/runtime': link:../../runtime
|
||||||
|
|
||||||
packages/apps/reactapp:
|
packages/apps/reactapp:
|
||||||
specifiers:
|
specifiers:
|
||||||
|
'@babel/runtime-corejs3': ^7.20.7
|
||||||
'@vitejs/plugin-react': ^1.0.7
|
'@vitejs/plugin-react': ^1.0.7
|
||||||
'@voerkai18n/cli': workspace:^1.0.11
|
'@voerkai18n/cli': workspace:^1.0.11
|
||||||
'@voerkai18n/react': workspace:^1.0.0
|
'@voerkai18n/react': workspace:^1.0.0
|
||||||
|
'@voerkai18n/runtime': workspace:^1.1.9
|
||||||
'@voerkai18n/vite': workspace:^1.0.7
|
'@voerkai18n/vite': workspace:^1.0.7
|
||||||
|
core-js: ^3.27.1
|
||||||
react: ^17.0.2
|
react: ^17.0.2
|
||||||
react-dom: ^17.0.2
|
react-dom: ^17.0.2
|
||||||
vite: ^2.9.0
|
vite: ^2.9.0
|
||||||
vite-plugin-inspect: ^0.4.3
|
vite-plugin-inspect: ^0.4.3
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@babel/runtime-corejs3': 7.20.7
|
||||||
'@voerkai18n/react': link:../../react
|
'@voerkai18n/react': link:../../react
|
||||||
|
'@voerkai18n/runtime': link:../../runtime
|
||||||
'@voerkai18n/vite': link:../../vite
|
'@voerkai18n/vite': link:../../vite
|
||||||
|
core-js: 3.27.1
|
||||||
react: 17.0.2
|
react: 17.0.2
|
||||||
react-dom: 17.0.2_react@17.0.2
|
react-dom: 17.0.2_react@17.0.2
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@ -201,12 +207,9 @@ importers:
|
|||||||
|
|
||||||
packages/react:
|
packages/react:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@voerkai18n/autopublish': workspace:^1.0.2
|
'@voerkai18n/runtime': latest
|
||||||
react: ^17.0.2
|
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 17.0.2
|
'@voerkai18n/runtime': link:../runtime
|
||||||
devDependencies:
|
|
||||||
'@voerkai18n/autopublish': link:../autopublish
|
|
||||||
|
|
||||||
packages/runtime:
|
packages/runtime:
|
||||||
specifiers:
|
specifiers:
|
||||||
@ -215,15 +218,19 @@ importers:
|
|||||||
'@babel/plugin-transform-runtime': ^7.17.0
|
'@babel/plugin-transform-runtime': ^7.17.0
|
||||||
'@babel/preset-env': ^7.16.11
|
'@babel/preset-env': ^7.16.11
|
||||||
'@babel/runtime': ^7.17.8
|
'@babel/runtime': ^7.17.8
|
||||||
|
'@babel/runtime-corejs3': latest
|
||||||
'@rollup/plugin-babel': ^5.3.1
|
'@rollup/plugin-babel': ^5.3.1
|
||||||
'@rollup/plugin-commonjs': ^21.0.2
|
'@rollup/plugin-commonjs': ^21.0.2
|
||||||
'@rollup/plugin-node-resolve': ^13.1.3
|
'@rollup/plugin-node-resolve': ^13.1.3
|
||||||
'@voerkai18n/autopublish': workspace:^1.0.2
|
core-js: '3.21'
|
||||||
deepmerge: ^4.2.2
|
deepmerge: ^4.2.2
|
||||||
jest: ^27.5.1
|
jest: ^27.5.1
|
||||||
rollup: ^2.69.0
|
rollup: ^2.69.0
|
||||||
rollup-plugin-clear: ^2.0.7
|
rollup-plugin-clear: ^2.0.7
|
||||||
rollup-plugin-terser: ^7.0.2
|
rollup-plugin-terser: ^7.0.2
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime-corejs3': 7.20.7
|
||||||
|
core-js: 3.21.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@babel/cli': 7.18.10_@babel+core@7.18.10
|
'@babel/cli': 7.18.10_@babel+core@7.18.10
|
||||||
'@babel/core': 7.18.10
|
'@babel/core': 7.18.10
|
||||||
@ -233,7 +240,6 @@ importers:
|
|||||||
'@rollup/plugin-babel': 5.3.1_tui6liyexu3zy4m5r2rytc7ixu
|
'@rollup/plugin-babel': 5.3.1_tui6liyexu3zy4m5r2rytc7ixu
|
||||||
'@rollup/plugin-commonjs': 21.1.0_rollup@2.77.2
|
'@rollup/plugin-commonjs': 21.1.0_rollup@2.77.2
|
||||||
'@rollup/plugin-node-resolve': 13.3.0_rollup@2.77.2
|
'@rollup/plugin-node-resolve': 13.3.0_rollup@2.77.2
|
||||||
'@voerkai18n/autopublish': link:../autopublish
|
|
||||||
deepmerge: 4.2.2
|
deepmerge: 4.2.2
|
||||||
jest: 27.5.1
|
jest: 27.5.1
|
||||||
rollup: 2.77.2
|
rollup: 2.77.2
|
||||||
@ -1478,11 +1484,19 @@ packages:
|
|||||||
core-js-pure: 3.24.1
|
core-js-pure: 3.24.1
|
||||||
regenerator-runtime: 0.13.9
|
regenerator-runtime: 0.13.9
|
||||||
|
|
||||||
|
/@babel/runtime-corejs3/7.20.7:
|
||||||
|
resolution: {integrity: sha512-jr9lCZ4RbRQmCR28Q8U8Fu49zvFqLxTY9AMOUz+iyMohMoAgpEcVxY+wJNay99oXOpOcCTODkk70NDN2aaJEeg==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
core-js-pure: 3.27.1
|
||||||
|
regenerator-runtime: 0.13.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@babel/runtime/7.18.6:
|
/@babel/runtime/7.18.6:
|
||||||
resolution: {integrity: sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==}
|
resolution: {integrity: sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime: 0.13.9
|
regenerator-runtime: 0.13.11
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@babel/runtime/7.18.9:
|
/@babel/runtime/7.18.9:
|
||||||
@ -2322,7 +2336,7 @@ packages:
|
|||||||
'@umijs/utils': 3.5.32
|
'@umijs/utils': 3.5.32
|
||||||
ansi-html: 0.0.7
|
ansi-html: 0.0.7
|
||||||
core-js: 3.6.5
|
core-js: 3.6.5
|
||||||
core-js-pure: 3.24.1
|
core-js-pure: 3.27.1
|
||||||
error-stack-parser: 2.1.4
|
error-stack-parser: 2.1.4
|
||||||
es-module-lexer: 0.7.1
|
es-module-lexer: 0.7.1
|
||||||
es5-imcompatible-versions: 0.1.74
|
es5-imcompatible-versions: 0.1.74
|
||||||
@ -4465,16 +4479,31 @@ packages:
|
|||||||
resolution: {integrity: sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg==}
|
resolution: {integrity: sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
|
|
||||||
|
/core-js-pure/3.27.1:
|
||||||
|
resolution: {integrity: sha512-BS2NHgwwUppfeoqOXqi08mUqS5FiZpuRuJJpKsaME7kJz0xxuk0xkhDdfMIlP/zLa80krBqss1LtD7f889heAw==}
|
||||||
|
requiresBuild: true
|
||||||
|
|
||||||
/core-js/2.6.12:
|
/core-js/2.6.12:
|
||||||
resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==}
|
resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==}
|
||||||
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/core-js/3.21.1:
|
||||||
|
resolution: {integrity: sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==}
|
||||||
|
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/core-js/3.24.1:
|
/core-js/3.24.1:
|
||||||
resolution: {integrity: sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==}
|
resolution: {integrity: sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
|
|
||||||
|
/core-js/3.27.1:
|
||||||
|
resolution: {integrity: sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==}
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/core-js/3.6.5:
|
/core-js/3.6.5:
|
||||||
resolution: {integrity: sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==}
|
resolution: {integrity: sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==}
|
||||||
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||||
@ -9965,6 +9994,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==}
|
resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/regenerator-runtime/0.13.11:
|
||||||
|
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
||||||
|
|
||||||
/regenerator-runtime/0.13.5:
|
/regenerator-runtime/0.13.5:
|
||||||
resolution: {integrity: sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==}
|
resolution: {integrity: sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user