diff --git a/.gitignore b/.gitignore index fae58f7..30ad343 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,14 @@ node_modules /packages/**/node_modules /coverage /packages/apps/vueapp/src/languages -/packages/apps/app/languages \ No newline at end of file +/packages/apps/app/languages +/packages/apps/test +node_modules/ +docs/.vuepress/.cache/ +docs/.vuepress/.temp/ +docs/.vuepress/dist/ +/packages/cli/baidu.api.txt +node_modules/ +docs/.vuepress/.cache/ +docs/.vuepress/.temp/ +docs/.vuepress/dist/ diff --git a/package.json b/package.json index e503640..1d41b64 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,12 @@ "scripts": { "build:runtime": "pnpm build --filter \"@voerkai18n/runtime\"", "test": "cross-env NODE_OPTIONS=--experimental-vm-modules node node_modules/jest/bin/jest.js ", - "test:babelplugin": "jest babel", - "test:extract": "jest extract", - "test:translate": "jest translate", - "list:package":"node ./packages/autopublish/index.js list" - + "test:app": "cross-env NODE_OPTIONS=--experimental-vm-modules node node_modules/jest/bin/jest.js -- app", + "list:package": "node ./packages/autopublish/index.js list", + "autopublish": "node ./packages/autopublish/index.js", + "docs:build": "cross-env NODE_OPTIONS=--openssl-legacy-provider vuepress build docs", + "docs:dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider && vuepress dev docs", + "docs:clean-dev": "vuepress dev docs --clean-cache" }, "author": "", "license": "ISC", @@ -20,6 +21,7 @@ "@babel/preset-env": "^7.16.11", "@rollup/plugin-babel": "^5.3.1", "@rollup/plugin-commonjs": "^21.0.2", + "@voerkai18n/autopublish": "^1.0.3", "dayjs": "^1.11.0", "deepmerge": "^4.2.2", "fs-extra": "^10.0.1", @@ -29,9 +31,12 @@ "rollup": "^2.70.1", "rollup-plugin-clear": "^2.0.7", "shelljs": "^0.8.5", - "vinyl": "^2.2.1" + "vinyl": "^2.2.1", + "vuepress": "^2.0.0-beta.38", + "vuepress-theme-hope": "^2.0.0-beta.36" }, "dependencies": { + "cross-env": "^7.0.3", "inquirer": "^8.2.2" } } diff --git a/packages/apps/app/languages/en.js b/packages/apps/app/languages/en.js index a68ea6b..40a14e6 100644 --- a/packages/apps/app/languages/en.js +++ b/packages/apps/app/languages/en.js @@ -1,32 +1,32 @@ -module.exports = { +export default { "1": "a", "2": "b", "3": "c", "4": "d", "5": "e", - "6": "请输入旧密码:", - "7": "请再次输入旧密码:", - "8": "请输入新密码:", - "9": "请再次输入新密码:", - "10": "密码至少需要6位,并且至少包含数字、字符或特殊符号中的两种", - "11": "密码强度: {strength}", - "12": "用户名或密码错误", - "13": "请输入用户名:", - "14": "请输入密码:", - "15": "欢迎您: {}", - "16": "数据库类型:{}、{}、{}", - "17": "数据库密码:{pwd}", - "18": "数据库地址:{url}", - "19": "编码:{encode}", - "20": "编码", - "21": "名称", - "22": "描述", - "23": "文件名称", - "24": "您有{}条未读消息", - "25": "消息总数:{$count}", - "26": "消息类型:{type}", - "27": "登录", - "28": "请输入密码:", - "29": "头像", - "30": "相片" + "6": "Please enter your old password:", + "7": "Please enter your old password again:", + "8": "Please enter a new password:", + "9": "Please enter the new password again:", + "10": "The password needs at least 6 digits and contains at least two of numbers, characters or special symbols", + "11": "Password strength: {strength}", + "12": "Wrong user name or password", + "13": "Please enter user name:", + "14": "Please input a password:", + "15": "Welcome: {}", + "16": "Database type: {}, {}, {}", + "17": "Database password: {PWD}", + "18": "Database address: {URL}", + "19": "Code: {encode}", + "20": "code", + "21": "name", + "22": "describe", + "23": "File name", + "24": "You have {} unread messages", + "25": "Total messages: {$count}", + "26": "Message type: {type}", + "27": "Sign in", + "28": "Please input a password:", + "29": "head portrait", + "30": "photo" } \ No newline at end of file diff --git a/packages/apps/app/languages/formatters.js b/packages/apps/app/languages/formatters.js index cfc964c..c7474fd 100644 --- a/packages/apps/app/languages/formatters.js +++ b/packages/apps/app/languages/formatters.js @@ -47,7 +47,7 @@ * */ -module.exports = { +export default { // 在所有语言下生效的格式化器 "*":{ //[格式化名称]:(value)=>{...}, diff --git a/packages/apps/app/languages/idMap.js b/packages/apps/app/languages/idMap.js index 776652d..214c04b 100644 --- a/packages/apps/app/languages/idMap.js +++ b/packages/apps/app/languages/idMap.js @@ -1,4 +1,4 @@ -module.exports = { +export default { "a": 1, "b": 2, "c": 3, diff --git a/packages/apps/app/languages/index.js b/packages/apps/app/languages/index.js index 1824519..3f803aa 100644 --- a/packages/apps/app/languages/index.js +++ b/packages/apps/app/languages/index.js @@ -1,9 +1,10 @@ -const messageIds = require("./idMap") -const { translate,i18nScope } = require("./runtime.js") +import messageIds from "./idMap.js" +import runtime from "./runtime.js" +const { translate,i18nScope } = runtime -const formatters = require("./formatters.js") -const defaultMessages = require("./cn.js") +import formatters from "./formatters.js" +import defaultMessages from "./zh.js" const activeMessages = defaultMessages @@ -11,16 +12,24 @@ const activeMessages = defaultMessages const scopeSettings = { "languages": [ { - "name": "cn", - "title": "cn" + "name": "zh", + "title": "中文" }, { "name": "en", - "title": "en" + "title": "英语" + }, + { + "name": "de", + "title": "德语" + }, + { + "name": "jp", + "title": "日语" } ], - "defaultLanguage": "cn", - "activeLanguage": "cn", + "defaultLanguage": "zh", + "activeLanguage": "zh", "namespaces": {} } @@ -33,12 +42,16 @@ const scope = new i18nScope({ idMap:messageIds, // 消息id映射列表 formatters, // 当前作用域的格式化函数列表 loaders:{ - "en" : ()=>import("./en.js") + "en" : ()=>import("./en.js"), + "de" : ()=>import("./de.js"), + "jp" : ()=>import("./jp.js") } }) // 翻译函数 -const t = translate.bind(scope) +const scopedTtranslate = translate.bind(scope) -module.exports.t = t -module.exports.i18nScope = scope +export { + scopedTtranslate as t, + scope as i18nScope +} diff --git a/packages/apps/app/languages/settings.json b/packages/apps/app/languages/settings.json index 4082e51..30ea50e 100644 --- a/packages/apps/app/languages/settings.json +++ b/packages/apps/app/languages/settings.json @@ -1,15 +1,23 @@ { "languages": [ { - "name": "cn", - "title": "cn" + "name": "zh", + "title": "中文" }, { "name": "en", - "title": "en" + "title": "英语" + }, + { + "name": "de", + "title": "德语" + }, + { + "name": "jp", + "title": "日语" } ], - "defaultLanguage": "cn", - "activeLanguage": "cn", + "defaultLanguage": "zh", + "activeLanguage": "zh", "namespaces": {} } \ No newline at end of file diff --git a/packages/apps/app/languages/translates/default.json b/packages/apps/app/languages/translates/default.json index f3af067..4dab38e 100644 --- a/packages/apps/app/languages/translates/default.json +++ b/packages/apps/app/languages/translates/default.json @@ -3,181 +3,241 @@ "en": "a", "$file": [ "index.js" - ] + ], + "de": "a", + "jp": "a" }, "b": { "en": "b", "$file": [ "index.js" - ] + ], + "de": "b", + "jp": "b" }, "c": { "en": "c", "$file": [ "index.js" - ] + ], + "de": "c", + "jp": "c" }, "d": { "en": "d", "$file": [ "index.js" - ] + ], + "de": "d", + "jp": "d" }, "e": { "en": "e", "$file": [ "index.js" - ] + ], + "de": "e", + "jp": "e" }, "请输入旧密码:": { - "en": "请输入旧密码:", + "en": "Please enter your old password:", "$file": [ "auth\\changepassword.js" - ] + ], + "de": "Bitte geben Sie Ihr altes Passwort ein:", + "jp": "古いパスワードを入力してください:" }, "请再次输入旧密码:": { - "en": "请再次输入旧密码:", + "en": "Please enter your old password again:", "$file": [ "auth\\changepassword.js" - ] + ], + "de": "Bitte geben Sie Ihr altes Passwort erneut ein:", + "jp": "古いパスワードをもう一度入力してください:" }, "请输入新密码:": { - "en": "请输入新密码:", + "en": "Please enter a new password:", "$file": [ "auth\\changepassword.js" - ] + ], + "de": "Bitte geben Sie ein neues Passwort ein:", + "jp": "新しいパスワードを入力してください:" }, "请再次输入新密码:": { - "en": "请再次输入新密码:", + "en": "Please enter the new password again:", "$file": [ "auth\\changepassword.js" - ] + ], + "de": "Bitte geben Sie das neue Passwort erneut ein:", + "jp": "新しいパスワードを再度入力してください:" }, "密码至少需要6位,并且至少包含数字、字符或特殊符号中的两种": { - "en": "密码至少需要6位,并且至少包含数字、字符或特殊符号中的两种", + "en": "The password needs at least 6 digits and contains at least two of numbers, characters or special symbols", "$file": [ "auth\\changepassword.js" - ] + ], + "de": "Das Passwort benötigt mindestens sechs Ziffern und enthält mindestens zwei Ziffern, Zeichen oder Sondersymbole", + "jp": "パスワードには少なくとも6ビットが必要で、数字、文字、または特殊記号の少なくとも2種類が含まれています。" }, "密码强度: {strength}": { - "en": "密码强度: {strength}", + "en": "Password strength: {strength}", "$file": [ "auth\\changepassword.js" - ] + ], + "de": "Kennwortstärke: {Stärke}", + "jp": "パスワードの強度:{strength}" }, "用户名或密码错误": { - "en": "用户名或密码错误", + "en": "Wrong user name or password", "$file": [ "auth\\login.js" - ] + ], + "de": "Falscher Benutzername oder falsches Passwort", + "jp": "ユーザー名またはパスワードが間違っています" }, "请输入用户名:": { - "en": "请输入用户名:", + "en": "Please enter user name:", "$file": [ "auth\\login.js", "auth\\login.html" - ] + ], + "de": "Bitte geben Sie Ihren Benutzernamen ein:", + "jp": "ユーザー名を入力してください:" }, "请输入密码:": { - "en": "请输入密码:", + "en": "Please input a password:", "$file": [ "auth\\login.js" - ] + ], + "de": "Bitte geben Sie ein Passwort ein:", + "jp": "パスワードを入力してください:" }, "欢迎您: {}": { - "en": "欢迎您: {}", + "en": "Welcome: {}", "$file": [ "auth\\login.js" - ] + ], + "de": "Willkommen: {}", + "jp": "ようこそ" }, "数据库类型:{}、{}、{}": { - "en": "数据库类型:{}、{}、{}", + "en": "Database type: {}, {}, {}", "$file": [ "db\\index.js" - ] + ], + "de": "Datenbanktyp: {}, {}, {}, {}", + "jp": "データベースタイプ:{}、{}、{}" }, "数据库密码:{pwd}": { - "en": "数据库密码:{pwd}", + "en": "Database password: {PWD}", "$file": [ "db\\index.js" - ] + ], + "de": "Datenbankpasswort: {PWD}", + "jp": "データベースパスワード:{pwd}" }, "数据库地址:{url}": { - "en": "数据库地址:{url}", + "en": "Database address: {URL}", "$file": [ "db\\index.js" - ] + ], + "de": "Datenbankadresse: {URL}", + "jp": "データベースアドレス:{url}" }, "编码:{encode}": { - "en": "编码:{encode}", + "en": "Code: {encode}", "$file": [ "db\\index.js" - ] + ], + "de": "Code: {kodieren}", + "jp": "エンコーディング:{encode}" }, "编码": { - "en": "编码", + "en": "code", "$file": [ "db\\models.js" - ] + ], + "de": "Code", + "jp": "エンコーディング" }, "名称": { - "en": "名称", + "en": "name", "$file": [ "db\\models.js" - ] + ], + "de": "Name", + "jp": "名前" }, "描述": { - "en": "描述", + "en": "describe", "$file": [ "db\\models.js" - ] + ], + "de": "Beschreibung", + "jp": "説明" }, "文件名称": { - "en": "文件名称", + "en": "File name", "$file": [ "db\\models.js" - ] + ], + "de": "Dateiname", + "jp": "ファイル名" }, "您有{}条未读消息": { - "en": "您有{}条未读消息", + "en": "You have {} unread messages", "$file": [ "messages\\index.js" - ] + ], + "de": "Sie haben {} ungelesene Nachrichten", + "jp": "未読メッセージがあります" }, "消息总数:{$count}": { - "en": "消息总数:{$count}", + "en": "Total messages: {$count}", "$file": [ "messages\\index.js" - ] + ], + "de": "Gesamtnachrichten: {$count}", + "jp": "合計メッセージ:{$count}" }, "消息类型:{type}": { - "en": "消息类型:{type}", + "en": "Message type: {type}", "$file": [ "messages\\index.js" - ] + ], + "de": "Nachrichtentyp: {type}", + "jp": "メッセージタイプ:{type}" }, "登录": { - "en": "登录", + "en": "Sign in", "$file": [ "auth\\login.html" - ] + ], + "de": "Anmelden", + "jp": "ログイン" }, "请输入密码:": { - "en": "请输入密码:", + "en": "Please input a password:", "$file": [ "auth\\login.html" - ] + ], + "de": "Bitte geben Sie ein Passwort ein:", + "jp": "パスワードを入力してください:" }, "头像": { - "en": "头像", + "en": "head portrait", "$file": [ "auth\\login.html" - ] + ], + "de": "Kopfportrait", + "jp": "アイコン" }, "相片": { - "en": "相片", + "en": "photo", "$file": [ "auth\\login.html" - ] + ], + "de": "Foto", + "jp": "写真" } } \ No newline at end of file diff --git a/packages/autopublish/index.js b/packages/autopublish/index.js index 907f977..35048b3 100644 --- a/packages/autopublish/index.js +++ b/packages/autopublish/index.js @@ -18,46 +18,86 @@ * */ - const fs = require("fs-extra"); - const inquirer = require("inquirer"); - const semver = require("semver") - const path = require("path"); - const shelljs = require("shelljs"); - const createLogger = require("logsets"); - const { Command ,Option} = require('commander'); - const dayjs = require("dayjs"); - const relativeTime = require("dayjs/plugin/relativeTime"); - dayjs.extend(relativeTime); - require('dayjs/locale/zh-cn') - dayjs.locale("zh-cn"); - - const logger = createLogger(); - - - const program =new Command() - - +const fs = require("fs-extra"); +const inquirer = require("inquirer"); +const semver = require("semver") +const path = require("path"); +const shelljs = require("shelljs"); +const createLogger = require("logsets"); +const TaskListPlugin = require("logsets/plugins/tasklist") +const TablePlugin = require("logsets/plugins/table") + +const { Command ,Option} = require('commander'); + +const dayjs = require("dayjs"); +const relativeTime = require("dayjs/plugin/relativeTime"); +const { rejects } = require("assert"); +const { Console } = require("console"); +dayjs.extend(relativeTime); +require('dayjs/locale/zh-CN') +dayjs.locale("zh-CN"); +const logger = createLogger(); +logger.use(TaskListPlugin) +logger.use(TablePlugin) + +const program =new Command() + + // 排除要发布的包 + const exclude_packages = ["autopublish"] + function getPackages(){ let workspaceRoot = process.cwd() if(!fs.existsSync(path.join(workspaceRoot,"pnpm-workspace.yaml"))){ console.log("命令只能在工作区根目录下执行") return } - // 获取包最后一次提交的时间 - const getLastCommitScript = "git log --format=%cd --date=iso -1 -- {packagePath}" - return fs.readdirSync(path.join(workspaceRoot,"packages")).map(packageName=>{ + // 读取所有包 + let packages = fs.readdirSync(path.join(workspaceRoot,"packages")).map(packageName=>{ + const packageFolder = path.join(workspaceRoot,"packages",packageName) const pkgFile = path.join(workspaceRoot,"packages",packageName,"package.json") if(fs.existsSync(pkgFile)){ - const { name, version }= fs.readJSONSync(pkgFile) - const lastCommit = shelljs.exec(getLastCommitScript.replace("{packagePath}",`packages/${packageName}/package.json`), { silent: true }).stdout.trim() + const { name, version,lastPublish,dependencies,devDependencies }= fs.readJSONSync(pkgFile) + // 读取工作区包依赖 + let packageDependencies =[] + Object.entries({...dependencies,...devDependencies}).forEach(([name,version])=>{ + if(version.startsWith("workspace:") && !exclude_packages.includes(name.replace("@voerkai18n/",""))){ + packageDependencies.push(name) + } + }) return { - name, + name, // 完整包名 + value:packageName, // 文件夹名称 version, - lastCommit + lastPublish, + isDirty: packageIsDirty(packageFolder), // 包自上次发布之后是否已修改 + dependencies:packageDependencies // 依赖的工作区包 } } - }).filter(pkgInfo=>pkgInfo) + }).filter(pkgInfo=>pkgInfo && !exclude_packages.includes(pkgInfo.value)) + + // 根据依赖关系进行排序 + for(let i=0;i { + if(package.isDirty){ + packages.forEach(p=>{ + if(p.name!==package.name && p.dependencies.includes(package.name)){ + p.isDirty = true + } + }) + } + }) + return packages } function assertInWorkspaceRoot(){ @@ -66,162 +106,334 @@ throw new Error("命令只能在工作区根目录下执行") } } + + function assertInPackageRoot(){ + const currentFolder = process.cwd() + const workspaceRoot = path.join(currentFolder,"../../") + + const inPackageRoot = fs.existsSync(path.join(currentFolder,"package.json")) && fs.existsSync(path.join(workspaceRoot,"pnpm-workspace.yaml")) - /** - * 返回当前包是否有未提交的文件 - * - * 如果包文件夹下有未提交的文件,则返回true - * - */ - function getPackageLastChanges(packageName){ - const changeFiles = shelljs.exec(`git status -s .`, { silent: true }).stdout.trim() - return changeFiles.length>0 ? changeFiles.split("\n") : [] - } + if(!inPackageRoot){ + throw new Error("命令只能在工作区的包目录下执行") + } +} /** * 执行脚本,出错会返回错误信息 * @param {*} script */ function execShellScript(script,options={}){ - if(shelljs.exec(script).code>0){ - throw new Error(`执行<${script}>失败`) + let {code,stdout} = shelljs.exec(script,options) + if(code>0){ + new Error(`执行<${script}>失败: ${stdout.trim()}`) } +} +/** + * 异步执行脚本 + * @param {*} script + * @param {*} options + * @returns + */ +async function asyncExecShellScript(script,options={}){ + return new Promise((resolve,reject)=>{ + shelljs.exec(script,{...options,async:true},(code,stdout)=>{ + if(code>0){ + reject(new Error(`执行<${script}>失败: ${stdout.trim()}`)) + }else{ + resolve() + } + }) + }) } /** * 执行脚本并返回结果 * @param {*} script */ -function execShellScriptReturns(script,options={}){ ){ - return shelljs.exec(script,options).code>0).stdout.trim() +function execShellScriptReturns(script,options={}){ + return shelljs.exec(script,options).stdout.trim() +} + +/** + * 读取指定包最近一次更新的时间 + * 通过遍历所有文件夹 + * @param {*} folder + * @returns + */ + function getFolderLastModified(folder,patterns=[],options={}){ + patterns.push(...[ + "package.json", + "**", + "**/*", + "!node_modules/**", + "!node_modules/**/*", + "!**/node_modules/**", + "!**/node_modules/**/*", + ]) + + const glob = require("fast-glob") + let files = glob.sync(patterns, { + cwd: folder, + absolute:true, + ...options + }) + let lastUpdateTime = null + for(let file of files){ + const { mtimeMs } = fs.statSync(file) + lastUpdateTime = lastUpdateTime ? Math.max(lastUpdateTime,mtimeMs) : mtimeMs + } + return lastUpdateTime +} + +function getFileLastModified(file){ + const { mtimeMs } = fs.statSync(file) + return mtimeMs +} + +/** + * + * @param {*} packageInfo {name:"@voerkai18n/autopublish",value:"",version:"1.0.0",lastPublish:"2020-05-01T00:00:00.000Z"} + */ +async function runPackageScript(workspaceRoot,packageInfo,{silent=false}={}){ + const packageFolder = path.join(workspaceRoot,"packages",packageInfo.value) + const package = fs.readJSONSync(path.join(packageFolder,"package.json")) + const lastModified = getFolderLastModified(packageFolder) + // 进入包所在的文件夹 + shelljs.cd(packageFolder) + // 每个包必须定义自己的发布脚本 + if("release" in package.scripts){ + await asyncExecShellScript(`pnpm release`,{silent}) + }else{ + const reason = `包[{}]没有定义自动发布脚本release` + if(showLog) logger.log(reason,package.name) + throw new Error(`未配置脚本`) + } } /** - * 执行Git提交命令 * - * 1. 检查当前包是否有未提交的文件 - * 2. 如果没有则不提交 - * 3. 如果有则提交 + * 返回指定包自上次发布之后是否有更新过 + * + * @param {*} packageFolder * * */ -function commitProject(packageName,{versionIncrementStep="patch",autoCommit=false}={}){ - const lastChanges = getPackageLastChanges(package.name) - let lastCommit = shelljs.exec(`git log --format=%cd --date=iso -1 -- .`, { silent: true }).stdout.trim() - let hasError = false // 执行过程是否出错了 - let isCommit = autoCommit // 是否执行了提交操作 +function packageIsDirty(packageFolder){ + const pkgFile = path.join(packageFolder,"package.json") + if(!fs.existsSync(pkgFile)){ + logger.log("当前包[{}]不存在package.json文件",packageFolder) + throw new Error("当前包不存在package.json文件") + } + const package = fs.readJSONSync(pkgFile) + const lastModified = getFolderLastModified(packageFolder) + const lastPublish = package.lastPublish + // 由于上一次发布时会更新package.json文件,如果最后更新的文件时间==package.json文件最后更新时间,则说明没有更新 + const pkgLastModified = getFileLastModified(pkgFile) - if(lastCommit){ - lastCommit = dayjs(lastCommit) - logger.log("最后一次提交:{}({})",lastCommit.format("YYYY-MM-DD HH:mm:ss"),lastCommit.fromNow()) - } - if(lastChanges.length>0){ - logger.log("包[{}]存在{}个未提交的文件:",package.name,lastChanges.length) - lastChanges.forEach(file=>logger.log(` - ${file.trim()}`)) - if(!autoCommit){ - const result = await inquirer.prompt({ - name:"isCommit", - type:"confirm", - message:"是否提交以上文件到仓库?" - }) - isCommit = result.isCommit - } - if(isCommit){ - execShellScript(`git commit -a -m "Update ${package.name}"`) - } - } + return dayjs(lastModified).isAfter(dayjs(lastPublish)) && !dayjs(pkgLastModified).isSame(dayjs(lastModified)) } -let VERSION_STEPS = ["major", "minor", "patch","premajor","preminor","prepatch","prerelease"] -program - .command("publish") - .description("发布当前工作区下的包") - .option("-p, --package-name", "包名称") - .option("-f, --force", "强制发布") - .option("--no-auto-commit", "不提交源码") - .option("-q, --query", "询问是否发布,否则会自动发布") - .option("--no-add-version-tag", "不添加版本标签") - .addOption(new Option('-i, --version-increment-step [value]', '版本增长方式').default("patch").choices(VERSION_STEPS)) - .action(async (options) => { - console.log(JSON.stringify(options)) - const {versionIncrementStep,autoCommit,addVersionTag} = options - - const packageFolder = process.cwd() - const packageName = path.basename(packageFolder) - const pkgFile = path.join(packageFolder,"package.json") - const package = fs.readJSONSync(pkgFile) - const packageBackup = Object.assign({},package) // 备份package.json,当操作失败时,还原 - - logger.log("将发布包:{}",`${packageName}`) - - // 第一步: 提交代码 - commitProject(package,options) - - // 第二步: 更新版本号和发布时间 - package.version = semver.inc(package.version,versionIncrementStep) - package.lastPublish = dayjs().format() - fs.writeJSONSync(pkgFile,package) +/** + * 发布所有包 + * + * 将比对最后发布时间和最后修改时间的差别来决定是否发布 + * + * + * @param {*} packages + */ +async function publishAllPackages(packages,options={}){ + const tasks = logger.tasklist() + const workspaceRoot = process.cwd() + // 依次对每个包进行发布 + for(let package of packages){ + tasks.add(`发布包[${package.name}]`) + try{ + if(package.isDirty){ + await runPackageScript(workspaceRoot,package,{silent:true,...options}) + let { version } = fs.readJSONSync(path.join(workspaceRoot,"packages",package.value,"package.json")) + tasks.complete(`${package.version}->${version}`) + }else{ + tasks.skip() + } + }catch(e){ + tasks.error(`${e.message}`) + } + } +} - - - - // 第三步:执行发布到Npm + +/** + * 发布包,并且在package.json中记录最后发布时间 + * 本命令只能在包文件夹下执行 + * @param {*} options + */ +async function publishPackage(options){ + const { versionIncrementStep,silent=true } = options + + // 此命令需要切换到包所在目录 + const packageFolder = process.cwd() + const packageName = path.basename(packageFolder) + const pkgFile = path.join(packageFolder,"package.json") + + if(!fs.existsSync(pkgFile)){ + logger.log("当前包[{}]不存在package.json文件",packageName) + throw new Error("当前包不存在package.json文件,请在包文件夹下执行") + } + + let package = fs.readJSONSync(pkgFile) + const oldVersion = package.version + let packageBackup = Object.assign({},package) // 备份package.json,当操作失败时,还原 + + logger.log("发布包:{}",`@voerkai18n/${packageName}`) + + const tasks = logger.tasklist() + + try{ + // 第一步: 更新版本号和发布时间 + tasks.add("更新版本号") + await asyncExecShellScript(`npm version ${versionIncrementStep}`,{silent}) + // 重新读取包 + package = fs.readJSONSync(pkgFile) + packageBackup = Object.assign({},package) + tasks.complete(`${oldVersion}->${package.version}`) + + // 第二步:构建包 + if("build" in package.scripts){ + tasks.add("构建包") + await asyncExecShellScript(`pnpm build`,{silent}) + tasks.complete() + } + + + // 第三步:发布 // 由于工程可能引用了工作区内的其他包,必须pnpm publish才能发布 // pnpm publish会修正引用工作区其他包到的依赖信息,而npm publish不能识别工作区内的依赖,会导致报错 - try{ - execShellScript(`pnpm publish --no-git-checks --access publish`) - // 当发布完毕后,由于更新了publish,因此需要重新提交代码 - }catch{ - fs.writeJSONSync(pkgFile,packageBackup) - } + tasks.add("发布包") + await asyncExecShellScript(`pnpm publish --no-git-checks --access publish`,{silent}) + tasks.complete() - }) - - program - .command("list") - .description("列出各个包的最后一次提交时间和版本信息") - .action(options => { - assertInWorkspaceRoot() + // 第四步:更新发布时间 + tasks.add("更新发布时间") + package.lastPublish = dayjs().format() + fs.writeFileSync(pkgFile,JSON.stringify(package,null,4)) + tasks.complete() + + }catch(e){// 如果发布失败,则还原package.json + fs.writeFileSync(pkgFile,JSON.stringify(packageBackup,null,4)) + tasks.error(`${e.message}`) + } + +} + + + +program + .command("list") + .description("列出各个包的最后一次提交时间和版本信息") + .action(options => { + assertInWorkspaceRoot() + workspaceRoot = process.cwd() + const table = logger.table({grid:1}) + table.addHeader("包名","版本号","最后提交时间","最后修改时间") getPackages().forEach(package => { - if(package.lastCommit){ - console.log(`${package.name.padEnd(16)}\tVersion: ${package.version.padEnd(12)} lastCommit: ${dayjs(package.lastCommit).format("YYYY/MM/DD hh:mm:ss")}(${dayjs(package.lastCommit).fromNow()}) `) + const lastPublish = package.lastPublish ? dayjs(package.lastPublish).format("MM/DD hh:mm:ss") : "None" + const lastPublishRef = package.lastPublish ? `(${dayjs(package.lastPublish).fromNow()})` : "" + const lastModified = getFolderLastModified(path.join(workspaceRoot,"packages",package.value)) + const lastUpdate = dayjs(lastModified).format("MM/DD hh:mm:ss") + const lastUpdateRef = dayjs(lastModified).fromNow() + if(package.lastPublish){ + table.addRow(package.name,package.version,`${lastPublish}(${lastPublishRef})`,`${lastUpdate}(${lastUpdateRef})`) }else{ - console.log(`${package.name.padEnd(16)}\tVersion: ${package.version.padEnd(12)} lastCommit: None `) + table.addRow(package.name,package.version,"None",`${lastUpdate}(${lastUpdateRef})`) } }) - }) - - - - program.parseAsync(process.argv); + table.render() + }) -// inquirer -// .prompt([ -// { -// type: "confirm", -// name: "autoPublish", -// message: "是否自动发布?", -// default: true, -// }, -// { -// type: "checkbox", -// name: "selectPackages", -// message: "请选择要发布的库:", -// choices: packages, -// when: function (answer) { -// return !answer.autoPublish; -// }, -// }, -// ]) -// .then((answers) => { -// console.log(answers); -// }) -// .catch((error) => { -// if (error.isTtyError) { -// // Prompt couldn't be rendered in the current environment -// } else { -// // Something else went wrong -// } -// }); + +async function answerForSelectPackages(packages,options){ + const workspaceRoot = process.cwd() + return new Promise((resolve,reject) => { + inquirer + .prompt([ + { + type: "checkbox", + name: "selectPackages", + message: "请选择要发布的库:", + choices: packages.map(package => { + const lastPublish = package.lastPublish ? dayjs(package.lastPublish).format("MM/DD hh:mm:ss") : "None" + const lastPublishRef = package.lastPublish ? `(${dayjs(package.lastPublish).fromNow()})` : "" + const lastModified = getFolderLastModified(path.join(workspaceRoot,"packages",package.value)) + const lastUpdate = dayjs(lastModified).format("MM/DD hh:mm:ss") + const lastUpdateRef = dayjs(lastModified).fromNow() + return { + ...package, + value: package, + name:`${package.name.padEnd(24)}Version: ${package.version.padEnd(8)} LastPublish: ${lastPublish.padEnd(16)}${lastPublishRef} lastModified: ${lastUpdate}(${lastUpdateRef})`, } + }), + pageSize:12, + loop: false + }, + ]) + .then((answers) => { + resolve(answers.selectPackages) + }) + .catch((error) => { + logger.log(error.message) + reject(error) + }); + }) +} +/** + * 发布包的模式 + * + * 1. 在包中使用 + * { + * scripts:{ + * "release":"pnpm autopublish" + * } + * } + * + * 2. 发布所有包 + * { + * scripts:{ + * "autopublish":"pnpm autopublish -a" + * } + * } + * > pnpm autopublish -- -a // 自动发布,会询问要发布的 + * > pnpm autopublish -- -a --no-ask // 自动发布,不会询问全自动发布 + * + */ +const VERSION_STEPS = ["major", "minor", "patch","premajor","preminor","prepatch","prerelease"] +program + .description("自动发布包") + .option("-a, --all", "发布所有包") + .option("-n, --no-ask", "不询问") + .option("-s, --no-silent", "静默显示脚本输出") + .addOption(new Option('-i, --version-increment-step [value]', '版本增长方式').default("patch").choices(VERSION_STEPS)) + .action(async (options) => { + // 发布所有包时只能在工作区根目录下执行 + if(options.all){ + assertInWorkspaceRoot() + }else{// 发布指定包时只能在包目录下执行 + assertInPackageRoot() + } + if(options.all){ // 自动发布所有包 + const workspaceRoot = process.cwd() + let packages = getPackages() + if(options.ask){ + packages = await answerForSelectPackages(packages,options) + } + if(packages.length > 0){ + await publishAllPackages(packages,options) + } + }else{// 只发布指定的包 + await publishPackage(options) + } + }) + + program.parseAsync(process.argv); + + \ No newline at end of file diff --git a/packages/autopublish/package.json b/packages/autopublish/package.json index 6f589c7..ba572ae 100644 --- a/packages/autopublish/package.json +++ b/packages/autopublish/package.json @@ -1,20 +1,20 @@ { - "name": "@voerkai18n/publish", - "version": "1.0.1", - "description": "发布项目工具", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "release": "npm version patch && pnpm publish --no-git-checks --access public", - "postpublish": "git push --follow-tags && npm run build && npm publish" - }, - "author": "", - "license": "ISC", - "bin": { - "publish": "./index.js" - }, - "dependencies": { - "commander": "^9.0.0", - "semver": "^7.3.5" - } -} + "name": "@voerkai18n/autopublish", + "version": "1.0.2", + "description": "自动发布工作区的包", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "release": "node ./index.js publish" + }, + "author": "", + "license": "ISC", + "bin": { + "autopublish": "./index.js" + }, + "dependencies": { + "commander": "^9.0.0", + "fast-glob": "^3.2.11" + }, + "lastPublish": "2022-04-06T15:36:15+08:00" +} \ No newline at end of file diff --git a/packages/autopublish/readme.md b/packages/autopublish/readme.md index 775db72..c1f3730 100644 --- a/packages/autopublish/readme.md +++ b/packages/autopublish/readme.md @@ -1,5 +1,111 @@ + + +# 概述 + +`@voerkai18n`项目是一个标准的`monorepo`包工程,包含了`@voerkai18n/cli`、`@voerkai18n/runtime`、`@voerkai18n/utils`、`@voerkai18n/vue`、`@voerkai18n/vite`、`@voerkai18n/babel`、`@voerkai18n/react`、`@voerkai18n/formatters`等多个包,发布包时容易引起混乱问题,最大问题时: +- 经常忘记哪个包最近什么时间修改,哪个包应该发布。 +- 由于包之间存在依赖关系,需要按一定的顺序进行发布 + +`@voerkai18n/autopublish`用来实现全自动或手动辅助进行发布。 + +**源码与文档:**[https://gitee.com/zhangfisher/voerka-i18n](https://gitee.com/zhangfisher/voerka-i18n) + [![fisher/voerka-i18n](https://gitee.com/zhangfisher/voerka-i18n/widgets/widget_card.svg?colors=4183c4,ffffff,ffffff,e3e9ed,666666,9b9b9b)](https://gitee.com/zhangfisher/voerka-i18n) -`@voerkai18n/autopublish`辅助进行自动发布 +# 使用 -源码与文档:[https://gitee.com/zhangfisher/voerka-i18n](https://gitee.com/zhangfisher/voerka-i18n) \ No newline at end of file +## 准备 + +`@voerkai18n/autopublish`用于采用`pnpmp`创建的`monorepo`包工程,不支持`lerna/yarn`。 +按照常规约定,包存放在`/packages/`。 + +## 第一步:配置包的发布脚本 + +将`@voerkai18n/autopublish`添加为包的开发依赖。 + +```javascript +// 进入包文件夹后执行 +> pnpm add -D @voerkai18n/autopublish +``` +然后,配置发布脚本: +```json +{ + "scripts":{ + "build":"默认的包构建命令", + "release":"pnpm autopublish" + }, + "devDependencies": { + "@voerkai18n/autopublish": "workspace:^1.0.0" + } +} +``` + +- 发布脚本必须为`release`,不能是其他名称,特别是`publish` +- `pnpm autopublish`也可以在包路径下单独执行。 +- `pnpm autopublish`默认依次执行: + - `npm version patch`:升级版本号 + - `pnpm run build`(可选) + - `pnpm publish --no-git-checks --access publish` +- 默认每次发布均会升级`patch`版本号,可以通过`pnpm autopublish -i <版本递增方式>`来增加版本号,递增方式可选:[`"major"`, `"minor"`, `"patch"`,`"premajor"`,`"preminor"`,`"prepatch"`,`"prerelease"`] +- 每次执行`pnpm autopublish`均会在当前包的`package.json`中添加`lastPublish`字段,用来记录发布的时间。这是下一次发布时进行自动比对发布的依据。 + + +## 第二步:配置工作区发布脚本 + +在当前工程的根文件夹下配置`package.json` +```json +{ + "scripts":{ + "list:package": "node ./packages/autopublish/index.js list", + "autopublish": "node ./packages/autopublish/index.js" + }, + "devDependencies": { + "@voerkai18n/autopublish": "workspace:^1.0.0" + } +} +``` +## 第三步:自动发布所有包 + +```javascript +> pnpm autopublish -- -a -n +``` + +`pnpm autopublish`会自动枚举出当前所有包,然后对比包路径`packages/<包名>`最后修改时间和`package.json`的`lastPublish`字段值,如果: +- 最后修改时间大于最后发布时间,则发布该包 +- 最后修改时间关于或者小于最后发布时间,则忽略发布该包 + +因此,每次当修改完工程后,可以自动执行`pnpm autopublish -- -a -n`就可以进行全自动发布。 + +`pnpm autopublish`命令行参数: +```shell +自动发布包 + +Options: + -a, --all 发布所有包 + -n, --no-ask 不询问 + -s, --no-silent 静默显示脚本输出 + -i, --version-increment-step [value] 版本增长方式 (choices: "major", "minor", "patch", "premajor", "preminor", "prepatch", + "prerelease", default: "patch") + -h, --help display help for command + +Commands: + list 列出各个包的最后一次提交时间和版本信息 +``` + +- `-a`代表要发布所有包,如果没有启用`-n`,则会让用户选择要发布哪一个包。如果启用`-n`参数,则会全自动比对发布时间和修改时间后发布。 +- `-no-ask`代表不会询问让用户选择要发布的包. +- `--no-silent`代表是否不输出脚本输出。 +- 由于包之间存在依赖关系,`autopublish`会根据依赖关系进行排序发布和关联发布。比如`@voerkai18n/cli`依赖于`@voerkai18n/utils`,当`@voerkai18n/utils`有更新需要发布时,`@voerkai18n/cli`也会自动发布。 + + +## 第四步: 手动选择发布 + +`pnpm autopublish -- -a -n`会根据发布时间和修改时间进行自动发布。也支持手动选择要发布的包。 +```javascript +> pnpm autopublish -- -a +```` +如果不启用`-n`参数,则会列出当前工作区的所有包,让用户选择要发布的包。 + +## 列出包 + +`pnpm autopublish -- list`列出当前工程的所有包,并显示当前包最近更新和最近发布时间。 \ No newline at end of file diff --git a/packages/babel/index.js b/packages/babel/index.js index 07faa7d..5cf892b 100644 --- a/packages/babel/index.js +++ b/packages/babel/index.js @@ -11,9 +11,15 @@ * * { * plugins:[ - * ["voerkai18n",{}] + * ["voerkai18n",{ + * location:"./languages", + * autoImport:"./languages", + * moduleType:"esm" + * }] * ] * + * + * * } * * diff --git a/packages/babel/package.json b/packages/babel/package.json index 24e323f..861f364 100644 --- a/packages/babel/package.json +++ b/packages/babel/package.json @@ -1,20 +1,24 @@ { - "name": "@voerkai18n/babel", - "version": "1.0.4", - "description": "VoerkaI18n babel plugin", - "main": "index.js", - "homepage": "https://gitee.com/zhangfisher/voerka-i18n", - "repository": { - "type": "git", - "url": "git+https://gitee.com/zhangfisher/voerka-i18n.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "release": "npm version patch && pnpm publish --no-git-checks --access public" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@voerkai18n/utils": "workspace:^1.0.0" - } -} + "name": "@voerkai18n/babel", + "version": "1.0.21", + "description": "VoerkaI18n babel plugin", + "main": "index.js", + "homepage": "https://gitee.com/zhangfisher/voerka-i18n", + "repository": { + "type": "git", + "url": "git+https://gitee.com/zhangfisher/voerka-i18n.git" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "release": "pnpm autopublish" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@voerkai18n/utils": "workspace:^1.0.6" + }, + "devDependencies": { + "@voerkai18n/autopublish": "workspace:^1.0.2" + }, + "lastPublish": "2022-04-10T17:21:40+08:00" +} \ No newline at end of file diff --git a/packages/cli/available_languages.js b/packages/cli/available_languages.js new file mode 100644 index 0000000..a4c53de --- /dev/null +++ b/packages/cli/available_languages.js @@ -0,0 +1,2556 @@ +/** + * 常用的语言代码 + * + * 此处只包含一些常用的语言代码,如果你的语言没有在此处列出,请自行添加 + * + * + * + */ + +module.exports = { + "zh": [ + { + "name": "zh", + "title": "中文" + }, + { + "name": "cht", + "title": "繁体中文" + }, + { + "name": "en", + "title": "英语" + }, + { + "name": "jp", + "title": "日语" + }, + { + "name": "kor", + "title": "韩语" + }, + { + "name": "fra", + "title": "法语" + }, + { + "name": "spa", + "title": "西班牙语" + }, + { + "name": "ru", + "title": "俄语" + }, + { + "name": "de", + "title": "德语" + }, + { + "name": "it", + "title": "意大利语" + }, + { + "name": "ara", + "title": "阿拉伯语" + }, + { + "name": "pt", + "title": "葡萄牙语" + }, + { + "name": "el", + "title": "希腊语" + }, + { + "name": "nl", + "title": "荷兰语" + }, + { + "name": "pl", + "title": "波兰语" + }, + { + "name": "bul", + "title": "保加利亚语" + }, + { + "name": "est", + "title": "爱沙尼亚语" + }, + { + "name": "dan", + "title": "丹麦语" + }, + { + "name": "fin", + "title": "芬兰语" + }, + { + "name": "cs", + "title": "捷克语" + }, + { + "name": "rom", + "title": "罗马尼亚语" + }, + { + "name": "slo", + "title": "斯洛文尼亚语" + }, + { + "name": "swe", + "title": "瑞典语" + }, + { + "name": "hu", + "title": "匈牙利语" + }, + { + "name": "vie", + "title": "越南语" + } + ], + "cht": [ + { + "name": "zh", + "title": "中文" + }, + { + "name": "cht", + "title": "繁體中文" + }, + { + "name": "en", + "title": "英語" + }, + { + "name": "jp", + "title": "日語" + }, + { + "name": "kor", + "title": "韓語" + }, + { + "name": "fra", + "title": "法語" + }, + { + "name": "spa", + "title": "西班牙語" + }, + { + "name": "ru", + "title": "俄語" + }, + { + "name": "de", + "title": "德語" + }, + { + "name": "it", + "title": "義大利語" + }, + { + "name": "ara", + "title": "阿拉伯語" + }, + { + "name": "pt", + "title": "葡萄牙語" + }, + { + "name": "el", + "title": "希臘語" + }, + { + "name": "nl", + "title": "荷蘭語" + }, + { + "name": "pl", + "title": "波蘭語" + }, + { + "name": "bul", + "title": "保加利亞語" + }, + { + "name": "est", + "title": "愛沙尼亞語" + }, + { + "name": "dan", + "title": "丹麥語" + }, + { + "name": "fin", + "title": "芬蘭語" + }, + { + "name": "cs", + "title": "捷克語" + }, + { + "name": "rom", + "title": "羅馬尼亞語" + }, + { + "name": "slo", + "title": "斯洛文尼亞語" + }, + { + "name": "swe", + "title": "瑞典語" + }, + { + "name": "hu", + "title": "匈牙利語" + }, + { + "name": "vie", + "title": "越南語" + } + ], + "en": [ + { + "name": "zh", + "title": "Chinese" + }, + { + "name": "cht", + "title": "traditional Chinese" + }, + { + "name": "en", + "title": "English" + }, + { + "name": "jp", + "title": "Japanese" + }, + { + "name": "kor", + "title": "Korean" + }, + { + "name": "fra", + "title": "French" + }, + { + "name": "spa", + "title": "Spanish" + }, + { + "name": "ru", + "title": "Russian" + }, + { + "name": "de", + "title": "German" + }, + { + "name": "it", + "title": "Italian" + }, + { + "name": "ara", + "title": "Arabic" + }, + { + "name": "pt", + "title": "Portuguese" + }, + { + "name": "el", + "title": "Greek" + }, + { + "name": "nl", + "title": "Dutch" + }, + { + "name": "pl", + "title": "polish" + }, + { + "name": "bul", + "title": "Bulgarian" + }, + { + "name": "est", + "title": "Estonian" + }, + { + "name": "dan", + "title": "Danish" + }, + { + "name": "fin", + "title": "Finnish" + }, + { + "name": "cs", + "title": "Czech" + }, + { + "name": "rom", + "title": "Romanian" + }, + { + "name": "slo", + "title": "Slovenian" + }, + { + "name": "swe", + "title": "Swedish" + }, + { + "name": "hu", + "title": "Hungarian" + }, + { + "name": "vie", + "title": "Vietnamese" + } + ], + "jp": [ + { + "name": "zh", + "title": "中国語" + }, + { + "name": "cht", + "title": "繁体字中国語" + }, + { + "name": "en", + "title": "英語" + }, + { + "name": "jp", + "title": "日本語" + }, + { + "name": "kor", + "title": "韓国語" + }, + { + "name": "fra", + "title": "フランス語" + }, + { + "name": "spa", + "title": "スペイン語" + }, + { + "name": "ru", + "title": "ロシア語" + }, + { + "name": "de", + "title": "ドイツ語" + }, + { + "name": "it", + "title": "イタリア語" + }, + { + "name": "ara", + "title": "アラビア語" + }, + { + "name": "pt", + "title": "ポルトガル語" + }, + { + "name": "el", + "title": "ギリシャ語" + }, + { + "name": "nl", + "title": "オランダ語" + }, + { + "name": "pl", + "title": "ポーランド語" + }, + { + "name": "bul", + "title": "ブルガリア語" + }, + { + "name": "est", + "title": "エストニア語" + }, + { + "name": "dan", + "title": "デンマーク語" + }, + { + "name": "fin", + "title": "フィンランド語" + }, + { + "name": "cs", + "title": "チェコ語" + }, + { + "name": "rom", + "title": "ローマニア語" + }, + { + "name": "slo", + "title": "スロベニア語" + }, + { + "name": "swe", + "title": "スウェーデン語" + }, + { + "name": "hu", + "title": "ハンガリー語" + }, + { + "name": "vie", + "title": "ベトナム語" + } + ], + "kor": [ + { + "name": "zh", + "title": "중국어" + }, + { + "name": "cht", + "title": "중국어 번체" + }, + { + "name": "en", + "title": "영어" + }, + { + "name": "jp", + "title": "일본어" + }, + { + "name": "kor", + "title": "한국어" + }, + { + "name": "fra", + "title": "프랑스어" + }, + { + "name": "spa", + "title": "스페인어" + }, + { + "name": "ru", + "title": "러시아어" + }, + { + "name": "de", + "title": "독일어" + }, + { + "name": "it", + "title": "이탈리아어" + }, + { + "name": "ara", + "title": "아랍어" + }, + { + "name": "pt", + "title": "포르투갈어" + }, + { + "name": "el", + "title": "그리스어" + }, + { + "name": "nl", + "title": "네덜란드어" + }, + { + "name": "pl", + "title": "폴란드어" + }, + { + "name": "bul", + "title": "불가리아어" + }, + { + "name": "est", + "title": "에스토니아어" + }, + { + "name": "dan", + "title": "덴마크어" + }, + { + "name": "fin", + "title": "핀란드어" + }, + { + "name": "cs", + "title": "체코어" + }, + { + "name": "rom", + "title": "로마니아어" + }, + { + "name": "slo", + "title": "슬로베니아어" + }, + { + "name": "swe", + "title": "스웨덴어" + }, + { + "name": "hu", + "title": "헝가리어" + }, + { + "name": "vie", + "title": "베트남어" + } + ], + "fra": [ + { + "name": "zh", + "title": "Chinois" + }, + { + "name": "cht", + "title": "chinois traditionnel" + }, + { + "name": "en", + "title": "anglais" + }, + { + "name": "jp", + "title": "japonais" + }, + { + "name": "kor", + "title": "coréen" + }, + { + "name": "fra", + "title": "français" + }, + { + "name": "spa", + "title": "espagnol" + }, + { + "name": "ru", + "title": "russe" + }, + { + "name": "de", + "title": "allemand" + }, + { + "name": "it", + "title": "italien" + }, + { + "name": "ara", + "title": "arabe" + }, + { + "name": "pt", + "title": "portugais" + }, + { + "name": "el", + "title": "grec" + }, + { + "name": "nl", + "title": "néerlandais" + }, + { + "name": "pl", + "title": "polonais" + }, + { + "name": "bul", + "title": "bulgare" + }, + { + "name": "est", + "title": "estonien" + }, + { + "name": "dan", + "title": "danois" + }, + { + "name": "fin", + "title": "finnois" + }, + { + "name": "cs", + "title": "tchèque" + }, + { + "name": "rom", + "title": "roumain" + }, + { + "name": "slo", + "title": "slovène" + }, + { + "name": "swe", + "title": "suédois" + }, + { + "name": "hu", + "title": "hongrois" + }, + { + "name": "vie", + "title": "vietnamien" + } + ], + "spa": [ + { + "name": "zh", + "title": "Chino" + }, + { + "name": "cht", + "title": "chino tradicional" + }, + { + "name": "en", + "title": "inglés" + }, + { + "name": "jp", + "title": "japonés" + }, + { + "name": "kor", + "title": "coreano" + }, + { + "name": "fra", + "title": "francés" + }, + { + "name": "spa", + "title": "español" + }, + { + "name": "ru", + "title": "ruso" + }, + { + "name": "de", + "title": "alemán" + }, + { + "name": "it", + "title": "italiano" + }, + { + "name": "ara", + "title": "árabe" + }, + { + "name": "pt", + "title": "portugués" + }, + { + "name": "el", + "title": "griego" + }, + { + "name": "nl", + "title": "holandés" + }, + { + "name": "pl", + "title": "polaco" + }, + { + "name": "bul", + "title": "búlgaro" + }, + { + "name": "est", + "title": "estonio" + }, + { + "name": "dan", + "title": "danés" + }, + { + "name": "fin", + "title": "finlandés" + }, + { + "name": "cs", + "title": "checo" + }, + { + "name": "rom", + "title": "Romano" + }, + { + "name": "slo", + "title": "esloveno" + }, + { + "name": "swe", + "title": "sueco" + }, + { + "name": "hu", + "title": "húngaro" + }, + { + "name": "vie", + "title": "vietnamita" + } + ], + "ru": [ + { + "name": "zh", + "title": "китайский" + }, + { + "name": "cht", + "title": "английский" + }, + { + "name": "en", + "title": "японский" + }, + { + "name": "jp", + "title": "корейский" + }, + { + "name": "kor", + "title": "французский" + }, + { + "name": "fra", + "title": "испанский" + }, + { + "name": "spa", + "title": "русский" + }, + { + "name": "ru", + "title": "немецкий" + }, + { + "name": "de", + "title": "итальянский" + }, + { + "name": "it", + "title": "арабский" + }, + { + "name": "ara", + "title": "португальский" + }, + { + "name": "pt", + "title": "греческий" + }, + { + "name": "el", + "title": "голландский" + }, + { + "name": "nl", + "title": "польский" + }, + { + "name": "pl", + "title": "болгарский" + }, + { + "name": "bul", + "title": "Эстонский" + }, + { + "name": "est", + "title": "датский" + }, + { + "name": "dan", + "title": "финский" + }, + { + "name": "fin", + "title": "чешский" + }, + { + "name": "cs", + "title": "Римский" + }, + { + "name": "rom", + "title": "словенский" + }, + { + "name": "slo", + "title": "шведский" + }, + { + "name": "swe", + "title": "венгерский" + }, + { + "name": "hu", + "title": "вьетнамский" + }, + { + "name": "vie" + } + ], + "de": [ + { + "name": "zh", + "title": "Chinesisch" + }, + { + "name": "cht", + "title": "traditionelles Chinesisch" + }, + { + "name": "en", + "title": "Englisch" + }, + { + "name": "jp", + "title": "Japanisch" + }, + { + "name": "kor", + "title": "Koreanisch" + }, + { + "name": "fra", + "title": "Französisch" + }, + { + "name": "spa", + "title": "Spanisch" + }, + { + "name": "ru", + "title": "Russisch" + }, + { + "name": "de", + "title": "Deutsch" + }, + { + "name": "it", + "title": "Italienisch" + }, + { + "name": "ara", + "title": "Arabisch" + }, + { + "name": "pt", + "title": "Portugiesisch" + }, + { + "name": "el", + "title": "Griechisch" + }, + { + "name": "nl", + "title": "Niederländisch" + }, + { + "name": "pl", + "title": "Polnisch" + }, + { + "name": "bul", + "title": "Bulgarisch" + }, + { + "name": "est", + "title": "Estnisch" + }, + { + "name": "dan", + "title": "Dänisch" + }, + { + "name": "fin", + "title": "Finnisch" + }, + { + "name": "cs", + "title": "Tschechisch" + }, + { + "name": "rom", + "title": "Rumänisch" + }, + { + "name": "slo", + "title": "Slowenisch" + }, + { + "name": "swe", + "title": "Schwedisch" + }, + { + "name": "hu", + "title": "Ungarisch" + }, + { + "name": "vie", + "title": "Vietnamesisch" + } + ], + "it": [ + { + "name": "zh", + "title": "Cinese" + }, + { + "name": "cht", + "title": "cinese tradizionale" + }, + { + "name": "en", + "title": "inglese" + }, + { + "name": "jp", + "title": "giapponese" + }, + { + "name": "kor", + "title": "coreano" + }, + { + "name": "fra", + "title": "francese" + }, + { + "name": "spa", + "title": "spagnolo" + }, + { + "name": "ru", + "title": "russo" + }, + { + "name": "de", + "title": "tedesco" + }, + { + "name": "it", + "title": "italiano" + }, + { + "name": "ara", + "title": "arabo" + }, + { + "name": "pt", + "title": "portoghese" + }, + { + "name": "el", + "title": "greco" + }, + { + "name": "nl", + "title": "olandese" + }, + { + "name": "pl", + "title": "polacco" + }, + { + "name": "bul", + "title": "bulgaro" + }, + { + "name": "est", + "title": "estone" + }, + { + "name": "dan", + "title": "danese" + }, + { + "name": "fin", + "title": "finlandese" + }, + { + "name": "cs", + "title": "ceco" + }, + { + "name": "rom", + "title": "rumeno" + }, + { + "name": "slo", + "title": "sloveno" + }, + { + "name": "swe", + "title": "svedese" + }, + { + "name": "hu", + "title": "ungherese" + }, + { + "name": "vie", + "title": "vietnamita" + } + ], + "ara": [ + { + "name": "zh", + "title": "الصينية" + }, + { + "name": "cht", + "title": "التقليدية" + }, + { + "name": "en", + "title": "الإنجليزية" + }, + { + "name": "jp", + "title": "اليابانية" + }, + { + "name": "kor", + "title": "الكورية" + }, + { + "name": "fra", + "title": "الفرنسية" + }, + { + "name": "spa", + "title": "الإسبانية" + }, + { + "name": "ru", + "title": "الروسية" + }, + { + "name": "de", + "title": "الألمانية" + }, + { + "name": "it", + "title": "الإيطالية" + }, + { + "name": "ara", + "title": "العربية" + }, + { + "name": "pt", + "title": "البرتغالية" + }, + { + "name": "el", + "title": "اليونانية" + }, + { + "name": "nl", + "title": "الهولندية" + }, + { + "name": "pl", + "title": "البولندية" + }, + { + "name": "bul", + "title": "البلغارية" + }, + { + "name": "est", + "title": "الإستونية" + }, + { + "name": "dan", + "title": "الدانماركية" + }, + { + "name": "fin", + "title": "الفنلندية" + }, + { + "name": "cs", + "title": "التشيكية" + }, + { + "name": "rom", + "title": "الرومانية" + }, + { + "name": "slo", + "title": "السلوفينية" + }, + { + "name": "swe", + "title": "السويدية" + }, + { + "name": "hu", + "title": "المجرية" + }, + { + "name": "vie", + "title": "الفيتنامية" + } + ], + "pt": [ + { + "name": "zh", + "title": "Chinês" + }, + { + "name": "cht", + "title": "Chinês tradicional" + }, + { + "name": "en", + "title": "Inglês" + }, + { + "name": "jp", + "title": "Japonês" + }, + { + "name": "kor", + "title": "Coreano" + }, + { + "name": "fra", + "title": "Francês" + }, + { + "name": "spa", + "title": "Espanhol" + }, + { + "name": "ru", + "title": "Russo" + }, + { + "name": "de", + "title": "Alemão" + }, + { + "name": "it", + "title": "Italiano" + }, + { + "name": "ara", + "title": "Árabe" + }, + { + "name": "pt", + "title": "Português" + }, + { + "name": "el", + "title": "Grego" + }, + { + "name": "nl", + "title": "Holandês" + }, + { + "name": "pl", + "title": "Polonês" + }, + { + "name": "bul", + "title": "Búlgaro" + }, + { + "name": "est", + "title": "Estoniano" + }, + { + "name": "dan", + "title": "Dinamarquês" + }, + { + "name": "fin", + "title": "Finlandês" + }, + { + "name": "cs", + "title": "Checo" + }, + { + "name": "rom", + "title": "Romeno" + }, + { + "name": "slo", + "title": "Esloveno" + }, + { + "name": "swe", + "title": "Sueco" + }, + { + "name": "hu", + "title": "Húngaro" + }, + { + "name": "vie", + "title": "Vietnamita" + } + ], + "el": [ + { + "name": "zh", + "title": "Αγγλικά" + }, + { + "name": "cht", + "title": "Ιαπωνικά" + }, + { + "name": "en", + "title": "Κορεατικά" + }, + { + "name": "jp", + "title": "Γαλλικά" + }, + { + "name": "kor", + "title": "Ισπανικά" + }, + { + "name": "fra", + "title": "Ρωσικά" + }, + { + "name": "spa", + "title": "Γερμανικά" + }, + { + "name": "ru", + "title": "Ιταλικά" + }, + { + "name": "de", + "title": "Αραβικά" + }, + { + "name": "it", + "title": "Πορτογαλικά" + }, + { + "name": "ara", + "title": "Ελληνικά" + }, + { + "name": "pt", + "title": "Ολλανδικά" + }, + { + "name": "el", + "title": "Πολωνικά" + }, + { + "name": "nl", + "title": "Βουλγαρικά" + }, + { + "name": "pl", + "title": "Εσθονικά" + }, + { + "name": "bul", + "title": "Δανικά" + }, + { + "name": "est", + "title": "Φινλανδικά" + }, + { + "name": "dan", + "title": "Τσεχικά" + }, + { + "name": "fin", + "title": "Ρουμανικά" + }, + { + "name": "cs", + "title": "Σλοβενικά" + }, + { + "name": "rom", + "title": "Σουηδικά" + }, + { + "name": "slo", + "title": "Ουγγρικά" + }, + { + "name": "swe", + "title": "Βιετναμέζικα" + }, + { + "name": "hu" + }, + { + "name": "vie" + } + ], + "nl": [ + { + "name": "zh", + "title": "Chinees" + }, + { + "name": "cht", + "title": "traditioneel Chinees" + }, + { + "name": "en", + "title": "Engels" + }, + { + "name": "jp", + "title": "Japans" + }, + { + "name": "kor", + "title": "Koreaans" + }, + { + "name": "fra", + "title": "Frans" + }, + { + "name": "spa", + "title": "Spaans" + }, + { + "name": "ru", + "title": "Russisch" + }, + { + "name": "de", + "title": "Duits" + }, + { + "name": "it", + "title": "Italiaans" + }, + { + "name": "ara", + "title": "Arabisch" + }, + { + "name": "pt", + "title": "Portugees" + }, + { + "name": "el", + "title": "Grieks" + }, + { + "name": "nl", + "title": "Nederlands" + }, + { + "name": "pl", + "title": "Pools" + }, + { + "name": "bul", + "title": "Bulgaars" + }, + { + "name": "est", + "title": "Ests" + }, + { + "name": "dan", + "title": "Deens" + }, + { + "name": "fin", + "title": "Fins" + }, + { + "name": "cs", + "title": "Tsjechisch" + }, + { + "name": "rom", + "title": "Roemeens" + }, + { + "name": "slo", + "title": "Sloveens" + }, + { + "name": "swe", + "title": "Zweeds" + }, + { + "name": "hu", + "title": "Hongaars" + }, + { + "name": "vie", + "title": "Vietnamees" + } + ], + "pl": [ + { + "name": "zh", + "title": "Chiński" + }, + { + "name": "cht", + "title": "tradycyjny chiński" + }, + { + "name": "en", + "title": "angielski" + }, + { + "name": "jp", + "title": "japoński" + }, + { + "name": "kor", + "title": "koreański" + }, + { + "name": "fra", + "title": "francuski" + }, + { + "name": "spa", + "title": "hiszpański" + }, + { + "name": "ru", + "title": "rosyjski" + }, + { + "name": "de", + "title": "niemiecki" + }, + { + "name": "it", + "title": "włoski" + }, + { + "name": "ara", + "title": "arabski" + }, + { + "name": "pt", + "title": "portugalski" + }, + { + "name": "el", + "title": "grecki" + }, + { + "name": "nl", + "title": "holenderski" + }, + { + "name": "pl", + "title": "polski" + }, + { + "name": "bul", + "title": "bułgarski" + }, + { + "name": "est", + "title": "estoński" + }, + { + "name": "dan", + "title": "duński" + }, + { + "name": "fin", + "title": "fiński" + }, + { + "name": "cs", + "title": "czeski" + }, + { + "name": "rom", + "title": "rumuński" + }, + { + "name": "slo", + "title": "słoweński" + }, + { + "name": "swe", + "title": "szwedzki" + }, + { + "name": "hu", + "title": "węgierski" + }, + { + "name": "vie", + "title": "wietnamski" + } + ], + "bul": [ + { + "name": "zh", + "title": "Китайски" + }, + { + "name": "cht", + "title": "традиционен китайски" + }, + { + "name": "en", + "title": "английски" + }, + { + "name": "jp", + "title": "японски" + }, + { + "name": "kor", + "title": "корейски" + }, + { + "name": "fra", + "title": "френски" + }, + { + "name": "spa", + "title": "испански" + }, + { + "name": "ru", + "title": "руски" + }, + { + "name": "de", + "title": "немски" + }, + { + "name": "it", + "title": "италиански" + }, + { + "name": "ara", + "title": "арабски" + }, + { + "name": "pt", + "title": "португалски" + }, + { + "name": "el", + "title": "гръцки" + }, + { + "name": "nl", + "title": "холандски" + }, + { + "name": "pl", + "title": "полски" + }, + { + "name": "bul", + "title": "български" + }, + { + "name": "est", + "title": "естонски" + }, + { + "name": "dan", + "title": "датски" + }, + { + "name": "fin", + "title": "финландски" + }, + { + "name": "cs", + "title": "чешки" + }, + { + "name": "rom", + "title": "румънски" + }, + { + "name": "slo", + "title": "словенски" + }, + { + "name": "swe", + "title": "шведски" + }, + { + "name": "hu", + "title": "унгарски" + }, + { + "name": "vie", + "title": "виетнамски" + } + ], + "est": [ + { + "name": "zh", + "title": "Hiina" + }, + { + "name": "cht", + "title": "traditsiooniline hiina" + }, + { + "name": "en", + "title": "inglise" + }, + { + "name": "jp", + "title": "jaapani" + }, + { + "name": "kor", + "title": "korea" + }, + { + "name": "fra", + "title": "prantsuse" + }, + { + "name": "spa", + "title": "hispaania" + }, + { + "name": "ru", + "title": "vene" + }, + { + "name": "de", + "title": "saksa" + }, + { + "name": "it", + "title": "itaalia" + }, + { + "name": "ara", + "title": "araabia" + }, + { + "name": "pt", + "title": "portugali" + }, + { + "name": "el", + "title": "kreeka" + }, + { + "name": "nl", + "title": "hollandi" + }, + { + "name": "pl", + "title": "poola" + }, + { + "name": "bul", + "title": "bulgaaria" + }, + { + "name": "est", + "title": "eesti" + }, + { + "name": "dan", + "title": "taani" + }, + { + "name": "fin", + "title": "soome" + }, + { + "name": "cs", + "title": "tšehhi" + }, + { + "name": "rom", + "title": "rumeenia" + }, + { + "name": "slo", + "title": "sloveeni" + }, + { + "name": "swe", + "title": "rootsi" + }, + { + "name": "hu", + "title": "ungari" + }, + { + "name": "vie", + "title": "vietnami" + } + ], + "dan": [ + { + "name": "zh", + "title": "Kinesisk" + }, + { + "name": "cht", + "title": "traditionel kinesisk" + }, + { + "name": "en", + "title": "engelsk" + }, + { + "name": "jp", + "title": "japansk" + }, + { + "name": "kor", + "title": "koreansk" + }, + { + "name": "fra", + "title": "fransk" + }, + { + "name": "spa", + "title": "spansk" + }, + { + "name": "ru", + "title": "russisk" + }, + { + "name": "de", + "title": "tysk" + }, + { + "name": "it", + "title": "italiensk" + }, + { + "name": "ara", + "title": "arabisk" + }, + { + "name": "pt", + "title": "portugisisk" + }, + { + "name": "el", + "title": "græsk" + }, + { + "name": "nl", + "title": "hollandsk" + }, + { + "name": "pl", + "title": "polsk" + }, + { + "name": "bul", + "title": "bulgarsk" + }, + { + "name": "est", + "title": "estisk" + }, + { + "name": "dan", + "title": "dansk" + }, + { + "name": "fin", + "title": "finsk" + }, + { + "name": "cs", + "title": "tjekkisk" + }, + { + "name": "rom", + "title": "rumænsk" + }, + { + "name": "slo", + "title": "slovensk" + }, + { + "name": "swe", + "title": "svensk" + }, + { + "name": "hu", + "title": "ungarsk" + }, + { + "name": "vie", + "title": "vietnamesisk" + } + ], + "fin": [ + { + "name": "zh", + "title": "Kiinalainen" + }, + { + "name": "cht", + "title": "perinteinen kiina" + }, + { + "name": "en", + "title": "englanti" + }, + { + "name": "jp", + "title": "japani" + }, + { + "name": "kor", + "title": "korea" + }, + { + "name": "fra", + "title": "ranska" + }, + { + "name": "spa", + "title": "espanja" + }, + { + "name": "ru", + "title": "venäjä" + }, + { + "name": "de", + "title": "saksa" + }, + { + "name": "it", + "title": "italia" + }, + { + "name": "ara", + "title": "arabia" + }, + { + "name": "pt", + "title": "portugali" + }, + { + "name": "el", + "title": "kreikka" + }, + { + "name": "nl", + "title": "hollanti" + }, + { + "name": "pl", + "title": "puola" + }, + { + "name": "bul", + "title": "bulgaria" + }, + { + "name": "est", + "title": "viro" + }, + { + "name": "dan", + "title": "tanska" + }, + { + "name": "fin", + "title": "suomi" + }, + { + "name": "cs", + "title": "tšekki" + }, + { + "name": "rom", + "title": "romania" + }, + { + "name": "slo", + "title": "sloveeni" + }, + { + "name": "swe", + "title": "ruotsi" + }, + { + "name": "hu", + "title": "unkari" + }, + { + "name": "vie", + "title": "vietnam" + } + ], + "cs": [ + { + "name": "zh", + "title": "Čínština" + }, + { + "name": "cht", + "title": "tradiční čínština" + }, + { + "name": "en", + "title": "angličtina" + }, + { + "name": "jp", + "title": "japonština" + }, + { + "name": "kor", + "title": "korejština" + }, + { + "name": "fra", + "title": "francouzština" + }, + { + "name": "spa", + "title": "španělština" + }, + { + "name": "ru", + "title": "ruština" + }, + { + "name": "de", + "title": "němčina" + }, + { + "name": "it", + "title": "italština" + }, + { + "name": "ara", + "title": "arabská" + }, + { + "name": "pt", + "title": "portugalština" + }, + { + "name": "el", + "title": "řecká" + }, + { + "name": "nl", + "title": "nizozemština" + }, + { + "name": "pl", + "title": "polská" + }, + { + "name": "bul", + "title": "bulharština" + }, + { + "name": "est", + "title": "estonština" + }, + { + "name": "dan", + "title": "dánština" + }, + { + "name": "fin", + "title": "finština" + }, + { + "name": "cs", + "title": "čeština" + }, + { + "name": "rom", + "title": "rumunská" + }, + { + "name": "slo", + "title": "slovinština" + }, + { + "name": "swe", + "title": "švédská" + }, + { + "name": "hu", + "title": "maďarská" + }, + { + "name": "vie", + "title": "vietnamská" + } + ], + "rom": [ + { + "name": "zh", + "title": "Chineză" + }, + { + "name": "cht", + "title": "engleză" + }, + { + "name": "en", + "title": "japoneză" + }, + { + "name": "jp", + "title": "coreeană" + }, + { + "name": "kor", + "title": "franceză" + }, + { + "name": "fra", + "title": "spaniolă" + }, + { + "name": "spa", + "title": "rusă" + }, + { + "name": "ru", + "title": "germană" + }, + { + "name": "de", + "title": "italiană" + }, + { + "name": "it", + "title": "arabă" + }, + { + "name": "ara", + "title": "portugheză" + }, + { + "name": "pt", + "title": "greacă" + }, + { + "name": "el", + "title": "olandeză" + }, + { + "name": "nl", + "title": "poloneză" + }, + { + "name": "pl", + "title": "bulgară" + }, + { + "name": "bul", + "title": "estonă" + }, + { + "name": "est", + "title": "daneză" + }, + { + "name": "dan", + "title": "finlandeză" + }, + { + "name": "fin", + "title": "cehă" + }, + { + "name": "cs", + "title": "română" + }, + { + "name": "rom", + "title": "slovenă" + }, + { + "name": "slo", + "title": "suedeză" + }, + { + "name": "swe", + "title": "maghiară" + }, + { + "name": "hu", + "title": "vietnameză" + }, + { + "name": "vie" + } + ], + "slo": [ + { + "name": "zh", + "title": "Kitajski" + }, + { + "name": "cht", + "title": "tradicionalni kitajski" + }, + { + "name": "en", + "title": "angleški" + }, + { + "name": "jp", + "title": "japonski" + }, + { + "name": "kor", + "title": "korejski" + }, + { + "name": "fra", + "title": "francoski" + }, + { + "name": "spa", + "title": "španski" + }, + { + "name": "ru", + "title": "ruski" + }, + { + "name": "de", + "title": "nemški" + }, + { + "name": "it", + "title": "italijanski" + }, + { + "name": "ara", + "title": "arabski" + }, + { + "name": "pt", + "title": "portugalski" + }, + { + "name": "el", + "title": "grški" + }, + { + "name": "nl", + "title": "nizozemski" + }, + { + "name": "pl", + "title": "poljski" + }, + { + "name": "bul", + "title": "bolgarski" + }, + { + "name": "est", + "title": "estonski" + }, + { + "name": "dan", + "title": "danski" + }, + { + "name": "fin", + "title": "finski" + }, + { + "name": "cs", + "title": "češki" + }, + { + "name": "rom", + "title": "romunski" + }, + { + "name": "slo", + "title": "slovenski" + }, + { + "name": "swe", + "title": "švedski" + }, + { + "name": "hu", + "title": "madžarski" + }, + { + "name": "vie", + "title": "vietnamski" + } + ], + "swe": [ + { + "name": "zh", + "title": "Kinesiska" + }, + { + "name": "cht", + "title": "traditionella kinesiska" + }, + { + "name": "en", + "title": "engelska" + }, + { + "name": "jp", + "title": "japanska" + }, + { + "name": "kor", + "title": "koreanska" + }, + { + "name": "fra", + "title": "franska" + }, + { + "name": "spa", + "title": "spanska" + }, + { + "name": "ru", + "title": "ryska" + }, + { + "name": "de", + "title": "tyska" + }, + { + "name": "it", + "title": "italienska" + }, + { + "name": "ara", + "title": "arabiska" + }, + { + "name": "pt", + "title": "portugisiska" + }, + { + "name": "el", + "title": "grekiska" + }, + { + "name": "nl", + "title": "nederländska" + }, + { + "name": "pl", + "title": "polska" + }, + { + "name": "bul", + "title": "bulgariska" + }, + { + "name": "est", + "title": "estniska" + }, + { + "name": "dan", + "title": "danska" + }, + { + "name": "fin", + "title": "finska" + }, + { + "name": "cs", + "title": "tjeckiska" + }, + { + "name": "rom", + "title": "rumänska" + }, + { + "name": "slo", + "title": "slovenska" + }, + { + "name": "swe", + "title": "svenska" + }, + { + "name": "hu", + "title": "ungerska" + }, + { + "name": "vie", + "title": "vietnamesiska" + } + ], + "hu": [ + { + "name": "zh", + "title": "Kínai" + }, + { + "name": "cht", + "title": "hagyományos kínai" + }, + { + "name": "en", + "title": "angol" + }, + { + "name": "jp", + "title": "japán" + }, + { + "name": "kor", + "title": "koreai" + }, + { + "name": "fra", + "title": "francia" + }, + { + "name": "spa", + "title": "spanyol" + }, + { + "name": "ru", + "title": "orosz" + }, + { + "name": "de", + "title": "német" + }, + { + "name": "it", + "title": "olasz" + }, + { + "name": "ara", + "title": "arab" + }, + { + "name": "pt", + "title": "portugál" + }, + { + "name": "el", + "title": "görög" + }, + { + "name": "nl", + "title": "holland" + }, + { + "name": "pl", + "title": "lengyel" + }, + { + "name": "bul", + "title": "bolgár" + }, + { + "name": "est", + "title": "észt" + }, + { + "name": "dan", + "title": "dán" + }, + { + "name": "fin", + "title": "finn" + }, + { + "name": "cs", + "title": "cseh" + }, + { + "name": "rom", + "title": "román" + }, + { + "name": "slo", + "title": "szlovén" + }, + { + "name": "swe", + "title": "svéd" + }, + { + "name": "hu", + "title": "magyar" + }, + { + "name": "vie", + "title": "vietnámi" + } + ], + "vie": [ + { + "name": "zh", + "title": "Trung Quốc" + }, + { + "name": "cht", + "title": "truyền thống Trung Quốc" + }, + { + "name": "en", + "title": "Anh" + }, + { + "name": "jp", + "title": "Nhật" + }, + { + "name": "kor", + "title": "Hàn Quốc" + }, + { + "name": "fra", + "title": "Pháp" + }, + { + "name": "spa", + "title": "Tây Ban Nha" + }, + { + "name": "ru", + "title": "Nga" + }, + { + "name": "de", + "title": "Đức" + }, + { + "name": "it", + "title": "Ý" + }, + { + "name": "ara", + "title": "Ả Rập" + }, + { + "name": "pt", + "title": "Bồ Đào Nha" + }, + { + "name": "el", + "title": "Hy Lạp" + }, + { + "name": "nl", + "title": "Dutch" + }, + { + "name": "pl", + "title": "Xi-lô" + }, + { + "name": "bul", + "title": "Estonia" + }, + { + "name": "est", + "title": "Đan Mạch" + }, + { + "name": "dan", + "title": "Phần Lan" + }, + { + "name": "fin", + "title": "Séc" + }, + { + "name": "cs", + "title": "Rumani" + }, + { + "name": "rom", + "title": "Xlôven" + }, + { + "name": "slo", + "title": "Thụy Điển" + }, + { + "name": "swe", + "title": "Hungari" + }, + { + "name": "hu", + "title": "ViệtNam" + }, + { + "name": "vie" + } + ] +} \ No newline at end of file diff --git a/packages/cli/baidu.translate.js b/packages/cli/baidu.translate.js new file mode 100644 index 0000000..1912e26 --- /dev/null +++ b/packages/cli/baidu.translate.js @@ -0,0 +1,59 @@ +const axios = require("axios") +const md5 = require("md5"); +const qs = require("qs"); + + +/** + * q string 是 请求翻译query UTF-8编码 +from string 是 翻译源语言 可设置为auto +to string 是 翻译目标语言 不可设置为auto +appid string 是 APPID 可在管理控制台查看 +salt string 是 随机数 可为字母或数字的字符串 +sign string 是 签名 appid+q+salt+密钥的MD5值 +* + * + */ +module.exports = function(options={}){ + const { appkey,appid ,baseurl = "http://api.fanyi.baidu.com/api/trans/vip/translate" } = options; + return { + /** + * + * @param {*} texts 多条文本 + * @returns + */ + translate:async (texts=[],from,to)=>{ + + if(Array.isArray(texts)){ + texts = texts.join("\n"); + } + // saltStep1. 拼接字符串1: + // 拼接[appid=2015063000000001][q=apple][salt=1435660288][密钥=12345678]得到字符串1:“2015063000000001apple143566028812345678” + // Step2. 计算签名:(对字符串1做MD5加密) + // sign=MD5(2015063000000001apple143566028812345678),得到sign=f89f9594663708c1605f3d736d01d2d4 + const salt = new Date().getTime() + const sign = md5(`${appid}${texts}${salt}${appkey}`); + + let params = qs.stringify({ + q:texts, + from, + to, + appid, + salt, + sign + }); + return new Promise((resolve,reject)=>{ + axios.get(`${baseurl}?${params}`).then(res=>{ + const { data } = res; + if(data.error_code){ + reject(data.error_msg) + }else{ + resolve(res.data.trans_result.map(item=>item.dst)); + } + }).catch(err=>{ + reject(err); + }) + }); + } + + } +} \ No newline at end of file diff --git a/packages/cli/compile.command.js b/packages/cli/compile.command.js index ab6d5bd..1307129 100644 --- a/packages/cli/compile.command.js +++ b/packages/cli/compile.command.js @@ -11,11 +11,11 @@ * - languages * translates * - en.json - * - cn.json + * - zh.json * - ... * idMap.js // id映射列表 * settings.json // 配置文件 - * cn.js // 中文语言包 + * zh.js // 中文语言包 * en.js // 英文语言包 * [lang].js // 其他语言包 * @@ -25,7 +25,7 @@ const glob = require("glob") const createLogger = require("logsets") const path = require("path") -const { findModuleType,getCurrentPackageJson,installVoerkai18nRuntime,isInstallDependent} = require("@voerkai18n/utils") +const { findModuleType,getCurrentPackageJson,installVoerkai18nRuntime,isInstallDependent,updateVoerkai18nRuntime} = require("@voerkai18n/utils") const { t } = require("./i18nProxy") const fs = require("fs-extra") const logger = createLogger() @@ -126,10 +126,11 @@ module.exports =async function compile(langFolder,opts={}){ logger.log(t(" - 运行时: {}"),"runtime.js") }else{//如果不嵌入则需要安装运行时依赖 if(!isInstallDependent("@voerkai18n/runtime")){ - installVoerkai18nRuntime(langFolder,moduleType) + installVoerkai18nRuntime(langFolder) logger.log(t(" - 安装运行时: {}"),"@voerkai18n/runtime") }else{ - logger.log(t(" - 运行时{}已安装"),"@voerkai18n/runtime") + updateVoerkai18nRuntime(langFolder) + logger.log(t(" - 更新运行时:{}"),"@voerkai18n/runtime") } } const templateContext = { diff --git a/packages/cli/extract.command.js b/packages/cli/extract.command.js index e9204bc..95f4ef6 100644 --- a/packages/cli/extract.command.js +++ b/packages/cli/extract.command.js @@ -1,4 +1,5 @@ -const { findModuleType,t } = require("./utils") +const { findModuleType } = require("@voerkai18n/utils") +const { t } = require("./i18nProxy") const path = require("path") const fs = require("fs") const gulp = require("gulp") diff --git a/packages/cli/extract.plugin.js b/packages/cli/extract.plugin.js index 7f6e92a..4374739 100644 --- a/packages/cli/extract.plugin.js +++ b/packages/cli/extract.plugin.js @@ -96,7 +96,7 @@ function inNamespace(filePath,nsPath){ * @param {*} content * @param {*} file * @param {*} options - * @returns {namespace:{text:{cn:"",en:"",...,$file:""},text:{cn:"",en:"",...,$file:""}} + * @returns {namespace:{text:{zh:"",en:"",...,$file:""},text:{zh:"",en:"",...,$file:""}} */ function extractTranslateTextUseRegexp(content,namespace,extractor,file,options){ @@ -179,7 +179,7 @@ function getFileTypeExtractors(filetype,extractor){ } /** * 找出要翻译的文本列表 {namespace:[text,text],...} - * {namespace:{text:{cn:"",en:"",$source:""},...} + * {namespace:{text:{zh:"",en:"",$source:""},...} * @param {*} content * @param {*} extractor * @returns @@ -219,7 +219,7 @@ function getTranslateTexts(content,file,options){ const defaultExtractLanguages = [ {name:'en',title:"英文"}, - {name:'cn',title:"中文",default:true}, + {name:'zh',title:"中文",default:true}, {name:'de',title:"德语"}, {name:'fr',title:"法语"}, {name:'es',title:"西班牙语"}, @@ -231,8 +231,8 @@ function normalizeLanguageOptions(options){ options = Object.assign({ debug : true, // 输出调试信息,控制台输出相关的信息 languages :defaultExtractLanguages, // 默认要支持的语言 - defaultLanguage: "cn", // 默认语言:指的是在源代码中的原始文本语言 - activeLanguage : "cn", // 当前激活语言:指的是当前启用的语言,比如在源码中使用中文,在默认激活的是英文 + defaultLanguage: "zh", // 默认语言:指的是在源代码中的原始文本语言 + activeLanguage : "zh", // 当前激活语言:指的是当前启用的语言,比如在源码中使用中文,在默认激活的是英文 extractor : { // 匹配翻译函数并提取内容的正则表达式 "*" : DefaultTranslateExtractor, "html,vue,jsx" : DefaultHtmlAttrExtractor @@ -258,7 +258,7 @@ function normalizeLanguageOptions(options){ }else{ options.output = Object.assign({},{updateMode: 'sync',path:null},options.output) } - // 语言配置 languages = [{name:"en",title:"英文"},{name:"cn",title:"中文",active:true,default:true}] + // 语言配置 languages = [{name:"en",title:"英文"},{name:"zh",title:"中文",active:true,default:true}] if(!Array.isArray(options.languages)){ throw new TypeError("options.languages must be an array") }else{ @@ -368,7 +368,7 @@ function updateLanguageFile(newTexts,toLangFile,options){ } Object.entries(newTexts).forEach(([text,sourceLangs])=>{ if(text in oldTexts){ // 合并 - let targetLangs = oldTexts[text] //{cn:'',en:''} + let targetLangs = oldTexts[text] //{zh:'',en:''} Object.entries(sourceLangs).forEach(([langName,sourceText])=>{ if(langName.startsWith("$")) return // 以$开头的为保留字段,不是翻译内容 const langExists = langName in targetLangs diff --git a/packages/cli/index.js b/packages/cli/index.js index 3ddb5ee..7a8e302 100644 --- a/packages/cli/index.js +++ b/packages/cli/index.js @@ -1,13 +1,30 @@ const { Command } = require('commander'); const createLogger = require("logsets") +const bannerPluin = require("logsets/plugins/banner") + const path = require("path") const fs = require("fs-extra") const logger = createLogger() -const { i18nScope ,t } = require("./i18nScope") -const { getProjectRootFolder, getProjectSourceFolder } = require("@voerkai18n/utils") +const { i18nScope ,t } = require("./i18nProxy") +const { getProjectRootFolder, getProjectSourceFolder } = require("@voerkai18n/utils"); +const { translate } = require('../runtime/dist/index.cjs'); +logger.use(bannerPluin) const program = new Command(); +program + .name("voerkai18n") + .option("-v, --version", "当前版本号") + .helpOption('-h, --help', '显示帮助') + .action((options) => { + const banner = logger.banner() + banner.add("VoerkaI18n CLI") + banner.add("VoerkaI18n command line interactive tools",{style:"darkGray"}) + banner.add() + banner.add("版本号:",`${require("./package.json").version}`,{style:["","yellow"]}) + banner.render() + }) + program .command('init') @@ -15,12 +32,12 @@ program .description(t('初始化项目国际化配置')) .option('-D, --debug', t('输出调试信息')) .option('-r, --reset', t('重新生成当前项目的语言配置')) - .option('-lngs, --languages ', t('支持的语言列表'), ['cn','en']) - .option('-d, --defaultLanguage ', t('默认语言'), 'cn') + .option('-lngs, --languages ', t('支持的语言列表'), ['zh','en']) + .option('-d, --defaultLanguage ', t('默认语言'), 'zh') // .option('-i, --installRuntime', t('自动安装默认语言'),true) - .option('-a, --activeLanguage ', t('激活语言'), 'cn') + .option('-a, --activeLanguage ', t('激活语言'), 'zh') .hook("preAction",async function(location){ - const lang= process.env.LANGUAGE || "cn" + const lang= process.env.LANGUAGE || "zh" await i18nScope.change(lang) }) .action((location,options) => { @@ -39,16 +56,16 @@ program .command('extract') .description(t('扫描并提取所有待翻译的字符串到文件夹中')) .option('-D, --debug', t('输出调试信息')) - .option('-lngs, --languages ', t('支持的语言'), ['cn','en']) - .option('-d, --defaultLanguage', t('默认语言'), 'cn') - .option('-a, --activeLanguage', t('激活语言'), 'cn') + .option('-lngs, --languages ', t('支持的语言'), ['zh','en']) + .option('-d, --defaultLanguage', t('默认语言'), 'zh') + .option('-a, --activeLanguage', t('激活语言'), 'zh') .option('-ns, --namespaces', t('翻译名称空间')) .option('-e, --exclude ', t('排除要扫描的文件夹,多个用逗号分隔')) .option('-u, --updateMode', t('本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并'), 'sync') .option('-f, --filetypes', t('要扫描的文件类型'), 'js,vue,html,jsx,ts,mjs,cjs') .argument('[location]', t('工程项目所在目录'),"./") .hook("preAction",async function(location){ - const lang= process.env.LANGUAGE || "cn" + const lang= process.env.LANGUAGE || "zh" await i18nScope.change(lang) }) .action(async (location,options) => { @@ -59,7 +76,7 @@ program logger.log(t("工程目录:{}"),location) const langSettingsFile = path.join(location,"languages","settings.json") if(fs.existsSync(langSettingsFile)){ - logger.log(t("语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本","./languages/settings.json")) + logger.log(t("语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本"),"./languages/settings.json") let lngOptions = fs.readJSONSync(langSettingsFile) options.languages = lngOptions.languages options.defaultLanguage = lngOptions.defaultLanguage @@ -74,12 +91,12 @@ program program .command('compile') .description(t('编译指定项目的语言包')) - .option('-d, --debug', t('输出调试信息')) + .option('-D, --debug', t('输出调试信息')) .option('--no-inline-runtime', t('不嵌入运行时源码')) .option('-m, --moduleType [types]', t('输出模块类型,取值auto,esm,cjs'), 'esm') .argument('[location]', t('工程项目所在目录'),"./") .hook("preAction",async function(location){ - const lang= process.env.LANGUAGE || "cn" + const lang= process.env.LANGUAGE || "zh" await i18nScope.change(lang) }) .action(async (location,options) => { @@ -93,6 +110,29 @@ program compile(langFolder,options) }); +program + .command('translate') + .argument('[location]', t('工程项目所在目录')) + .description(t('调用在线翻译服务商的API翻译译指定项目的语言包,如使用百度云翻译服务')) + .option('--no-backup', t('备份原始文件')) + .option('--mode', t('翻译模式,取值auto=仅翻译未翻译的,full=全部翻译'), 'auto') + .option('-p, --provider ', t('在线翻译服务提供者名称或翻译脚本文件'), 'baidu') + .option('-m, --max-package-size ', t('将多个文本合并提交的最大包字节数'), 200) + .option('--appkey [key]', t('API密钥')) + .option('--appid [id]', t('API ID')) + .option('-q, --qps ', t('翻译速度限制,即每秒可调用的API次数'), 1) + .hook("preAction",async function(location){ + const lang= process.env.LANGUAGE || "zh" + await i18nScope.change(lang) + }) + .action((location,options) => { + location = getProjectSourceFolder(location) + const translate = require("./translate.command") + translate(location,options) + }); + + + program.parseAsync(process.argv); diff --git a/packages/cli/init.command.js b/packages/cli/init.command.js index 0fa5b27..242495a 100644 --- a/packages/cli/init.command.js +++ b/packages/cli/init.command.js @@ -12,7 +12,34 @@ const { findModuleType } = require("@voerkai18n/utils") const createLogger = require("logsets") const logger = createLogger() -module.exports = function(srcPath,{debug = true,languages=["cn","en"],defaultLanguage="cn",activeLanguage="cn",reset=false,installRuntime=true}={}){ +function getLanguageList(langs,defaultLanguage){ + try{ + const available_languages = require("./available_languages") + if(defaultLanguage in available_languages){ + return langs.map(lng=>{ + const langIndex = available_languages[defaultLanguage].findIndex(l=>l.name===lng) + if(langIndex > -1 ){ + return { + name:lng, + title:available_languages[defaultLanguage][langIndex].title + } + }else{ + return { + name:lng, + title:lng + } + } + }) + }else{ + return langs.map(lng=>({name:lng,title:lng})) + } + }catch(e){ + return langs.map(lng=>({name:lng,title:lng})) + } +} + + +module.exports = function(srcPath,{debug = true,languages=["zh","en"],defaultLanguage="zh",activeLanguage="zh",reset=false,installRuntime=true}={}){ // 语言文件夹名称 const langPath = "languages" // 查找当前项目的语言包类型路径 @@ -29,7 +56,7 @@ module.exports = function(srcPath,{debug = true,languages=["cn","en"],defaultLan return } const settings = { - languages:languages.map(lng=>({name:lng,title:lng})), + languages:getLanguageList(languages,defaultLanguage), defaultLanguage, activeLanguage, namespaces:{} diff --git a/packages/cli/languages/cn.js b/packages/cli/languages/de.js similarity index 72% rename from packages/cli/languages/cn.js rename to packages/cli/languages/de.js index e5c50af..3fb74ad 100644 --- a/packages/cli/languages/cn.js +++ b/packages/cli/languages/de.js @@ -1,4 +1,4 @@ -export default { +module.exports = { "1": "支持的语言\\t: {}", "2": "默认语言\\t: {}", "3": "激活语言\\t: {}", @@ -40,11 +40,19 @@ export default { "39": " - 语言包文件: {}", "40": " - idMap文件: {}", "41": " - 格式化器:{}", - "42": "Now is { value | date | bjTime }", - "43": " - 共合成{}条文本", - "44": " - 运行时: {}", - "45": "自动安装默认语言", - "46": "不嵌入运行时源码", - "47": " - 安装运行时: {}", - "48": " - 运行时{}已安装" + "42": " - 共合成{}条文本", + "43": " - 运行时: {}", + "44": "自动安装默认语言", + "45": "不嵌入运行时源码", + "46": " - 安装运行时: {}", + "47": " - 更新运行时:{}", + "48": "调用在线翻译服务商的API翻译译指定项目的语言包,如使用百度云翻译服务", + "49": "API密钥", + "50": "API ID", + "51": "翻译速度限制,即每秒可调用的API次数", + "52": "在线翻译服务提供者名称或翻译脚本文件", + "53": "将多个文本合并提交的最大包字节数", + "54": "正在翻译文件:{}", + "55": "需要指定翻译脚本或者appkey和appid", + "56": " - 翻译 -> {}" } \ No newline at end of file diff --git a/packages/cli/languages/en.js b/packages/cli/languages/en.js index 11ae455..083d00e 100644 --- a/packages/cli/languages/en.js +++ b/packages/cli/languages/en.js @@ -1,4 +1,4 @@ -export default { +module.exports = { "1": "Supported languages\\t: {}", "2": "Default language\\t: {}", "3": "Active language\\t\\t: {}", @@ -40,11 +40,19 @@ export default { "39": " - Language file: {}", "40": " - idMap file: {}", "41": " - Formatters: {}", - "42": "Now is { value | date | bjTime }", - "43": " - Total{} messages", - "44": " - Runtime: {}", - "45": "Auto install default language", - "46": "Not inline runtime source", - "47": " - Install runtime: {}", - "48": " - Runtime{} is installed" + "42": " - Total{} messages", + "43": " - Runtime: {}", + "44": "Auto install default language", + "45": "Not inline runtime source", + "46": " - Install runtime: {}", + "47": " - Update runtime:{}", + "48": "Call the API translation language package of the online translation service provider, eg:baidu translation service", + "49": "API密钥", + "50": "API ID", + "51": "Translation speed limit. API calls per second", + "52": "在线翻译服务提供者名称或翻译脚本文件", + "53": "将多个文本合并提交的最大包字节数", + "54": "正在翻译文件:{}", + "55": "需要指定翻译脚本或者appkey和appid", + "56": " - 翻译 -> {}" } \ No newline at end of file diff --git a/packages/cli/languages/formatters.js b/packages/cli/languages/formatters.js index ef6c3b1..ec81ae7 100644 --- a/packages/cli/languages/formatters.js +++ b/packages/cli/languages/formatters.js @@ -10,7 +10,7 @@ $types:{...}, // 只作用于特定数据类型的默认格式化器 .... // 全局格式化器 }, - cn:{ + zh:{ // 只作用于特定数据类型的格式化器 $types:{ Date:(value)=>dayjs(value).format("YYYY年MM月DD日 HH:mm:ss"), @@ -46,7 +46,7 @@ * */ -export default { +module.exports = { // 在所有语言下生效的格式化器 "*":{ //[格式化名称]:(value)=>{...}, @@ -56,7 +56,7 @@ export default { $types:{ }, - cn:{ + zh:{ $types:{ // 所有类型的默认格式化器 // "*":{ diff --git a/packages/cli/languages/idMap.js b/packages/cli/languages/idMap.js index 69a4e66..dd07250 100644 --- a/packages/cli/languages/idMap.js +++ b/packages/cli/languages/idMap.js @@ -1,4 +1,4 @@ -export default { +module.exports = { "支持的语言\\t: {}": 1, "默认语言\\t: {}": 2, "激活语言\\t: {}": 3, @@ -40,11 +40,19 @@ export default { " - 语言包文件: {}": 39, " - idMap文件: {}": 40, " - 格式化器:{}": 41, - "Now is { value | date | bjTime }": 42, - " - 共合成{}条文本": 43, - " - 运行时: {}": 44, - "自动安装默认语言": 45, - "不嵌入运行时源码": 46, - " - 安装运行时: {}": 47, - " - 运行时{}已安装": 48 + " - 共合成{}条文本": 42, + " - 运行时: {}": 43, + "自动安装默认语言": 44, + "不嵌入运行时源码": 45, + " - 安装运行时: {}": 46, + " - 更新运行时:{}": 47, + "调用在线翻译服务商的API翻译译指定项目的语言包,如使用百度云翻译服务": 48, + "API密钥": 49, + "API ID": 50, + "翻译速度限制,即每秒可调用的API次数": 51, + "在线翻译服务提供者名称或翻译脚本文件": 52, + "将多个文本合并提交的最大包字节数": 53, + "正在翻译文件:{}": 54, + "需要指定翻译脚本或者appkey和appid": 55, + " - 翻译 -> {}": 56 } \ No newline at end of file diff --git a/packages/cli/languages/index.js b/packages/cli/languages/index.js index 79799bd..e5f478b 100644 --- a/packages/cli/languages/index.js +++ b/packages/cli/languages/index.js @@ -1,9 +1,9 @@ -import messageIds from "./idMap.js" -import { translate,i18nScope } from "./runtime" +const messageIds = require("./idMap") +const { translate,i18nScope } = require("./runtime.js") -import formatters from "./formatters.js" -import defaultMessages from "./cn.js" +const formatters = require("./formatters.js") +const defaultMessages = require("./zh.js") const activeMessages = defaultMessages @@ -11,16 +11,20 @@ const activeMessages = defaultMessages const scopeSettings = { "languages": [ { - "name": "cn", - "title": "cn" + "name": "zh", + "title": "zh" }, { "name": "en", "title": "en" + }, + { + "name": "de", + "title": "de" } ], - "defaultLanguage": "cn", - "activeLanguage": "cn", + "defaultLanguage": "zh", + "activeLanguage": "zh", "namespaces": {} } @@ -33,14 +37,13 @@ const scope = new i18nScope({ idMap:messageIds, // 消息id映射列表 formatters, // 当前作用域的格式化函数列表 loaders:{ - "en" : ()=>import("./en.js") + "en" : ()=>import("./en.js"), + "de" : ()=>import("./de.js") } }) // 翻译函数 -const t = translate.bind(scope) +const scopedTtranslate = translate.bind(scope) -export { - t, - i18nScope:scope -} +module.exports.t = scopedTtranslate +module.exports.i18nScope = scope diff --git a/packages/cli/languages/runtime.js b/packages/cli/languages/runtime.js index c0ef5fb..8e60ccf 100644 --- a/packages/cli/languages/runtime.js +++ b/packages/cli/languages/runtime.js @@ -1,3 +1,93 @@ +'use strict'; + +/** + * 判断是否是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 +}; + /** * * 简单的事件触发器 @@ -36,7 +126,7 @@ var scope = class i18nScope { // 每个作用域都有一个唯一的id this._id = options.id || (new Date().getTime().toString()+parseInt(Math.random()*1000)); this._languages = options.languages; // 当前作用域的语言列表 - this._defaultLanguage = options.defaultLanguage || "cn"; // 默认语言名称 + this._defaultLanguage = options.defaultLanguage || "zh"; // 默认语言名称 this._activeLanguage = options.activeLanguage; // 当前语言名称 this._default = options.default; // 默认语言包 this._messages = options.messages; // 当前语言包 @@ -127,7 +217,7 @@ var scope = class i18nScope { const loader = this.loaders[newLanguage]; if(typeof(loader) === "function"){ try{ - this._messages = (await loader()).default; + this._messages = (await loader()).default; this._activeLanguage = newLanguage; }catch(e){ console.warn(`Error while loading language <${newLanguage}> on i18nScope(${this.id}): ${e.message}`); @@ -183,7 +273,7 @@ var scope = class i18nScope { return value } -var formatters$1 = { +var formatters = { "*":{ $types:{ Date:(value)=>value.toLocaleString() @@ -193,7 +283,7 @@ var formatters$1 = { date: (value)=> value.toLocaleDateString(), dict, //字典格式化器 }, - cn:{ + zh:{ $types:{ Date:(value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日 ${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒` }, @@ -210,9 +300,11 @@ var formatters$1 = { } }; +const { getDataTypeName,isNumber,isPlainObject,deepMerge } = utils; const EventEmitter = eventemitter; const i18nScope = scope; -let formatters = formatters$1; +let inlineFormatters = formatters; // 内置格式化器 + // 用来提取字符里面的插值变量参数 , 支持管道符 { var | formatter | formatter } @@ -237,79 +329,7 @@ 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"]; - -/** - * 获取指定变量类型名称 - * getDataTypeName(1) == Number - * getDataTypeName("") == String - * getDataTypeName(null) == Null - * getDataTypeName(undefined) == Undefined - * getDataTypeName(new Date()) == Date - * getDataTypeName(new Error()) == Error - * - * @param {*} v - * @returns - */ - function getDataTypeName(v){ - if (v === null) return 'Null' - if (v === undefined) return 'Undefined' - if(typeof(v)==="function") return "Function" - return v.constructor && v.constructor.name; -}function isPlainObject(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(value){ - return !isNaN(parseInt(value)) -} - - - -/** - * 简单进行对象合并 - * - * options={ - * array:0 , // 数组合并策略,0-替换,1-合并,2-去重合并 - * object:0, // 对象合并策略,0-替换,1-合并,2-去重合并 - * } - * - * @param {*} toObj - * @param {*} formObj - * @returns 合并后的对象 - */ -function deepMerge(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(results[key],value,options); - } - }else { - results[key] = value; - } - }else { - results[key] = value; - } - }); - return results -} - + /** 通过正则表达式对原始文本内容进行解析匹配后得到的 @@ -452,7 +472,7 @@ function resetScopeCache(scope,activeLanguage=null){ "*":{ $types:{...} // 在所有语言下只作用于特定数据类型的格式化器 }, // 在所有语言下生效的格式化器 - cn:{ + zh:{ $types:{ [数据类型]:(value)=>{...}, }, @@ -653,13 +673,13 @@ function replaceInterpolatedVars(template,...args) { // 默认语言配置 const defaultLanguageSettings = { - defaultLanguage: "cn", - activeLanguage: "cn", + defaultLanguage: "zh", + activeLanguage: "zh", languages:[ - {name:"cn",title:"中文",default:true}, + {name:"zh",title:"中文",default:true}, {name:"en",title:"英文"} ], - formatters + formatters:inlineFormatters }; function isMessageId(content){ @@ -829,11 +849,11 @@ function translate(message) { // 当前激活语言 get activeLanguage(){ return this._settings.activeLanguage} // 默认语言 - get defaultLanguage(){ return this.this._settings.defaultLanguage} + get defaultLanguage(){ return this._settings.defaultLanguage} // 支持的语言列表 get languages(){ return this._settings.languages} - // 全局格式化器 - get formatters(){ return formatters } + // 内置格式化器 + get formatters(){ return inlineFormatters } /** * 切换语言 */ @@ -889,7 +909,7 @@ function translate(message) { * 格式化器是一个简单的同步函数value=>{...},用来对输入进行格式化后返回结果 * * registerFormatters(name,value=>{...}) // 适用于所有语言 - * registerFormatters(name,value=>{...},{langauge:"cn"}) // 适用于cn语言 + * registerFormatters(name,value=>{...},{langauge:"zh"}) // 适用于cn语言 * registerFormatters(name,value=>{...},{langauge:"en"}) // 适用于en语言 * @param {*} formatters @@ -919,4 +939,4 @@ var runtime ={ isPlainObject }; -export { runtime as default }; +module.exports = runtime; diff --git a/packages/cli/languages/settings.json b/packages/cli/languages/settings.json index 4082e51..00da4a9 100644 --- a/packages/cli/languages/settings.json +++ b/packages/cli/languages/settings.json @@ -1,15 +1,19 @@ { "languages": [ { - "name": "cn", - "title": "cn" + "name": "zh", + "title": "zh" }, { "name": "en", "title": "en" + }, + { + "name": "de", + "title": "de" } ], - "defaultLanguage": "cn", - "activeLanguage": "cn", + "defaultLanguage": "zh", + "activeLanguage": "zh", "namespaces": {} } \ No newline at end of file diff --git a/packages/cli/languages/translates/default.json b/packages/cli/languages/translates/default.json index c1f0a17..e5e1994 100644 --- a/packages/cli/languages/translates/default.json +++ b/packages/cli/languages/translates/default.json @@ -4,291 +4,396 @@ "$file": [ "compile.command.js", "extract.plugin.js" - ] + ], + "de": "支持的语言\\t: {}" }, "默认语言\\t: {}": { "en": "Default language\\t: {}", "$file": [ "compile.command.js", "extract.plugin.js" - ] + ], + "de": "默认语言\\t: {}" }, "激活语言\\t: {}": { "en": "Active language\\t\\t: {}", "$file": [ "compile.command.js", "extract.plugin.js" - ] + ], + "de": "激活语言\\t: {}" }, "名称空间\\t: {}": { "en": "Namespaces\\t\\t: {}", "$file": [ "compile.command.js", "extract.plugin.js" - ] + ], + "de": "名称空间\\t: {}" }, " - 更新格式化器:{}": { "en": " - Update formatters:{}", "$file": [ "compile.command.js" - ] + ], + "de": " - 更新格式化器:{}" }, " - 访问入口文件: {}": { "en": " - Entry of language: {}", "$file": [ "compile.command.js" - ] + ], + "de": " - 访问入口文件: {}" }, "加载多语言配置文件<{}>失败: {} ": { "en": "Failed to load multilingual configuration file <{}>: {}", "$file": [ "compile.command.js" - ] + ], + "de": "加载多语言配置文件<{}>失败: {} " }, "目标文件夹<{}>不存在": { "en": "The destination folder < {} > does not exist", "$file": [ "extract.command.js" - ] + ], + "de": "目标文件夹<{}>不存在" }, "扫描提取范围:": { "en": "Scan for:", "$file": [ "extract.command.js" - ] + ], + "de": "扫描提取范围:" }, "工程项目所在目录": { "en": "Project directory", "$file": [ "index.js" - ] + ], + "de": "工程项目所在目录" }, "初始化项目国际化配置": { "en": "Initialize project i18n configuration", "$file": [ "index.js" - ] + ], + "de": "初始化项目国际化配置" }, "输出调试信息": { "en": "Output debug information", "$file": [ "index.js" - ] + ], + "de": "输出调试信息" }, "重新生成当前项目的语言配置": { "en": "Regenerate the language configuration of the current project", "$file": [ "index.js" - ] + ], + "de": "重新生成当前项目的语言配置" }, "支持的语言列表": { "en": "Supported languages", "$file": [ "index.js" - ] + ], + "de": "支持的语言列表" }, "工程目录:{}": { "en": "Folder of project:{}", "$file": [ "index.js" - ] + ], + "de": "工程目录:{}" }, "扫描并提取所有待翻译的字符串到文件夹中": { "en": "Scan and extract all strings to be translated into the folder", "$file": [ "index.js" - ] + ], + "de": "扫描并提取所有待翻译的字符串到文件夹中" }, "支持的语言": { "en": "Supported languages", "$file": [ "index.js" - ] + ], + "de": "支持的语言" }, "默认语言": { "en": "Default language", "$file": [ "index.js" - ] + ], + "de": "默认语言" }, "激活语言": { "en": "Active language", "$file": [ "index.js" - ] + ], + "de": "激活语言" }, "翻译名称空间": { "en": "Namespaces", "$file": [ "index.js" - ] + ], + "de": "翻译名称空间" }, "排除要扫描的文件夹,多个用逗号分隔": { "en": "Exclude folders to scan, multiple separated by commas", "$file": [ "index.js" - ] + ], + "de": "排除要扫描的文件夹,多个用逗号分隔" }, "本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并": { "en": " strategy of messages merge,with value of sync(default),overwrite,merge", "$file": [ "index.js" - ] + ], + "de": "本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并" }, "要扫描的文件类型": { "en": "Type of file to scan", "$file": [ "index.js" - ] + ], + "de": "要扫描的文件类型" }, "语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本": { "en": "The language configuration file <{}> already exists. It will be used preferentially to extract messages", "$file": [ "index.js" - ] + ], + "de": "语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本" }, "编译指定项目的语言包": { "en": "Compiles the language messages for project", "$file": [ "index.js" - ] + ], + "de": "编译指定项目的语言包" }, "输出模块类型,取值auto,esm,cjs": { "en": "Output module type, values: auto, esm, cjs", "$file": [ "index.js" - ] + ], + "de": "输出模块类型,取值auto,esm,cjs" }, "语言包文件夹<{}>不存在": { "en": "The language messages folder <{}> does not exist", "$file": [ "index.js" - ] + ], + "de": "语言包文件夹<{}>不存在" }, "语言配置文件{}文件已存在,跳过创建。\\n使用{}可以重新覆盖创建": { "en": "Language configuration {} file already exists, skipping creation\\n use {} to overwrite the creation", "$file": [ "init.command.js" - ] + ], + "de": "语言配置文件{}文件已存在,跳过创建。\\n使用{}可以重新覆盖创建" }, "生成语言配置文件:{}": { "en": "Generate language configuration: {}", "$file": [ "init.command.js" - ] + ], + "de": "生成语言配置文件:{}" }, "拟支持的语言:{}": { "en": "Languages to be supported:{}", "$file": [ "init.command.js" - ] + ], + "de": "拟支持的语言:{}" }, "初始化成功,下一步:": { "en": "Initialization succeeded, next step:", "$file": [ "init.command.js" - ] + ], + "de": "初始化成功,下一步:" }, " - 编辑{}确定拟支持的语言种类等参数": { "en": " - Edit language parameters in {}", "$file": [ "init.command.js" - ] + ], + "de": " - 编辑{}确定拟支持的语言种类等参数" }, " - 运行<{}>扫描提取要翻译的文本": { "en": " - Run <{}> scan to extract the messages to be translated", "$file": [ "init.command.js" - ] + ], + "de": " - 运行<{}>扫描提取要翻译的文本" }, " - 运行<{}>编译语言包": { "en": " - Run <{}> compile language messages", "$file": [ "init.command.js" - ] + ], + "de": " - 运行<{}>编译语言包" }, "创建语言包文件夹: {}": { "en": "Create folder: {}", "$file": [ "init.command.js" - ] + ], + "de": "创建语言包文件夹: {}" }, "模块类型\\t: {}": { "en": "Type of module\\t\\t: {}", "$file": [ "compile.command.js" - ] + ], + "de": "模块类型\\t: {}" }, "编译结果输出至:{}": { "en": "Compile to:{}", "$file": [ "compile.command.js" - ] + ], + "de": "编译结果输出至:{}" }, "读取语言文件{}失败:{}": { "en": "Error while read language file{}: {}", "$file": [ "compile.command.js" - ] + ], + "de": "读取语言文件{}失败:{}" }, " - 语言包文件: {}": { "en": " - Language file: {}", "$file": [ "compile.command.js" - ] + ], + "de": " - 语言包文件: {}" }, " - idMap文件: {}": { "en": " - idMap file: {}", "$file": [ "compile.command.js" - ] + ], + "de": " - idMap文件: {}" }, " - 格式化器:{}": { "en": " - Formatters: {}", "$file": [ "compile.command.js" - ] - }, - "Now is { value | date | bjTime }": { - "en": "Now is { value | date | bjTime }", - "$file": [ - "templates\\formatters.js" - ] + ], + "de": " - 格式化器:{}" }, " - 共合成{}条文本": { "en": " - Total{} messages", "$file": [ "compile.command.js" - ] + ], + "de": " - 共合成{}条文本" }, " - 运行时: {}": { "en": " - Runtime: {}", "$file": [ "compile.command.js" - ] + ], + "de": " - 运行时: {}" }, "自动安装默认语言": { "en": "Auto install default language", "$file": [ "index.js" - ] + ], + "de": "自动安装默认语言", + "zh": "自动安装默认语言" }, "不嵌入运行时源码": { "en": "Not inline runtime source", "$file": [ "index.js" - ] + ], + "de": "不嵌入运行时源码" }, " - 安装运行时: {}": { "en": " - Install runtime: {}", "$file": [ "compile.command.js" - ] + ], + "de": " - 安装运行时: {}" }, - " - 运行时{}已安装": { - "en": " - Runtime{} is installed", + " - 更新运行时:{}": { + "en": " - Update runtime:{}", "$file": [ "compile.command.js" + ], + "de": " - 更新运行时:{}" + }, + "调用在线翻译服务商的API翻译译指定项目的语言包,如使用百度云翻译服务": { + "en": "Call the API translation language package of the online translation service provider, eg:baidu translation service", + "$file": [ + "index.js" + ], + "de": "调用在线翻译服务商的API翻译译指定项目的语言包,如使用百度云翻译服务" + }, + "API密钥": { + "en": "API密钥", + "$file": [ + "index.js" + ], + "de": "API密钥" + }, + "API ID": { + "en": "API ID", + "$file": [ + "index.js" + ], + "de": "API ID" + }, + "翻译速度限制,即每秒可调用的API次数": { + "en": "Translation speed limit. API calls per second", + "de": "翻译速度限制,即每秒可调用的API次数", + "$file": [ + "index.js" + ] + }, + "在线翻译服务提供者名称或翻译脚本文件": { + "en": "在线翻译服务提供者名称或翻译脚本文件", + "de": "在线翻译服务提供者名称或翻译脚本文件", + "$file": [ + "index.js" + ] + }, + "将多个文本合并提交的最大包字节数": { + "en": "将多个文本合并提交的最大包字节数", + "de": "将多个文本合并提交的最大包字节数", + "$file": [ + "index.js" + ] + }, + "正在翻译文件:{}": { + "en": "正在翻译文件:{}", + "de": "正在翻译文件:{}", + "$file": [ + "translate.command.js" + ] + }, + "需要指定翻译脚本或者appkey和appid": { + "en": "需要指定翻译脚本或者appkey和appid", + "de": "需要指定翻译脚本或者appkey和appid", + "$file": [ + "translate.command.js" + ] + }, + " - 翻译 -> {}": { + "en": " - 翻译 -> {}", + "de": " - 翻译 -> {}", + "$file": [ + "translate.command.js" ] } } \ No newline at end of file diff --git a/packages/cli/languages/zh.js b/packages/cli/languages/zh.js new file mode 100644 index 0000000..3fb74ad --- /dev/null +++ b/packages/cli/languages/zh.js @@ -0,0 +1,58 @@ +module.exports = { + "1": "支持的语言\\t: {}", + "2": "默认语言\\t: {}", + "3": "激活语言\\t: {}", + "4": "名称空间\\t: {}", + "5": " - 更新格式化器:{}", + "6": " - 访问入口文件: {}", + "7": "加载多语言配置文件<{}>失败: {} ", + "8": "目标文件夹<{}>不存在", + "9": "扫描提取范围:", + "10": "工程项目所在目录", + "11": "初始化项目国际化配置", + "12": "输出调试信息", + "13": "重新生成当前项目的语言配置", + "14": "支持的语言列表", + "15": "工程目录:{}", + "16": "扫描并提取所有待翻译的字符串到文件夹中", + "17": "支持的语言", + "18": "默认语言", + "19": "激活语言", + "20": "翻译名称空间", + "21": "排除要扫描的文件夹,多个用逗号分隔", + "22": "本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并", + "23": "要扫描的文件类型", + "24": "语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本", + "25": "编译指定项目的语言包", + "26": "输出模块类型,取值auto,esm,cjs", + "27": "语言包文件夹<{}>不存在", + "28": "语言配置文件{}文件已存在,跳过创建。\\n使用{}可以重新覆盖创建", + "29": "生成语言配置文件:{}", + "30": "拟支持的语言:{}", + "31": "初始化成功,下一步:", + "32": " - 编辑{}确定拟支持的语言种类等参数", + "33": " - 运行<{}>扫描提取要翻译的文本", + "34": " - 运行<{}>编译语言包", + "35": "创建语言包文件夹: {}", + "36": "模块类型\\t: {}", + "37": "编译结果输出至:{}", + "38": "读取语言文件{}失败:{}", + "39": " - 语言包文件: {}", + "40": " - idMap文件: {}", + "41": " - 格式化器:{}", + "42": " - 共合成{}条文本", + "43": " - 运行时: {}", + "44": "自动安装默认语言", + "45": "不嵌入运行时源码", + "46": " - 安装运行时: {}", + "47": " - 更新运行时:{}", + "48": "调用在线翻译服务商的API翻译译指定项目的语言包,如使用百度云翻译服务", + "49": "API密钥", + "50": "API ID", + "51": "翻译速度限制,即每秒可调用的API次数", + "52": "在线翻译服务提供者名称或翻译脚本文件", + "53": "将多个文本合并提交的最大包字节数", + "54": "正在翻译文件:{}", + "55": "需要指定翻译脚本或者appkey和appid", + "56": " - 翻译 -> {}" +} \ No newline at end of file diff --git a/packages/cli/package.json b/packages/cli/package.json index ccad66c..2e57bb5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,46 +1,54 @@ { - "name": "@voerkai18n/cli", - "version": "1.0.15", - "description": "VoerkaI18n command line interactive tools", - "main": "index.js", - "homepage": "https://gitee.com/zhangfisher/voerka-i18n", - "repository": { - "type": "git", - "url": "git+https://gitee.com/zhangfisher/voerka-i18n.git" - }, - "keywords": [ - "i18n", - "language", - "translation", - "internationalize" - ], - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "extract": "node ./index.js extract -d -e babel-plugin-voerkai18n.js,templates/**", - "compile": "node ./index.js compile -d", - "compile:en": "cross-env LANGUAGE=en node ./index.js compile -d", - "release": "npm version patch && pnpm publish --no-git-checks --access public" - }, - "author": "wxzhang", - "license": "MIT", - "bin": { - "voerkai18n": "./index.js" - }, - "dependencies": { - "@babel/cli": "^7.17.6", - "@babel/core": "^7.17.5", - "@voerkai18n/runtime": "workspace:^1.0.8", - "@voerkai18n/utils": "workspace:^1.0.0", - "art-template": "^4.13.2", - "commander": "^9.0.0", - "cross-env": "^7.0.3", - "deepmerge": "^4.2.2", - "fs-extra": "^10.0.1", - "glob": "^7.2.0", - "gulp": "^4.0.2", - "logsets": "^1.0.8", - "shelljs": "^0.8.5", - "through2": "^4.0.2", - "vinyl": "^2.2.1" - } -} + "name": "@voerkai18n/cli", + "version": "1.0.26", + "description": "VoerkaI18n command line interactive tools", + "main": "index.js", + "homepage": "https://gitee.com/zhangfisher/voerka-i18n", + "repository": { + "type": "git", + "url": "git+https://gitee.com/zhangfisher/voerka-i18n.git" + }, + "keywords": [ + "i18n", + "language", + "translation", + "internationalize" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "extract": "node ./index.js extract -D -e templates/** ", + "compile": "node ./index.js compile -m cjs", + "compile:en": "cross-env LANGUAGE=en node ./index.js compile -d", + "build": "node ./index.js compile -m cjs", + "release": "pnpm autopublish" + }, + "author": "wxzhang", + "license": "MIT", + "bin": { + "voerkai18n": "./index.js" + }, + "dependencies": { + "@babel/cli": "^7.17.6", + "@babel/core": "^7.17.5", + "@voerkai18n/runtime": "workspace:^1.0.14", + "@voerkai18n/utils": "workspace:^1.0.6", + "art-template": "^4.13.2", + "axios": "^0.26.1", + "commander": "^9.0.0", + "cross-env": "^7.0.3", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.1", + "glob": "^7.2.0", + "gulp": "^4.0.2", + "logsets": "^1.0.8", + "md5": "^2.3.0", + "qs": "^6.10.3", + "shelljs": "^0.8.5", + "through2": "^4.0.2", + "vinyl": "^2.2.1" + }, + "devDependencies": { + "@voerkai18n/autopublish": "workspace:^1.0.2" + }, + "lastPublish": "2022-04-10T20:14:07+08:00" +} \ No newline at end of file diff --git a/packages/cli/stringify.js b/packages/cli/stringify.js index 6224c0b..29cc2d4 100644 --- a/packages/cli/stringify.js +++ b/packages/cli/stringify.js @@ -12,7 +12,7 @@ * { * "保存{}\\n": "Save{}\n", * } - * 这个转义方式比较不符合我们的预期,更关键的是,在require("cn.js")时, + * 这个转义方式比较不符合我们的预期,更关键的是,在require("zh.js")时, * 得到的是: * { * "保存{}\\n": "Save{}\n", diff --git a/packages/cli/templates/formatters.js b/packages/cli/templates/formatters.js index de2bea1..1793dde 100644 --- a/packages/cli/templates/formatters.js +++ b/packages/cli/templates/formatters.js @@ -10,7 +10,7 @@ $types:{...}, // 只作用于特定数据类型的默认格式化器 .... // 全局格式化器 }, - cn:{ + zh:{ // 只作用于特定数据类型的格式化器 $types:{ Date:(value)=>dayjs(value).format("YYYY年MM月DD日 HH:mm:ss"), diff --git a/packages/cli/translate.command.js b/packages/cli/translate.command.js new file mode 100644 index 0000000..832c0f1 --- /dev/null +++ b/packages/cli/translate.command.js @@ -0,0 +1,193 @@ + +/** + * 将extract插件扫描的文件编译为语言文件 + * + * 编译后的语言文件用于运行环境使用 + * + * 编译原理如下: + * + * + * 编译后会在目标文件夹输出: + * + * - languages + * translates + * - en.json + * - zh.json + * - ... + * idMap.js // id映射列表 + * settings.json // 配置文件 + * zh.js // 中文语言包 + * en.js // 英文语言包 + * [lang].js // 其他语言包 + * + * @param {*} opts + */ + +const createLogger = require("logsets") +const path = require("path") +const { t } = require("./i18nProxy") +const fs = require("fs-extra") +const { glob } = require("glob") +const { default: axios } = require("axios") +const logger = createLogger() +const TaskListPlugin = require("logsets/plugins/tasklist") +const { deepMerge } = require("@voerkai18n/utils") +logger.use(TaskListPlugin) + +const delay = async (t) => new Promise(resolve=>setTimeout(resolve,t)) + +function normalizeTranslateOptions(opts={}) { + let options = Object.assign({ + appkey:null, + appid:null, + backup:true, // 是否备份原始文件 + mode:"auto", // 是否全部翻译,auto=仅仅对未翻译的内容进行翻译,full=全部翻译 + provider:null, // 指定脚本文件来进行翻译 + }, opts) + + return options; +} + +function getTranslateProvider(options={}){ + const { provider } = options; + if(provider==="baidu"){ + return require("./baidu.translate.js")(options) + }else{ + return require(provider)(options) + } +} +/** + * 翻译多条文本 + * @param {*} to + * @param {*} messages + * @param {*} options + * @returns + */ +async function translateMessages(messages={},from,to,options={}){ + let { mode,qps=1 } = options + if(messages.length===0) return; + const provider = getTranslateProvider(options) + await delay(1000/qps) + let translatedMessages =await provider.translate(Object.keys(messages),from,to) + Object.keys(messages).forEach((key,index)=>{ + messages[key][to] = translatedMessages[index] + }) + return messages +} +/** + * 翻译多行文本 + * @param {*} messages + * @param {*} options + * @returns + */ +async function translateMultiLineMessage(messages=[],from,to,options={}){ + if(messages.length===0) return; + const provider = getTranslateProvider(options) + await delay(1000/qps) + let result = await provider.translate(messages,from,to) + return result.join("\n") +} + +/** + * 翻译指定的语言 + * @param {*} messages + * @param {*} from + * @param {*} to + * @param {*} options + * @returns + */ +async function translateLanguage(messages,from,to,options={}){ + const { maxPackageSize,mode } = options; + let result = {} + let lngMessages = {} ,packageSize =0 + for(let [ text,lngs ] of Object.entries(messages)){ + // 如果mode=auto,则当翻译内容已经有变化时,则不再翻译 + if(mode=="auto" && typeof(lngs[to])==="string" && (lngs[to]!=text && lngs[to].trim()!="")){ + if(!(text in result)) result[text] = {} + result[text][to] =lngs[to] + continue; + } + // 由于百度翻译按\n来分行翻译,如果有\n则会出现多行翻译的情况,因此,如果有\n则就不将多条文件合并翻译 + if(text.includes("\n")){ + if(!(text in result)) result[text] = {} + result[text][to] = await translateMultiLineMessage(text.split("\n"),from,to,options) + }else{ + lngMessages[text]={[to]:''} + packageSize+=text.length + // 多个信息合并进行翻译,减少请求次数 + if(packageSize>=options.maxPackageSize){ + await translateMessages(lngMessages,from,to,options) + result = deepMerge(result,lngMessages) + packageSize=0 + lngMessages={} + } + } + } + // 对剩余的信息进行翻译 + if(Object.keys(lngMessages).length > 0){ + requestCount++ + await translateMessages(lngMessages,from,to,options) + result = deepMerge(result,lngMessages) + } + + return result + +} + +/** + * 翻译指定的文件 + * @param {*} file + * @param {*} langSettings + * @param {*} options + */ +async function translateMessageFile(file,langSettings,options={}){ + let context = this + logger.log(t("正在翻译文件:{}"),path.basename(file)) + let messages = fs.readJSONSync(file); + // texts = {text:{zh:"",en:"",...,jp:""}} + let results = {} + const tasks = logger.tasklist() + for(let lng of langSettings.languages){ + if(lng.name === langSettings.defaultLanguage) continue + try{ + tasks.add(t(" - 翻译 -> {}",lng.name)) + results = deepMerge(results,await translateLanguage(messages,langSettings.defaultLanguage,lng.name,options)) + tasks.complete() + }catch(e){ + tasks.error(e.message || e) + } + } + results = deepMerge(messages,results) + // 写入原始文件 + fs.writeFileSync(file,JSON.stringify(results,null,4)) +} + + + +module.exports =async function translate(srcFolder,opts={}){ + const options = normalizeTranslateOptions(opts); + let { backup, appkey,appid,provider="baidu",qps=1 } = options; + if(!provider && !(appkey && appid) ) throw new Error(t("需要指定翻译脚本或者appkey和appid")) + + const langFolder = path.join(srcFolder,"languages"); + const files = glob.sync(path.join(langFolder,"translates/*.json")) + const langSettings = fs.readJSONSync(path.join(langFolder,"settings.json")) + // 保存一些调用信息,用来在翻译完成后,显示 + let context = { + provider, + files:[] // 翻译的文件{filename:<翻译>,messages:<数量>,calls:<调用>,timeConsuming:<耗时>} + } + + // 枚举所有需要翻译的文件 + for(let file of files){ + // 备份原始文件 + const backupFile = path.join(langFolder,"translates","backup",path.basename(file)) + if(backup && !fs.existsSync(backupFile)){ + if(!fs.existsSync(path.dirname(backupFile))) fs.mkdirSync(path.dirname(backupFile)) + fs.copyFileSync(file,backupFile) + } + // 翻译文件 + let results = await translateMessageFile.call(context,file,langSettings,options) + + } +} \ No newline at end of file diff --git a/packages/formatters/package.json b/packages/formatters/package.json index ba1f6c8..cff2fab 100644 --- a/packages/formatters/package.json +++ b/packages/formatters/package.json @@ -1,20 +1,23 @@ { - "name": "@voerkai18n/formatters", - "version": "1.0.0", - "description": "", - "main": "currency.formatters.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "release": "npm version patch && pnpm publish --no-git-checks --access public" - }, - "exports":{ - - }, - "author": "wxzhang", - "license": "MIT", - "devDependencies": { - "deepmerge": "^4.2.2", - "gulp": "^4.0.2", - "vinyl": "^2.2.1" - } -} + "name": "@voerkai18n/formatters", + "version": "1.0.5", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "release": "pnpm autopublish" + }, + "exports": { + "currency": "./currency.formatters.js", + "datetime": "./datetime.formatters.js" + }, + "author": "wxzhang", + "license": "MIT", + "dependencies": { + "dayjs": "^1.11.0" + }, + "devDependencies": { + "@voerkai18n/autopublish": "workspace:^1.0.2" + }, + "lastPublish": "2022-04-06T20:54:23+08:00" +} \ No newline at end of file diff --git a/packages/runtime/dist/index.cjs b/packages/runtime/dist/index.cjs deleted file mode 100644 index 9caf2e8..0000000 --- a/packages/runtime/dist/index.cjs +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";var e=require("@babel/runtime-corejs3/core-js-stable/weak-map"),t=require("@babel/runtime-corejs3/core-js-stable/instance/reduce"),r=require("@babel/runtime-corejs3/core-js-stable/object/keys"),a=require("@babel/runtime-corejs3/core-js-stable/object/create"),n=require("@babel/runtime-corejs3/core-js-stable/symbol/replace"),l=require("@babel/runtime-corejs3/core-js-stable/array/from"),u=require("@babel/runtime-corejs3/core-js-stable/symbol"),s=require("@babel/runtime-corejs3/core-js/get-iterator-method"),i=require("@babel/runtime-corejs3/core-js-stable/reflect/construct");require("core-js/modules/es.regexp.constructor.js"),require("core-js/modules/es.regexp.dot-all.js"),require("core-js/modules/es.regexp.sticky.js"),require("core-js/modules/es.regexp.test.js"),require("core-js/modules/es.reflect.to-string-tag.js");var c=require("@babel/runtime-corejs3/helpers/asyncToGenerator"),o=require("@babel/runtime-corejs3/helpers/classCallCheck"),f=require("@babel/runtime-corejs3/helpers/createClass"),d=require("@babel/runtime-corejs3/helpers/assertThisInitialized"),g=require("@babel/runtime-corejs3/helpers/possibleConstructorReturn"),h=require("@babel/runtime-corejs3/helpers/getPrototypeOf"),b=require("@babel/runtime-corejs3/helpers/typeof"),p=require("@babel/runtime-corejs3/helpers/toConsumableArray"),m=require("@babel/runtime-corejs3/helpers/slicedToArray"),v=require("@babel/runtime-corejs3/helpers/taggedTemplateLiteral"),y=require("@babel/runtime-corejs3/helpers/inherits"),j=require("@babel/runtime-corejs3/helpers/setPrototypeOf"),k=require("@babel/runtime-corejs3/regenerator");require("core-js/modules/es.regexp.exec.js"),require("core-js/modules/es.string.split.js"),require("core-js/modules/es.string.substr.js"),require("core-js/modules/es.function.name.js"),require("core-js/modules/es.error.to-string.js"),require("core-js/modules/es.date.to-string.js"),require("core-js/modules/es.object.to-string.js"),require("core-js/modules/es.regexp.to-string.js"),require("core-js/modules/esnext.array.last-index.js"),require("core-js/modules/es.string.replace.js"),require("core-js/modules/es.error.cause.js"),require("core-js/modules/es.array.iterator.js"),require("core-js/modules/es.promise.js"),require("core-js/modules/es.promise.all-settled.js"),require("core-js/modules/es.string.iterator.js"),require("core-js/modules/web.dom-collections.iterator.js");var q=require("@babel/runtime-corejs3/core-js-stable/string/raw"),w=require("@babel/runtime-corejs3/core-js-stable/instance/includes"),_=require("@babel/runtime-corejs3/core-js-stable/instance/map"),x=require("@babel/runtime-corejs3/core-js-stable/instance/trim"),L=require("@babel/runtime-corejs3/core-js-stable/instance/index-of"),S=require("@babel/runtime-corejs3/core-js-stable/instance/last-index-of"),$=require("@babel/runtime-corejs3/core-js-stable/parse-int"),M=require("@babel/runtime-corejs3/core-js-stable/instance/starts-with"),A=require("@babel/runtime-corejs3/core-js-stable/instance/ends-with"),F=require("@babel/runtime-corejs3/core-js-stable/instance/find-index"),T=require("@babel/runtime-corejs3/core-js-stable/object/assign"),E=require("@babel/runtime-corejs3/core-js/instance/replace-all"),I=require("@babel/runtime-corejs3/core-js-stable/array/is-array");require("@babel/runtime-corejs3/core-js-stable/json/stringify");var z=require("@babel/runtime-corejs3/core-js-stable/instance/concat"),D=require("@babel/runtime-corejs3/core-js-stable/instance/splice"),N=require("@babel/runtime-corejs3/core-js-stable/instance/for-each"),C=require("@babel/runtime-corejs3/core-js-stable/object/entries"),O=require("@babel/runtime-corejs3/core-js-stable/instance/slice"),V=require("@babel/runtime-corejs3/core-js-stable/promise"),R=require("@babel/runtime-corejs3/core-js-stable/object/get-prototype-of"),P=require("@babel/runtime-corejs3/core-js-stable/set"),B=require("@babel/runtime-corejs3/core-js/global-this"),U=require("@babel/runtime-corejs3/core-js-stable/instance/bind");function Y(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var H=Y(e),W=Y(t),G=Y(r),J=Y(a),K=Y(n),Q=Y(l),X=Y(u),Z=Y(s),ee=Y(i),te=Y(c),re=Y(o),ae=Y(f),ne=Y(d),le=Y(g),ue=Y(h),se=Y(b),ie=Y(p),ce=Y(m),oe=Y(v),fe=Y(y),de=Y(j),ge=Y(k),he=Y(q),be=Y(w),pe=Y(_),me=Y(x),ve=Y(L),ye=Y(S),je=Y($),ke=Y(M),qe=Y(A),we=Y(F),_e=Y(T),xe=Y(E),Le=Y(I),Se=Y(z),$e=Y(D),Me=Y(N),Ae=Y(C),Fe=Y(O),Te=Y(V),Ee=Y(R),Ie=Y(P),ze=Y(B),De=Y(U);var Ne,Ce=function(e){if("object"!==se.default(e)||null===e)return!1;var t=Ee.default(e);if(null===t)return!0;for(var r=t;null!==Ee.default(r);)r=Ee.default(r);return t===r},Oe=function(e){return!isNaN(je.default(e))},Ve=function e(t,r){var a,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},l=_e.default({},t);return Me.default(a=Ae.default(r)).call(a,(function(t){var r=ce.default(t,2),a=r[0],u=r[1];if(a in l)if("object"===se.default(u)&&null!==u)if(Le.default(u)){if(0===n.array)l[a]=u;else if(1===n.array){var s;l[a]=Se.default(s=[]).call(s,ie.default(l[a]),ie.default(u))}else if(2===n.array){var i;l[a]=ie.default(new Ie.default(Se.default(i=[]).call(i,ie.default(l[a]),ie.default(u))))}}else l[a]=e(l[a],u,n);else l[a]=u;else l[a]=u})),l},Re=function(e){return null===e?"Null":void 0===e?"Undefined":"function"==typeof e?"Function":e.constructor&&e.constructor.name},Pe=function(){function e(){re.default(this,e),this._callbacks=[]}var t;return ae.default(e,[{key:"on",value:function(e){var t;be.default(t=this._callbacks).call(t,e)||this._callbacks.push(e)}},{key:"off",value:function(e){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:{},r=arguments.length>1?arguments[1]:void 0;if(re.default(this,e),this._id=t.id||(new Date).getTime().toString()+je.default(1e3*Math.random()),this._languages=t.languages,this._defaultLanguage=t.defaultLanguage||"cn",this._activeLanguage=t.activeLanguage,this._default=t.default,this._messages=t.messages,this._idMap=t.idMap,this._formatters=t.formatters,this._loaders=t.loaders,this._global=null,this.$cache={activeLanguage:null,typedFormatters:{},formatters:{}},!ze.default.VoerkaI18n){var a=pt.I18nManager;ze.default.VoerkaI18n=new a({defaultLanguage:this.defaultLanguage,activeLanguage:this.activeLanguage,languages:t.languages})}this.global=ze.default.VoerkaI18n,this._loading=!1,this.register(r)}var t;return ae.default(e,[{key:"id",get:function(){return this._id}},{key:"defaultLanguage",get:function(){return this._defaultLanguage}},{key:"activeLanguage",get:function(){return this._activeLanguage}},{key:"default",get:function(){return this._default}},{key:"messages",get:function(){return this._messages}},{key:"idMap",get:function(){return this._idMap}},{key:"formatters",get:function(){return this._formatters}},{key:"loaders",get:function(){return this._loaders}},{key:"global",get:function(){return this._global},set:function(e){this._global=e}},{key:"register",value:function(e){"function"===!se.default(e)&&(e=function(){}),this.global.register(this).then(e).catch(e)}},{key:"registerFormatter",value:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},a=r.language,n=void 0===a?"*":a;if("function"===!se.default(t)||"string"!=typeof e)throw new TypeError("Formatter must be a function");be.default(DataTypes).call(DataTypes,e)?this.formatters[n].$types[e]=t:this.formatters[n][e]=t}},{key:"_fallback",value:function(){this._messages=this._default,this._activeLanguage=this.defaultLanguage}},{key:"refresh",value:(t=te.default(ge.default.mark((function e(t){var r,a,n;return ge.default.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(this._loading=Te.default.resolve(),t||(t=this.activeLanguage),t!==this.defaultLanguage){e.next=5;break}return this._messages=this._default,e.abrupt("return");case 5:if("function"!=typeof(r=this.loaders[t])){e.next=20;break}return e.prev=7,e.next=10,r();case 10:this._messages=e.sent.default,this._activeLanguage=t,e.next=18;break;case 14:e.prev=14,e.t0=e.catch(7),console.warn(Se.default(a=Se.default(n="Error while loading language <".concat(t,"> on i18nScope(")).call(n,this.id,"): ")).call(a,e.t0.message)),this._fallback();case 18:e.next=21;break;case 20:this._fallback();case 21:case"end":return e.stop()}}),e,this,[[7,14]])}))),function(e){return t.apply(this,arguments)})},{key:"on",get:function(){var e;return De.default(e=this.global.on).call(e,this.global)}},{key:"off",get:function(){var e;return De.default(e=this.global.off).call(e,this.global)}},{key:"offAll",get:function(){var e;return De.default(e=this.global.offAll).call(e,this.global)}},{key:"change",get:function(){var e;return De.default(e=this.global.change).call(e,this.global)}}]),e}();function Ue(e){var t=function(){if("undefined"==typeof Reflect||!ee.default)return!1;if(ee.default.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(ee.default(Boolean,[],(function(){}))),!0}catch(e){return!1}}();return function(){var r,a=ue.default(e);if(t){var n=ue.default(this).constructor;r=ee.default(a,arguments,n)}else r=a.apply(this,arguments);return le.default(this,r)}}function Ye(e,t){var r=void 0!==X.default&&Z.default(e)||e["@@iterator"];if(!r){if(Le.default(e)||(r=function(e,t){var r;if(!e)return;if("string"==typeof e)return He(e,t);var a=Fe.default(r=Object.prototype.toString.call(e)).call(r,8,-1);"Object"===a&&e.constructor&&(a=e.constructor.name);if("Map"===a||"Set"===a)return Q.default(e);if("Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a))return He(e,t)}(e))||t&&e&&"number"==typeof e.length){r&&(e=r);var a=0,n=function(){};return{s:n,n:function(){return a>=e.length?{done:!0}:{done:!1,value:e[a++]}},e:function(e){throw e},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var l,u=!0,s=!1;return{s:function(){r=r.call(e)},n:function(){var e=r.next();return u=e.done,e},e:function(e){s=!0,l=e},f:function(){try{u||null==r.return||r.return()}finally{if(s)throw l}}}}function He(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,a=new Array(t);r]+)>/g,(function(e,t){return"$"+l[t]})))}if("function"==typeof n){var u=this;return e[K.default].call(this,r,(function(){var e=arguments;return"object"!=se.default(e[e.length-1])&&(e=Fe.default([]).call(e)).push(a(e,u)),n.apply(this,e)}))}return e[K.default].call(this,r,n)},We.apply(this,arguments)}var Ge=Re,Je=Oe,Ke=Ce,Qe=Ve,Xe=Pe,Ze=Be,et={"*":{$types:{Date:function(e){return e.toLocaleString()}},time:function(e){return e.toLocaleTimeString()},shorttime:function(e){return e.toLocaleTimeString()},date:function(e){return e.toLocaleDateString()},dict:function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),a=1;a0&&r.length%2!=0?r[r.length-1]:e}},cn:{$types:{Date:function(e){var t,r,a,n,l;return Se.default(t=Se.default(r=Se.default(a=Se.default(n=Se.default(l="".concat(e.getFullYear(),"年")).call(l,e.getMonth()+1,"月")).call(n,e.getDate(),"日 ")).call(a,e.getHours(),"点")).call(r,e.getMinutes(),"分")).call(t,e.getSeconds(),"秒")}},shortime:function(e){return e.toLocaleTimeString()},time:function(e){var t,r;return Se.default(t=Se.default(r="".concat(e.getHours(),"点")).call(r,e.getMinutes(),"分")).call(t,e.getSeconds(),"秒")},date:function(e){var t,r;return Se.default(t=Se.default(r="".concat(e.getFullYear(),"年")).call(r,e.getMonth()+1,"月")).call(t,e.getDate(),"日")},shortdate:function(e){var t,r;return Se.default(t=Se.default(r="".concat(e.getFullYear(),"-")).call(r,e.getMonth()+1,"-")).call(t,e.getDate())},currency:function(e){return"".concat(e,"元")}},en:{currency:function(e){return"$".concat(e)}}},tt=We(/\{\s*(\w+)?((\s*\|\s*\w*(\(.*\))?\s*)*)\s*\}/g,{varname:1,formatters:2});function rt(e){return be.default(e).call(e,"{")&&be.default(e).call(e,"}")}he.default(Ne||(Ne=oe.default(["{s*{varname}s*}"],["\\{\\s*{varname}\\s*\\}"])));var at=["String","Number","Boolean","Object","Array","Function","Error","Symbol","RegExp","Date","Null","Undefined","Set","Map","WeakSet","WeakMap"];function nt(e){var t,r;if(!e)return[];var a=pe.default(t=me.default(r=me.default(e).call(e).substr(1)).call(r).split("|")).call(t,(function(e){return me.default(e).call(e)}));return pe.default(a).call(a,(function(e){var t=ve.default(e).call(e,"("),r=ye.default(e).call(e,")");if(-1!==t&&-1!==r){var a,n,l=me.default(a=e.substr(t+1,r-t-1)).call(a),u=""==l?[]:pe.default(n=l.split(",")).call(n,(function(e){if(e=me.default(e).call(e),!isNaN(je.default(e)))return je.default(e);if(ke.default(e).call(e,'"')&&qe.default(e).call(e,'"')||ke.default(e).call(e,"'")&&qe.default(e).call(e,"'"))return e.substr(1,e.length-2);if("true"===e.toLowerCase()||"false"===e.toLowerCase())return"true"===e.toLowerCase();if(!(ke.default(e).call(e,"{")&&qe.default(e).call(e,"}")||ke.default(e).call(e,"[")&&qe.default(e).call(e,"]")))return String(e);try{return JSON.parse(e)}catch(t){return String(e)}}));return[e.substr(0,t),u]}return[e,[]]}))}function lt(e,t){var r,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=e,l=_e.default({replaceAll:!0},a);for(tt.lastIndex=0;null!==(r=tt.exec(n));){var u=r.groups.varname||"",s=nt(r.groups.formatters);if("function"==typeof t)try{n=xe.default(l)?xe.default(n).call(n,r[0],t(u,s,r[0])):n.replace(r[0],t(u,s,r[0]))}catch(e){break}tt.lastIndex=0}return n}function ut(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e.$cache={activeLanguage:t,typedFormatters:{},formatters:{}}}function st(e,t,r){var a,n=[],l=Ye(r);try{var u=function(){var r=a.value;if(r[0]){var l=function(e,t,r){if(e.$cache||ut(e),e.$cache.activeLanguage===t){if(r in e.$cache.formatters)return e.$cache.formatters[r]}else ut(e,t);for(var a=0,n=[e.formatters,e.global.formatters];a1?a-1:0),l=1;li)return it(t,r,a,s[i++]);throw new Error}),{replaceAll:!1})}var ot={defaultLanguage:"cn",activeLanguage:"cn",languages:[{name:"cn",title:"中文",default:!0},{name:"en",title:"英文"}],formatters:formatters};function ft(e){return je.default(e)>0}function dt(e,t){try{return Le.default(e)?e.length>t?e[t]:e[e.length-1]:e}catch(t){return Le.default(e)?e[0]:e}}function gt(e){var t,r,a,n,l,u,s,i;return xe.default(t=xe.default(r=xe.default(a=xe.default(n=xe.default(l=xe.default(u=xe.default(s=xe.default(i=xe.default(e).call(e,/\\(?![trnbvf'"]{1})/g,"\\\\")).call(i,"\t","\\t")).call(s,"\n","\\n")).call(u,"\b","\\b")).call(l,"\r","\\r")).call(n,"\f","\\f")).call(a,"'","\\'")).call(r,'"','\\"')).call(t,"\v","\\v")}function ht(e){var t,r,a,n,l,u,s,i;return xe.default(t=xe.default(r=xe.default(a=xe.default(n=xe.default(l=xe.default(u=xe.default(s=xe.default(i=xe.default(e).call(e,"\\t","\t")).call(i,"\\n","\n")).call(s,"\\b","\b")).call(u,"\\r","\r")).call(l,"\\f","\f")).call(n,"\\'","'")).call(a,'\\"','"')).call(r,"\\v","\v")).call(t,/\\\\(?![trnbvf'"]{1})/g,"\\")}var bt=function(e){fe.default(l,e);var t,r,a,n=Ue(l);function l(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return re.default(this,l),e=n.call(this),null!=l.instance||(l.instance=ne.default(e),e._settings=Qe(ot,t),e._scopes=[]),le.default(e,l.instance)}return ae.default(l,[{key:"settings",get:function(){return this._settings}},{key:"scopes",get:function(){return this._scopes}},{key:"activeLanguage",get:function(){return this._settings.activeLanguage}},{key:"defaultLanguage",get:function(){return this._settings.defaultLanguage}},{key:"languages",get:function(){return this._settings.languages}},{key:"formatters",get:function(){return et}},{key:"change",value:(a=te.default(ge.default.mark((function e(t){var r;return ge.default.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(t=me.default(t).call(t),-1===we.default(r=this.languages).call(r,(function(e){return e.name===t}))){e.next=9;break}return e.next=4,this._refreshScopes(t);case 4:return this._settings.activeLanguage=t,e.next=7,this.emit(t);case 7:e.next=10;break;case 9:throw new Error("Not supported language:"+t);case 10:case"end":return e.stop()}}),e,this)}))),function(e){return a.apply(this,arguments)})},{key:"_refreshScopes",value:(r=te.default(ge.default.mark((function e(t){var r,a;return ge.default.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(e.prev=0,a=pe.default(r=this._scopes).call(r,(function(e){return e.refresh(t)})),!Te.default.allSettled){e.next=7;break}return e.next=5,Te.default.allSettled(a);case 5:e.next=9;break;case 7:return e.next=9,Te.default.all(a);case 9:e.next=14;break;case 11:e.prev=11,e.t0=e.catch(0),console.warn("Error while refreshing i18n scopes:",e.t0.message);case 14:case"end":return e.stop()}}),e,this,[[0,11]])}))),function(e){return r.apply(this,arguments)})},{key:"register",value:(t=te.default(ge.default.mark((function e(t){return ge.default.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(t instanceof Ze){e.next=2;break}throw new TypeError("Scope must be an instance of I18nScope");case 2:return this._scopes.push(t),e.next=5,t.refresh(this.activeLanguage);case 5:case"end":return e.stop()}}),e,this)}))),function(e){return t.apply(this,arguments)})},{key:"registerFormatter",value:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},a=r.language,n=void 0===a?"*":a;if("function"===!se.default(t)||"string"!=typeof e)throw new TypeError("Formatter must be a function");be.default(at).call(at,e)?this.formatters[n].$types[e]=t:this.formatters[n][e]=t}}]),l}(Xe),pt={getInterpolatedVars:function(e){var t=[];return lt(e,(function(e,r,a){var n={name:e,formatters:pe.default(r).call(r,(function(e){var t=ce.default(e,2);return{name:t[0],args:t[1]}})),match:a};return-1===we.default(t).call(t,(function(e){return e.name===n.name&&n.formatters.toString()==e.formatters.toString()}))&&t.push(n),""})),t},replaceInterpolatedVars:ct,I18nManager:bt,translate:function(e){var t=this,r=t.global.activeLanguage,a=e,n=[],l=[],u=null;if("string"===!se.default(e))return e;try{var s,i;if(2===arguments.length&&Ke(arguments[1]))Me.default(s=Ae.default(arguments[1])).call(s,(function(e){var t=ce.default(e,2),r=t[0],a=t[1];if("function"==typeof a)try{n[r]=a()}catch(e){n[r]=a}ke.default(r).call(r,"$")&&"number"==typeof n[r]&&l.push(r)})),n=[arguments[1]];else if(arguments.length>=2){var c,o;n=pe.default(c=$e.default(o=Fe.default(Array.prototype).call(arguments)).call(o,1)).call(c,(function(e,t){try{e="function"==typeof e?e():e,Je(e)&&(u=je.default(e))}catch(e){}return e}))}if(r===t.defaultLanguage)ft(a)&&(a=t.default[a]||e);else{var f=ft(a)?a:t.idMap[gt(a)];a=t.messages[f]||a,a=Le.default(a)?pe.default(a).call(a,(function(e){return ht(e)})):ht(a)}return Le.default(a)&&a.length>0&&(a=null!==u?dt(a,u):pluralVar.length>0?dt(a,je.default(n(pluralVar[0]))):a[0]),0==n.length?a:ct.call.apply(ct,Se.default(i=[t,a]).call(i,ie.default(n)))}catch(e){return a}},languages:["af","am","ar-dz","ar-iq","ar-kw","ar-ly","ar-ma","ar-sa","ar-tn","ar","az","be","bg","bi","bm","bn","bo","br","bs","ca","cs","cv","cy","da","de-at","de-ch","de","dv","el","en-au","en-ca","en-gb","en-ie","en-il","en-in","en-nz","en-sg","en-tt","en","eo","es-do","es-mx","es-pr","es-us","es","et","eu","fa","fi","fo","fr-ca","fr-ch","fr","fy","ga","gd","gl","gom-latn","gu","he","hi","hr","ht","hu","hy-am","id","is","it-ch","it","ja","jv","ka","kk","km","kn","ko","ku","ky","lb","lo","lt","lv","me","mi","mk","ml","mn","mr","ms-my","ms","mt","my","nb","ne","nl-be","nl","nn","oc-lnc","pa-in","pl","pt-br","pt","ro","ru","rw","sd","se","si","sk","sl","sq","sr-cyrl","sr","ss","sv-fi","sv","sw","ta","te","tet","tg","th","tk","tl-ph","tlh","tr","tzl","tzm-latn","tzm","ug-cn","uk","ur","uz-latn","uz","vi","x-pseudo","yo","zh-cn","zh-hk","zh-tw","zh"],i18nScope:Ze,defaultLanguageSettings:ot,getDataTypeName:Ge,isNumber:Je,isPlainObject:Ke};module.exports=pt; -//# sourceMappingURL=index.cjs.map diff --git a/packages/runtime/dist/index.cjs.map b/packages/runtime/dist/index.cjs.map deleted file mode 100644 index 769e832..0000000 --- a/packages/runtime/dist/index.cjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.cjs","sources":["../utils.js","../eventemitter.js","../scope.js","../index.js","../formatters.js"],"sourcesContent":["\r\n/**\r\n * 判断是否是JSON对象\r\n * @param {*} obj \r\n * @returns \r\n */\r\n function isPlainObject(obj){\r\n if (typeof obj !== 'object' || obj === null) return false;\r\n var proto = Object.getPrototypeOf(obj);\r\n if (proto === null) return true;\r\n var baseProto = proto;\r\n\r\n while (Object.getPrototypeOf(baseProto) !== null) {\r\n baseProto = Object.getPrototypeOf(baseProto);\r\n }\r\n return proto === baseProto; \r\n}\r\n\r\nfunction isNumber(value){\r\n return !isNaN(parseInt(value))\r\n}\r\n \r\n/**\r\n * 简单进行对象合并\r\n * \r\n * options={\r\n * array:0 , // 数组合并策略,0-替换,1-合并,2-去重合并\r\n * }\r\n * \r\n * @param {*} toObj \r\n * @param {*} formObj \r\n * @returns 合并后的对象\r\n */\r\nfunction deepMerge(toObj,formObj,options={}){\r\n let results = Object.assign({},toObj)\r\n Object.entries(formObj).forEach(([key,value])=>{\r\n if(key in results){\r\n if(typeof value === \"object\" && value !== null){\r\n if(Array.isArray(value)){\r\n if(options.array === 0){\r\n results[key] = value\r\n }else if(options.array === 1){\r\n results[key] = [...results[key],...value]\r\n }else if(options.array === 2){\r\n results[key] = [...new Set([...results[key],...value])]\r\n }\r\n }else{\r\n results[key] = deepMerge(results[key],value,options)\r\n }\r\n }else{\r\n results[key] = value\r\n }\r\n }else{\r\n results[key] = value\r\n }\r\n })\r\n return results\r\n}\r\n\r\n\r\n/**\r\n * 获取指定变量类型名称\r\n * getDataTypeName(1) == Number\r\n * getDataTypeName(\"\") == String\r\n * getDataTypeName(null) == Null\r\n * getDataTypeName(undefined) == Undefined\r\n * getDataTypeName(new Date()) == Date\r\n * getDataTypeName(new Error()) == Error\r\n * \r\n * @param {*} v \r\n * @returns \r\n */\r\n function getDataTypeName(v){\r\n\tif (v === null) return 'Null' \r\n\tif (v === undefined) return 'Undefined' \r\n if(typeof(v)===\"function\") return \"Function\"\r\n\treturn v.constructor && v.constructor.name;\r\n};\r\n\r\n\r\n\r\n\r\n\r\nmodule.exports ={\r\n isPlainObject,\r\n isNumber,\r\n deepMerge,\r\n getDataTypeName\r\n}","/**\r\n* \r\n* 简单的事件触发器\r\n* \r\n*/\r\nmodule.exports = class EventEmitter{\r\n constructor(){\r\n this._callbacks = []\r\n }\r\n on(callback){\r\n if(this._callbacks.includes(callback)) return\r\n this._callbacks.push(callback)\r\n }\r\n off(callback){\r\n for(let i=0;icb(...args)))\r\n }else{\r\n await Promise.all(this._callbacks.map(cb=>cb(...args)))\r\n }\r\n } \r\n}","\r\nmodule.exports = class i18nScope {\r\n constructor(options={},callback){\r\n // 每个作用域都有一个唯一的id\r\n this._id = options.id || (new Date().getTime().toString()+parseInt(Math.random()*1000))\r\n this._languages = options.languages // 当前作用域的语言列表\r\n this._defaultLanguage = options.defaultLanguage || \"cn\" // 默认语言名称\r\n this._activeLanguage = options.activeLanguage // 当前语言名称\r\n this._default = options.default // 默认语言包\r\n this._messages = options.messages // 当前语言包\r\n this._idMap = options.idMap // 消息id映射列表\r\n this._formatters = options.formatters // 当前作用域的格式化函数列表\r\n this._loaders = options.loaders // 异步加载语言文件的函数列表\r\n this._global = null // 引用全局VoerkaI18n配置,注册后自动引用 \r\n // 主要用来缓存格式化器的引用,当使用格式化器时可以直接引用,避免检索\r\n this.$cache={\r\n activeLanguage : null,\r\n typedFormatters: {},\r\n formatters : {},\r\n }\r\n // 如果不存在全局VoerkaI18n实例,说明当前Scope是唯一或第一个加载的作用域,\r\n // 则使用当前作用域来初始化全局VoerkaI18n实例\r\n if(!globalThis.VoerkaI18n){\r\n const { I18nManager } = require(\"./\")\r\n globalThis.VoerkaI18n = new I18nManager({\r\n defaultLanguage: this.defaultLanguage,\r\n activeLanguage : this.activeLanguage,\r\n languages: options.languages,\r\n })\r\n }\r\n this.global = globalThis.VoerkaI18n \r\n // 正在加载语言包标识\r\n this._loading=false\r\n // 在全局注册作用域\r\n this.register(callback)\r\n }\r\n // 作用域\r\n get id(){return this._id}\r\n // 默认语言名称\r\n get defaultLanguage(){return this._defaultLanguage}\r\n // 默认语言名称\r\n get activeLanguage(){return this._activeLanguage}\r\n // 默认语言包\r\n get default(){return this._default}\r\n // 当前语言包\r\n get messages(){return this._messages}\r\n // 消息id映射列表\r\n get idMap(){return this._idMap}\r\n // 当前作用域的格式化函数列表\r\n get formatters(){return this._formatters}\r\n // 异步加载语言文件的函数列表\r\n get loaders(){return this._loaders}\r\n // 引用全局VoerkaI18n配置,注册后自动引用\r\n get global(){return this._global}\r\n set global(value){this._global = value}\r\n /**\r\n * 在全局注册作用域\r\n * @param {*} callback 当注册\r\n */\r\n register(callback){\r\n if(!typeof(callback)===\"function\") callback = ()=>{} \r\n this.global.register(this).then(callback).catch(callback) \r\n }\r\n registerFormatter(name,formatter,{language=\"*\"}={}){\r\n if(!typeof(formatter)===\"function\" || typeof(name)!==\"string\"){\r\n throw new TypeError(\"Formatter must be a function\")\r\n } \r\n if(DataTypes.includes(name)){\r\n this.formatters[language].$types[name] = formatter\r\n }else{\r\n this.formatters[language][name] = formatter\r\n }\r\n }\r\n /**\r\n * 回退到默认语言\r\n */\r\n _fallback(){\r\n this._messages = this._default \r\n this._activeLanguage = this.defaultLanguage\r\n }\r\n /**\r\n * 刷新当前语言包\r\n * @param {*} newLanguage \r\n */\r\n async refresh(newLanguage){\r\n this._loading = Promise.resolve()\r\n if(!newLanguage) newLanguage = this.activeLanguage\r\n // 默认语言,默认语言采用静态加载方式,只需要简单的替换即可\r\n if(newLanguage === this.defaultLanguage){\r\n this._messages = this._default\r\n return \r\n }\r\n // 非默认语言需要异步加载语言包文件,加载器是一个异步函数\r\n // 如果没有加载器,则无法加载语言包,因此回退到默认语言\r\n const loader = this.loaders[newLanguage]\r\n if(typeof(loader) === \"function\"){\r\n try{\r\n this._messages = (await loader()).default\r\n this._activeLanguage = newLanguage\r\n }catch(e){\r\n console.warn(`Error while loading language <${newLanguage}> on i18nScope(${this.id}): ${e.message}`)\r\n this._fallback()\r\n } \r\n }else{\r\n this._fallback()\r\n } \r\n }\r\n // 以下方法引用全局VoerkaI18n实例的方法\r\n get on(){return this.global.on.bind(this.global)}\r\n get off(){return this.global.off.bind(this.global)}\r\n get offAll(){return this.global.offAll.bind(this.global)}\r\n get change(){\r\n return this.global.change.bind(this.global)\r\n }\r\n}","const { getDataTypeName,isNumber,isPlainObject,deepMerge } = require(\"./utils\")\r\nconst EventEmitter = require(\"./eventemitter\")\r\nconst i18nScope = require(\"./scope.js\")\r\nlet inlineFormatters = require(\"./formatters\") // 内置格式化器\r\n\r\n\r\n\r\n// 用来提取字符里面的插值变量参数 , 支持管道符 { var | formatter | formatter }\r\n// 不支持参数: let varWithPipeRegexp = /\\{\\s*(?\\w+)?(?(\\s*\\|\\s*\\w*\\s*)*)\\s*\\}/g\r\n\r\n// 支持参数: { var | formatter(x,x,..) | formatter }\r\nlet varWithPipeRegexp = /\\{\\s*(?\\w+)?(?(\\s*\\|\\s*\\w*(\\(.*\\)){0,1}\\s*)*)\\s*\\}/g\r\n\r\n// 有效的语言名称列表\r\nconst languages = [\"af\",\"am\",\"ar-dz\",\"ar-iq\",\"ar-kw\",\"ar-ly\",\"ar-ma\",\"ar-sa\",\"ar-tn\",\"ar\",\"az\",\"be\",\"bg\",\"bi\",\"bm\",\"bn\",\"bo\",\"br\",\"bs\",\"ca\",\"cs\",\"cv\",\"cy\",\"da\",\"de-at\",\"de-ch\",\"de\",\"dv\",\"el\",\"en-au\",\"en-ca\",\"en-gb\",\"en-ie\",\"en-il\",\"en-in\",\"en-nz\",\"en-sg\",\"en-tt\",\"en\",\"eo\",\"es-do\",\"es-mx\",\"es-pr\",\"es-us\",\"es\",\"et\",\"eu\",\"fa\",\"fi\",\"fo\",\"fr-ca\",\"fr-ch\",\"fr\",\"fy\",\"ga\",\"gd\",\"gl\",\"gom-latn\",\"gu\",\"he\",\"hi\",\"hr\",\"ht\",\"hu\",\"hy-am\",\"id\",\"is\",\"it-ch\",\"it\",\"ja\",\"jv\",\"ka\",\"kk\",\"km\",\"kn\",\"ko\",\"ku\",\"ky\",\"lb\",\"lo\",\"lt\",\"lv\",\"me\",\"mi\",\"mk\",\"ml\",\"mn\",\"mr\",\"ms-my\",\"ms\",\"mt\",\"my\",\"nb\",\"ne\",\"nl-be\",\"nl\",\"nn\",\"oc-lnc\",\"pa-in\",\"pl\",\"pt-br\",\"pt\",\"ro\",\"ru\",\"rw\",\"sd\",\"se\",\"si\",\"sk\",\"sl\",\"sq\",\"sr-cyrl\",\"sr\",\"ss\",\"sv-fi\",\"sv\",\"sw\",\"ta\",\"te\",\"tet\",\"tg\",\"th\",\"tk\",\"tl-ph\",\"tlh\",\"tr\",\"tzl\",\"tzm-latn\",\"tzm\",\"ug-cn\",\"uk\",\"ur\",\"uz-latn\",\"uz\",\"vi\",\"x-pseudo\",\"yo\",\"zh-cn\",\"zh-hk\",\"zh-tw\",\"zh\"]\r\n\r\n\r\n// 插值变量字符串替换正则\r\n\r\n//let varReplaceRegexp =String.raw`\\{\\s*(?{name}\\.?\\w*)\\s*\\}`\r\n\r\n\r\nlet varReplaceRegexp =String.raw`\\{\\s*{varname}\\s*\\}`\r\n\r\n/**\r\n * 考虑到通过正则表达式进行插件的替换可能较慢,因此提供一个简单方法来过滤掉那些\r\n * 不需要进行插值处理的字符串\r\n * 原理很简单,就是判断一下是否同时具有{和}字符,如果有则认为可能有插值变量,如果没有则一定没有插件变量,则就不需要进行正则匹配\r\n * 从而可以减少不要的正则匹配\r\n * 注意:该方法只能快速判断一个字符串不包括插值变量\r\n * @param {*} str \r\n * @returns {boolean} true=可能包含插值变量,\r\n */\r\nfunction hasInterpolation(str){\r\n return str.includes(\"{\") && str.includes(\"}\")\r\n} \r\nconst DataTypes = [\"String\",\"Number\",\"Boolean\",\"Object\",\"Array\",\"Function\",\"Error\",\"Symbol\",\"RegExp\",\"Date\",\"Null\",\"Undefined\",\"Set\",\"Map\",\"WeakSet\",\"WeakMap\"]\r\n \r\n\r\n/**\r\n 通过正则表达式对原始文本内容进行解析匹配后得到的\r\n formatters=\"| aaa(1,1) | bbb \"\r\n\r\n 需要统一解析为\r\n\r\n [\r\n [aaa,[1,1]], // [formatter'name,[args,...]]\r\n [bbb,[]],\r\n ]\r\n\r\n formatters=\"| aaa(1,1,\"dddd\") | bbb \"\r\n\r\n 目前对参数采用简单的split(\",\")来解析,因为无法正确解析aaa(1,1,\"dd,,dd\")形式的参数\r\n 在此场景下基本够用了,如果需要支持更复杂的参数解析,可以后续考虑使用正则表达式来解析\r\n \r\n @returns [[,[,,...]]]\r\n */\r\nfunction parseFormatters(formatters){\r\n if(!formatters) return []\r\n // 1. 先解析为 [\"aaa()\",\"bbb\"]形式\r\n let result = formatters.trim().substr(1).trim().split(\"|\").map(r=>r.trim()) \r\n\r\n // 2. 解析格式化器参数\r\n return result.map(formatter=>{\r\n let firstIndex = formatter.indexOf(\"(\")\r\n let lastIndex = formatter.lastIndexOf(\")\")\r\n if(firstIndex!==-1 && lastIndex!==-1){ // 带参数的格式化器\r\n const argsContent = formatter.substr(firstIndex+1,lastIndex-firstIndex-1).trim()\r\n let args = argsContent==\"\" ? [] : argsContent.split(\",\").map(arg=>{\r\n arg = arg.trim()\r\n if(!isNaN(parseInt(arg))){\r\n return parseInt(arg) // 数字\r\n }else if((arg.startsWith('\\\"') && arg.endsWith('\\\"')) || (arg.startsWith('\\'') && arg.endsWith('\\'')) ){\r\n return arg.substr(1,arg.length-2) // 字符串\r\n }else if(arg.toLowerCase()===\"true\" || arg.toLowerCase()===\"false\"){\r\n return arg.toLowerCase()===\"true\" // 布尔值\r\n }else if((arg.startsWith('{') && arg.endsWith('}')) || (arg.startsWith('[') && arg.endsWith(']'))){ \r\n try{\r\n return JSON.parse(arg)\r\n }catch(e){\r\n return String(arg)\r\n }\r\n }else{\r\n return String(arg)\r\n }\r\n })\r\n return [formatter.substr(0,firstIndex),args]\r\n }else{// 不带参数的格式化器\r\n return [formatter,[]]\r\n } \r\n }) \r\n}\r\n\r\n/** \r\n * 提取字符串中的插值变量\r\n * // [\r\n // { \r\n name:<变量名称>,formatters:[{name:<格式化器名称>,args:[<参数>,<参数>,....]]}],<匹配字符串>],\r\n // ....\r\n // \r\n * @param {*} str \r\n * @param {*} isFull =true 保留所有插值变量 =false 进行去重\r\n * @returns {Array} \r\n * [\r\n * {\r\n * name:\"<变量名称>\",\r\n * formatters:[\r\n * {name:\"<格式化器名称>\",args:[<参数>,<参数>,....]},\r\n * {name:\"<格式化器名称>\",args:[<参数>,<参数>,....]},\r\n * ],\r\n * match:\"<匹配字符串>\"\r\n * },\r\n * ...\r\n * ]\r\n */\r\nfunction getInterpolatedVars(str){\r\n let vars = []\r\n forEachInterpolatedVars(str,(varName,formatters,match)=>{\r\n let varItem = {\r\n name:varName,\r\n formatters:formatters.map(([formatter,args])=>{\r\n return {\r\n name:formatter,\r\n args:args\r\n }\r\n }),\r\n match:match\r\n }\r\n if(vars.findIndex(varDef=>((varDef.name===varItem.name) && (varItem.formatters.toString() == varDef.formatters.toString())))===-1){\r\n vars.push(varItem) \r\n }\r\n return \"\"\r\n }) \r\n return vars\r\n}\r\n/**\r\n * 遍历str中的所有插值变量传递给callback,将callback返回的结果替换到str中对应的位置\r\n * @param {*} str \r\n * @param {Function(<变量名称>,[formatters],match[0])} callback \r\n * @returns 返回替换后的字符串\r\n */\r\nfunction forEachInterpolatedVars(str,callback,options={}){\r\n let result=str, match \r\n let opts = Object.assign({\r\n replaceAll:true, // 是否替换所有插值变量,当使用命名插值时应置为true,当使用位置插值时应置为false\r\n },options)\r\n varWithPipeRegexp.lastIndex=0\r\n while ((match = varWithPipeRegexp.exec(result)) !== null) {\r\n const varname = match.groups.varname || \"\"\r\n // 解析格式化器和参数 = [,[,[,,...]]]\r\n const formatters = parseFormatters(match.groups.formatters)\r\n if(typeof(callback)===\"function\"){\r\n try{\r\n if(opts.replaceAll){\r\n result=result.replaceAll(match[0],callback(varname,formatters,match[0]))\r\n }else{\r\n result=result.replace(match[0],callback(varname,formatters,match[0]))\r\n } \r\n }catch{// callback函数可能会抛出异常,如果抛出异常,则中断匹配过程\r\n break \r\n } \r\n }\r\n varWithPipeRegexp.lastIndex=0\r\n }\r\n return result\r\n}\r\n/**\r\n * 将要翻译内容提供了一个非文本内容时进行默认的转换\r\n * - 对函数则执行并取返回结果()\r\n * - 对Array和Object使用JSON.stringify\r\n * - 其他类型使用toString\r\n * \r\n * @param {*} value \r\n * @returns \r\n */\r\nfunction transformToString(value){\r\n let result = value\r\n if(typeof(result)===\"function\") result = value()\r\n if(!(typeof(result)===\"string\")){\r\n if(Array.isArray(result) || isPlainObject(result)){\r\n result = JSON.stringify(result)\r\n }else{\r\n result = result.toString()\r\n }\r\n }\r\n return result\r\n}\r\n\r\nfunction resetScopeCache(scope,activeLanguage=null){\r\n scope.$cache = {activeLanguage,typedFormatters:{},formatters:{}}\r\n}\r\n/**\r\n * 取得指定数据类型的默认格式化器 \r\n * \r\n * 可以为每一个数据类型指定一个默认的格式化器,当传入插值变量时,\r\n * 会自动调用该格式化器来对值进行格式化转换\r\n \r\n const formatters = { \r\n \"*\":{\r\n $types:{...} // 在所有语言下只作用于特定数据类型的格式化器\r\n }, // 在所有语言下生效的格式化器 \r\n cn:{ \r\n $types:{ \r\n [数据类型]:(value)=>{...},\r\n }, \r\n [格式化器名称]:(value)=>{...},\r\n [格式化器名称]:(value)=>{...},\r\n [格式化器名称]:(value)=>{...},\r\n },\r\n }\r\n * @param {*} scope \r\n * @param {*} activeLanguage \r\n * @param {*} dataType 数字类型\r\n * @returns {Function} 格式化函数 \r\n */\r\nfunction getDataTypeDefaultFormatter(scope,activeLanguage,dataType){\r\n if(!scope.$cache) resetScopeCache(scope)\r\n if(scope.$cache.activeLanguage === activeLanguage) {\r\n if(dataType in scope.$cache.typedFormatters) return scope.$cache.typedFormatters[dataType]\r\n }else{// 当语言切换时清空缓存\r\n resetScopeCache(scope,activeLanguage)\r\n }\r\n\r\n // 先在当前作用域中查找,再在全局查找\r\n const targets = [scope.formatters,scope.global.formatters] \r\n for(const target of targets){\r\n if(!target) continue\r\n // 优先在当前语言的$types中查找\r\n if((activeLanguage in target) && isPlainObject(target[activeLanguage].$types)){ \r\n let formatters = target[activeLanguage].$types \r\n if(dataType in formatters && typeof(formatters[dataType])===\"function\"){ \r\n return scope.$cache.typedFormatters[dataType] = formatters[dataType]\r\n } \r\n }\r\n // 在所有语言的$types中查找\r\n if((\"*\" in target) && isPlainObject(target[\"*\"].$types)){\r\n let formatters = target[\"*\"].$types \r\n if(dataType in formatters && typeof(formatters[dataType])===\"function\"){ \r\n return scope.$cache.typedFormatters[dataType] = formatters[dataType]\r\n } \r\n } \r\n } \r\n}\r\n\r\n/**\r\n * 获取指定名称的格式化器函数\r\n * @param {*} scope \r\n * @param {*} activeLanguage \r\n * @param {*} name 格式化器名称\r\n * @returns {Function} 格式化函数 \r\n */ \r\nfunction getFormatter(scope,activeLanguage,name){\r\n // 缓存格式化器引用,避免重复检索\r\n if(!scope.$cache) resetScopeCache(scope)\r\n if(scope.$cache.activeLanguage === activeLanguage) {\r\n if(name in scope.$cache.formatters) return scope.$cache.formatters[name]\r\n }else{// 当语言切换时清空缓存\r\n resetScopeCache(scope,activeLanguage)\r\n }\r\n // 先在当前作用域中查找,再在全局查找\r\n const targets = [scope.formatters,scope.global.formatters] \r\n for(const target of targets){\r\n // 优先在当前语言查找\r\n if(activeLanguage in target){ \r\n let formatters = target[activeLanguage] || {} \r\n if((name in formatters) && typeof(formatters[name])===\"function\") return scope.$cache.formatters[name] = formatters[name]\r\n }\r\n // 在所有语言的$types中查找\r\n let formatters = target[\"*\"] || {} \r\n if((name in formatters) && typeof(formatters[name])===\"function\") return scope.$cache.formatters[name] = formatters[name]\r\n } \r\n}\r\n\r\n/**\r\n * 执行格式化器并返回结果\r\n * @param {*} value \r\n * @param {*} formatters 多个格式化器顺序执行,前一个输出作为下一个格式化器的输入\r\n */\r\nfunction executeFormatter(value,formatters){\r\n if(formatters.length===0) return value\r\n let result = value\r\n try{\r\n for(let formatter of formatters){\r\n if(typeof(formatter) === \"function\") {\r\n result = formatter(result)\r\n }else{// 如果碰到无效的格式化器,则跳过过续的格式化器\r\n return result \r\n }\r\n }\r\n }catch(e){\r\n console.error(`Error while execute i18n formatter for ${value}: ${e.message} ` )\r\n } \r\n return result\r\n}\r\n/**\r\n * 将 [[格式化器名称,[参数,参数,...]],[格式化器名称,[参数,参数,...]]]格式化器转化为\r\n * \r\n * \r\n * \r\n * @param {*} scope \r\n * @param {*} activeLanguage \r\n * @param {*} formatters \r\n */\r\nfunction buildFormatters(scope,activeLanguage,formatters){\r\n let results = [] \r\n for(let formatter of formatters){\r\n if(formatter[0]){\r\n const func = getFormatter(scope,activeLanguage,formatter[0])\r\n if(typeof(func)===\"function\"){\r\n results.push((v)=>{\r\n return func(v,...formatter[1])\r\n })\r\n }else{\r\n // 格式化器无效或者没有定义时,查看当前值是否具有同名的原型方法,如果有则执行调用\r\n // 比如padStart格式化器是String的原型方法,不需要配置就可以直接作为格式化器调用\r\n results.push((v)=>{\r\n if(typeof(v[formatter[0]])===\"function\"){\r\n return v[formatter[0]].call(v,...formatter[1])\r\n }else{\r\n return v\r\n } \r\n }) \r\n } \r\n }\r\n }\r\n return results\r\n} \r\n\r\n/**\r\n * 将value经过格式化器处理后返回\r\n * @param {*} scope \r\n * @param {*} activeLanguage \r\n * @param {*} formatters \r\n * @param {*} value \r\n * @returns \r\n */\r\nfunction getFormattedValue(scope,activeLanguage,formatters,value){\r\n // 1. 取得格式化器函数列表\r\n const formatterFuncs = buildFormatters(scope,activeLanguage,formatters) \r\n // 2. 查找每种数据类型默认格式化器,并添加到formatters最前面,默认数据类型格式化器优先级最高\r\n const defaultFormatter = getDataTypeDefaultFormatter(scope,activeLanguage,getDataTypeName(value)) \r\n if(defaultFormatter){\r\n formatterFuncs.splice(0,0,defaultFormatter)\r\n } \r\n // 3. 执行格式化器\r\n value = executeFormatter(value,formatterFuncs) \r\n return value\r\n}\r\n\r\n/**\r\n * 字符串可以进行变量插值替换,\r\n * replaceInterpolatedVars(\"<模板字符串>\",{变量名称:变量值,变量名称:变量值,...})\r\n * replaceInterpolatedVars(\"<模板字符串>\",[变量值,变量值,...])\r\n * replaceInterpolatedVars(\"<模板字符串>\",变量值,变量值,...])\r\n * \r\n- 当只有两个参数并且第2个参数是{}时,将第2个参数视为命名变量的字典\r\n replaceInterpolatedVars(\"this is {a}+{b},{a:1,b:2}) --> this is 1+2\r\n- 当只有两个参数并且第2个参数是[]时,将第2个参数视为位置参数\r\n replaceInterpolatedVars\"this is {}+{}\",[1,2]) --> this is 1+2\r\n- 普通位置参数替换\r\n replaceInterpolatedVars(\"this is {a}+{b}\",1,2) --> this is 1+2\r\n- \r\nthis == scope == { formatters: {}, ... }\r\n* @param {*} template \r\n* @returns \r\n*/\r\nfunction replaceInterpolatedVars(template,...args) {\r\n const scope = this\r\n // 当前激活语言\r\n const activeLanguage = scope.global.activeLanguage \r\n let result=template\r\n\r\n // 没有变量插值则的返回原字符串 \r\n if(args.length===0 || !hasInterpolation(template)) return template \r\n\r\n // ****************************变量插值****************************\r\n if(args.length===1 && isPlainObject(args[0])){ \r\n // 读取模板字符串中的插值变量列表\r\n // [[var1,[formatter,formatter,...],match],[var2,[formatter,formatter,...],match],...}\r\n let varValues = args[0]\r\n return forEachInterpolatedVars(template,(varname,formatters)=>{\r\n let value = (varname in varValues) ? varValues[varname] : ''\r\n return getFormattedValue(scope,activeLanguage,formatters,value) \r\n }) \r\n }else{ \r\n // ****************************位置插值****************************\r\n // 如果只有一个Array参数,则认为是位置变量列表,进行展开\r\n const params=(args.length===1 && Array.isArray(args[0])) ? [...args[0]] : args \r\n if(params.length===0) return template // 没有变量则不需要进行插值处理,返回原字符串 \r\n let i = 0\r\n return forEachInterpolatedVars(template,(varname,formatters)=>{\r\n if(params.length>i){ \r\n return getFormattedValue(scope,activeLanguage,formatters,params[i++]) \r\n }else{\r\n throw new Error() // 抛出异常,停止插值处理\r\n }\r\n },{replaceAll:false})\r\n \r\n }\r\n return result\r\n} \r\n\r\n// 默认语言配置\r\nconst defaultLanguageSettings = { \r\n defaultLanguage: \"cn\",\r\n activeLanguage: \"cn\",\r\n languages:[\r\n {name:\"cn\",title:\"中文\",default:true},\r\n {name:\"en\",title:\"英文\"}\r\n ],\r\n formatters\r\n}\r\n\r\nfunction isMessageId(content){\r\n return parseInt(content)>0\r\n}\r\n/**\r\n * 根据值的单数和复数形式,从messages中取得相应的消息\r\n * \r\n * @param {*} messages 复数形式的文本内容 = [<=0时的内容>,<=1时的内容>,<=2时的内容>,...]\r\n * @param {*} value \r\n */\r\nfunction getPluraMessage(messages,value){\r\n try{\r\n if(Array.isArray(messages)){\r\n return messages.length > value ? messages[value] : messages[messages.length-1]\r\n }else{\r\n return messages\r\n }\r\n }catch{\r\n return Array.isArray(messages) ? messages[0] : messages\r\n }\r\n}\r\nfunction escape(str){\r\n return str.replaceAll(/\\\\(?![trnbvf'\"]{1})/g,\"\\\\\\\\\")\r\n .replaceAll(\"\\t\",\"\\\\t\")\r\n .replaceAll(\"\\n\",\"\\\\n\")\r\n .replaceAll(\"\\b\",\"\\\\b\")\r\n .replaceAll(\"\\r\",\"\\\\r\")\r\n .replaceAll(\"\\f\",\"\\\\f\")\r\n .replaceAll(\"\\'\",\"\\\\'\")\r\n .replaceAll('\\\"','\\\\\"')\r\n .replaceAll('\\v','\\\\v') \r\n}\r\nfunction unescape(str){\r\n return str\r\n .replaceAll(\"\\\\t\",\"\\t\")\r\n .replaceAll(\"\\\\n\",\"\\n\")\r\n .replaceAll(\"\\\\b\",\"\\b\")\r\n .replaceAll(\"\\\\r\",\"\\r\")\r\n .replaceAll(\"\\\\f\",\"\\f\")\r\n .replaceAll(\"\\\\'\",\"\\'\")\r\n .replaceAll('\\\\\"','\\\"')\r\n .replaceAll('\\\\v','\\v') \r\n .replaceAll(/\\\\\\\\(?![trnbvf'\"]{1})/g,\"\\\\\")\r\n}\r\n/**\r\n * 翻译函数\r\n * \r\n* translate(\"要翻译的文本内容\") 如果默认语言是中文,则不会进行翻译直接返回\r\n* translate(\"I am {} {}\",\"man\") == I am man 位置插值\r\n* translate(\"I am {p}\",{p:\"man\"}) 字典插值\r\n* translate(\"total {$count} items\", {$count:1}) //复数形式 \r\n* translate(\"total {} {} {} items\",a,b,c) // 位置变量插值\r\n * \r\n * this===scope 当前绑定的scope\r\n * \r\n */\r\nfunction translate(message) { \r\n const scope = this\r\n const activeLanguage = scope.global.activeLanguage \r\n let content = message\r\n let vars=[] // 插值变量列表\r\n let pluralVars= [] // 复数变量\r\n let pluraValue = null // 复数值\r\n if(!typeof(message)===\"string\") return message\r\n try{\r\n // 1. 预处理变量: 复数变量保存至pluralVars中 , 变量如果是Function则调用 \r\n if(arguments.length === 2 && isPlainObject(arguments[1])){\r\n Object.entries(arguments[1]).forEach(([name,value])=>{\r\n if(typeof(value)===\"function\"){\r\n try{\r\n vars[name] = value()\r\n }catch(e){\r\n vars[name] = value\r\n }\r\n } \r\n // 以$开头的视为复数变量\r\n if(name.startsWith(\"$\") && typeof(vars[name])===\"number\") pluralVars.push(name)\r\n })\r\n vars = [arguments[1]]\r\n }else if(arguments.length >= 2){\r\n vars = [...arguments].splice(1).map((arg,index)=>{\r\n try{\r\n arg = typeof(arg)===\"function\" ? arg() : arg \r\n // 位置参数中以第一个数值变量为复数变量\r\n if(isNumber(arg)) pluraValue = parseInt(arg) \r\n }catch(e){ }\r\n return arg \r\n })\r\n \r\n }\r\n \r\n \r\n \r\n\r\n // 3. 取得翻译文本模板字符串\r\n if(activeLanguage === scope.defaultLanguage){\r\n // 2.1 从默认语言中取得翻译文本模板字符串\r\n // 如果当前语言就是默认语言,不需要查询加载,只需要做插值变换即可\r\n // 当源文件运用了babel插件后会将原始文本内容转换为msgId\r\n // 如果是msgId则从scope.default中读取,scope.default=默认语言包={:}\r\n if(isMessageId(content)){\r\n content = scope.default[content] || message\r\n }\r\n }else{ \r\n // 2.2 从当前语言包中取得翻译文本模板字符串\r\n // 如果没有启用babel插件将源文本转换为msgId,需要先将文本内容转换为msgId\r\n // JSON.stringify在进行转换时会将\\t\\n\\r转换为\\\\t\\\\n\\\\r,这样在进行匹配时就出错 \r\n let msgId = isMessageId(content) ? content : scope.idMap[escape(content)] \r\n content = scope.messages[msgId] || content\r\n content = Array.isArray(content) ? content.map(v=>unescape(v)) : unescape(content)\r\n }\r\n // 2. 处理复数\r\n // 经过上面的处理,content可能是字符串或者数组\r\n // content = \"原始文本内容\" || 复数形式[\"原始文本内容\",\"原始文本内容\"....]\r\n // 如果是数组说明要启用复数机制,需要根据插值变量中的某个变量来判断复数形式\r\n if(Array.isArray(content) && content.length>0){\r\n // 如果存在复数命名变量,只取第一个复数变量\r\n if(pluraValue!==null){ // 启用的是位置插值,pluraIndex=第一个数字变量的位置\r\n content = getPluraMessage(content,pluraValue)\r\n }else if(pluralVar.length>0){\r\n content = getPluraMessage(content,parseInt(vars(pluralVar[0])))\r\n }else{ // 如果找不到复数变量,则使用第一个内容\r\n content = content[0]\r\n }\r\n } \r\n \r\n // 进行插值处理\r\n if(vars.length==0){\r\n return content\r\n }else{\r\n return replaceInterpolatedVars.call(scope,content,...vars)\r\n } \r\n }catch(e){\r\n return content // 出错则返回原始文本\r\n } \r\n}\r\n \r\n/** \r\n * 多语言管理类\r\n * \r\n * 当导入编译后的多语言文件时(import(\"./languages\")),会自动生成全局实例VoerkaI18n\r\n * \r\n * VoerkaI18n.languages // 返回支持的语言列表\r\n * VoerkaI18n.defaultLanguage // 默认语言\r\n * VoerkaI18n.language // 当前语言\r\n * VoerkaI18n.change(language) // 切换到新的语言 \r\n * \r\n * \r\n * VoerkaI18n.on(\"change\",(language)=>{}) // 注册语言切换事件\r\n * VoerkaI18n.off(\"change\",(language)=>{}) \r\n * \r\n * */ \r\n class I18nManager extends EventEmitter{\r\n constructor(settings={}){\r\n super()\r\n if(I18nManager.instance!=null){\r\n return I18nManager.instance;\r\n }\r\n I18nManager.instance = this;\r\n this._settings = deepMerge(defaultLanguageSettings,settings)\r\n this._scopes=[] \r\n return I18nManager.instance;\r\n }\r\n get settings(){ return this._settings }\r\n get scopes(){ return this._scopes }\r\n // 当前激活语言\r\n get activeLanguage(){ return this._settings.activeLanguage}\r\n // 默认语言\r\n get defaultLanguage(){ return this._settings.defaultLanguage}\r\n // 支持的语言列表\r\n get languages(){ return this._settings.languages}\r\n // 内置格式化器\r\n get formatters(){ return inlineFormatters }\r\n /**\r\n * 切换语言\r\n */\r\n async change(value){\r\n value=value.trim()\r\n if(this.languages.findIndex(lang=>lang.name === value)!==-1){\r\n // 通知所有作用域刷新到对应的语言包\r\n await this._refreshScopes(value)\r\n this._settings.activeLanguage = value\r\n /// 触发语言切换事件\r\n await this.emit(value) \r\n }else{\r\n throw new Error(\"Not supported language:\"+value)\r\n }\r\n }\r\n /**\r\n * 当切换语言时调用此方法来加载更新语言包\r\n * @param {*} newLanguage \r\n */\r\n async _refreshScopes(newLanguage){ \r\n // 并发执行所有作用域语言包的加载\r\n try{\r\n const scopeRefreshers = this._scopes.map(scope=>{\r\n return scope.refresh(newLanguage)\r\n })\r\n if(Promise.allSettled){\r\n await Promise.allSettled(scopeRefreshers)\r\n }else{\r\n await Promise.all(scopeRefreshers)\r\n } \r\n }catch(e){\r\n console.warn(\"Error while refreshing i18n scopes:\",e.message)\r\n } \r\n }\r\n /**\r\n * \r\n * 注册一个新的作用域\r\n * \r\n * 每一个库均对应一个作用域,每个作用域可以有多个语言包,且对应一个翻译函数\r\n * 除了默认语言外,其他语言采用动态加载的方式\r\n * \r\n * @param {*} scope \r\n */\r\n async register(scope){\r\n if(!(scope instanceof i18nScope)){\r\n throw new TypeError(\"Scope must be an instance of I18nScope\")\r\n }\r\n this._scopes.push(scope) \r\n await scope.refresh(this.activeLanguage) \r\n }\r\n /**\r\n * 注册全局格式化器\r\n * 格式化器是一个简单的同步函数value=>{...},用来对输入进行格式化后返回结果\r\n * \r\n * registerFormatters(name,value=>{...}) // 适用于所有语言\r\n * registerFormatters(name,value=>{...},{langauge:\"cn\"}) // 适用于cn语言\r\n * registerFormatters(name,value=>{...},{langauge:\"en\"}) // 适用于en语言 \r\n \r\n * @param {*} formatters \r\n */\r\n registerFormatter(name,formatter,{language=\"*\"}={}){\r\n if(!typeof(formatter)===\"function\" || typeof(name)!==\"string\"){\r\n throw new TypeError(\"Formatter must be a function\")\r\n } \r\n if(DataTypes.includes(name)){\r\n this.formatters[language].$types[name] = formatter\r\n }else{\r\n this.formatters[language][name] = formatter\r\n }\r\n }\r\n}\r\n\r\nmodule.exports ={\r\n getInterpolatedVars,\r\n replaceInterpolatedVars,\r\n I18nManager,\r\n translate,\r\n languages,\r\n i18nScope,\r\n defaultLanguageSettings,\r\n getDataTypeName,\r\n isNumber,\r\n isPlainObject \r\n}","/**\r\n * 内置的格式化器\r\n * \r\n */\r\n\r\n\r\n/**\r\n * 字典格式化器\r\n * 根据输入data的值,返回后续参数匹配的结果\r\n * dict(data,,,,,,,...)\r\n * \r\n * \r\n * dict(1,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == \"one\"\r\n * dict(2,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == \"two\"\r\n * dict(3,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == \"three\"\r\n * dict(4,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == \"four\"\r\n * // 无匹配时返回原始值\r\n * dict(5,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == 5 \r\n * // 无匹配时并且后续参数个数是奇数,则返回最后一个参数\r\n * dict(5,1,\"one\",2,\"two\",3,\"three\",4,\"four\",\"more\") == \"more\" \r\n * \r\n * 在翻译中使用\r\n * I have { value | dict(1,\"one\",2,\"two\",3,\"three\",4,\"four\")} apples\r\n * \r\n * @param {*} value \r\n * @param {...any} args \r\n * @returns \r\n */\r\n function dict(value,...args){\r\n for(let i=0;i0 && (args.length % 2!==0)) return args[args.length-1]\r\n return value\r\n}\r\n\r\nfunction formatCurrency(value,symbol,retainDots){\r\n\r\n}\r\n\r\nmodule.exports = { \r\n \"*\":{\r\n $types:{\r\n Date:(value)=>value.toLocaleString()\r\n },\r\n time:(value)=> value.toLocaleTimeString(), \r\n shorttime:(value)=> value.toLocaleTimeString(), \r\n date: (value)=> value.toLocaleDateString(), \r\n dict, //字典格式化器\r\n }, \r\n cn:{ \r\n $types:{\r\n Date:(value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日 ${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`\r\n },\r\n shortime:(value)=> value.toLocaleTimeString(), \r\n time:(value)=>`${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`, \r\n date: (value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日`,\r\n shortdate: (value)=> `${value.getFullYear()}-${value.getMonth()+1}-${value.getDate()}`,\r\n currency:(value)=>`${value}元`,\r\n },\r\n en:{\r\n currency:(value)=>{\r\n return `$${value}`\r\n }\r\n }\r\n}"],"names":["utils","obj","_typeof","proto","_Object$getPrototypeOf","baseProto","value","isNaN","_parseInt","deepMerge","toObj","formObj","_context","options","results","_Object$assign","_ref","_ref2","_slicedToArray","key","_Array$isArray","array","_context2","_concatInstanceProperty","call","_toConsumableArray","_context3","_Set","v","undefined","constructor","name","eventemitter","EventEmitter","_classCallCheck","this","_callbacks","_emit","_createClass","callback","_includesInstanceProperty","push","i","length","_spliceInstanceProperty","_asyncToGenerator","_regeneratorRuntime","mark","_callee","_len","args","_key","_context4","_args","arguments","wrap","_context5","prev","next","Array","_Promise","allSettled","_mapInstanceProperty","cb","apply","all","stop","scope","i18nScope","_id","id","Date","getTime","toString","Math","random","_languages","languages","_defaultLanguage","defaultLanguage","_activeLanguage","activeLanguage","_default","_messages","messages","_idMap","idMap","_formatters","formatters","_loaders","loaders","_global","$cache","typedFormatters","_globalThis","VoerkaI18n","I18nManager","require$$0","global","_loading","register","_refresh","get","set","then","formatter","_ref$language","language","TypeError","DataTypes","$types","newLanguage","loader","resolve","abrupt","sent","t0","console","warn","message","_fallback","_x","_bindInstanceProperty","on","off","_context6","offAll","_context7","change","getDataTypeName","isNumber","isPlainObject","require$$1","require$$2","inlineFormatters","toLocaleString","time","toLocaleTimeString","shorttime","date","toLocaleDateString","dict","cn","concat","getFullYear","getMonth","getDate","getHours","getMinutes","getSeconds","shortime","_context8","_context9","shortdate","_context10","_context11","currency","en","varWithPipeRegexp","varname","hasInterpolation","str","_String$raw","_templateObject","_taggedTemplateLiteral","parseFormatters","result","_trimInstanceProperty","substr","split","r","firstIndex","_indexOfInstanceProperty","lastIndex","_lastIndexOfInstanceProperty","argsContent","arg","_startsWithInstanceProperty","_endsWithInstanceProperty","toLowerCase","String","JSON","parse","e","forEachInterpolatedVars","match","opts","replaceAll","exec","groups","_replaceAllInstanceProperty","replace","_unused","resetScopeCache","buildFormatters","_step2","_iterator2","_createForOfIteratorHelper","_loop","func","_i2","_targets2","target","getFormatter","_v$formatter$","s","n","done","err","f","getFormattedValue","formatterFuncs","defaultFormatter","dataType","_i","_targets","getDataTypeDefaultFormatter","_step","_iterator","error","executeFormatter","replaceInterpolatedVars","template","varValues","params","Error","defaultLanguageSettings","title","default","isMessageId","content","getPluraMessage","_unused2","escape","_context12","_context13","_context14","_context15","unescape","_context16","_context17","_context18","_context19","_context20","_context21","_context22","_context23","_register","_refreshScopes2","_change","_this2","settings","_super2","instance","_assertThisInitialized","_settings","_scopes","_context28","_context29","_findIndexInstanceProperty","lang","_refreshScopes","emit","_callee2","_context30","scopeRefreshers","_context31","refresh","_callee3","_context32","_ref5","_ref5$language","runtime","getInterpolatedVars","vars","varName","varItem","varDef","translate","pluralVars","pluraValue","_context24","_context27","_forEachInstanceProperty","_Object$entries","_ref3","_ref4","_context25","_context26","_sliceInstanceProperty","prototype","index","msgId","pluralVar"],"mappings":"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"} \ No newline at end of file diff --git a/packages/runtime/dist/index.esm.js b/packages/runtime/dist/index.esm.js deleted file mode 100644 index fa09277..0000000 --- a/packages/runtime/dist/index.esm.js +++ /dev/null @@ -1,2 +0,0 @@ -import e from"@babel/runtime-corejs3/core-js-stable/weak-map";import t from"@babel/runtime-corejs3/core-js-stable/instance/reduce";import r from"@babel/runtime-corejs3/core-js-stable/object/keys";import n from"@babel/runtime-corejs3/core-js-stable/object/create";import a from"@babel/runtime-corejs3/core-js-stable/symbol/replace";import o from"@babel/runtime-corejs3/core-js-stable/array/from";import s from"@babel/runtime-corejs3/core-js-stable/symbol";import i from"@babel/runtime-corejs3/core-js/get-iterator-method";import l from"@babel/runtime-corejs3/core-js-stable/reflect/construct";import"core-js/modules/es.regexp.constructor.js";import"core-js/modules/es.regexp.dot-all.js";import"core-js/modules/es.regexp.sticky.js";import"core-js/modules/es.regexp.test.js";import"core-js/modules/es.reflect.to-string-tag.js";import c from"@babel/runtime-corejs3/helpers/asyncToGenerator";import u from"@babel/runtime-corejs3/helpers/classCallCheck";import f from"@babel/runtime-corejs3/helpers/createClass";import m from"@babel/runtime-corejs3/helpers/assertThisInitialized";import g from"@babel/runtime-corejs3/helpers/possibleConstructorReturn";import p from"@babel/runtime-corejs3/helpers/getPrototypeOf";import h from"@babel/runtime-corejs3/helpers/typeof";import b from"@babel/runtime-corejs3/helpers/toConsumableArray";import v from"@babel/runtime-corejs3/helpers/slicedToArray";import y from"@babel/runtime-corejs3/helpers/taggedTemplateLiteral";import d from"@babel/runtime-corejs3/helpers/inherits";import j from"@babel/runtime-corejs3/helpers/setPrototypeOf";import k from"@babel/runtime-corejs3/regenerator";import"core-js/modules/es.regexp.exec.js";import"core-js/modules/es.string.split.js";import"core-js/modules/es.string.substr.js";import"core-js/modules/es.function.name.js";import"core-js/modules/es.error.to-string.js";import"core-js/modules/es.date.to-string.js";import"core-js/modules/es.object.to-string.js";import"core-js/modules/es.regexp.to-string.js";import"core-js/modules/esnext.array.last-index.js";import"core-js/modules/es.string.replace.js";import"core-js/modules/es.error.cause.js";import"core-js/modules/es.array.iterator.js";import"core-js/modules/es.promise.js";import"core-js/modules/es.promise.all-settled.js";import"core-js/modules/es.string.iterator.js";import"core-js/modules/web.dom-collections.iterator.js";import w from"@babel/runtime-corejs3/core-js-stable/string/raw";import _ from"@babel/runtime-corejs3/core-js-stable/instance/includes";import x from"@babel/runtime-corejs3/core-js-stable/instance/map";import L from"@babel/runtime-corejs3/core-js-stable/instance/trim";import S from"@babel/runtime-corejs3/core-js-stable/instance/index-of";import $ from"@babel/runtime-corejs3/core-js-stable/instance/last-index-of";import M from"@babel/runtime-corejs3/core-js-stable/parse-int";import A from"@babel/runtime-corejs3/core-js-stable/instance/starts-with";import F from"@babel/runtime-corejs3/core-js-stable/instance/ends-with";import T from"@babel/runtime-corejs3/core-js-stable/instance/find-index";import E from"@babel/runtime-corejs3/core-js-stable/object/assign";import I from"@babel/runtime-corejs3/core-js/instance/replace-all";import z from"@babel/runtime-corejs3/core-js-stable/array/is-array";import"@babel/runtime-corejs3/core-js-stable/json/stringify";import D from"@babel/runtime-corejs3/core-js-stable/instance/concat";import N from"@babel/runtime-corejs3/core-js-stable/instance/splice";import C from"@babel/runtime-corejs3/core-js-stable/instance/for-each";import O from"@babel/runtime-corejs3/core-js-stable/object/entries";import V from"@babel/runtime-corejs3/core-js-stable/instance/slice";import R from"@babel/runtime-corejs3/core-js-stable/promise";import P from"@babel/runtime-corejs3/core-js-stable/object/get-prototype-of";import B from"@babel/runtime-corejs3/core-js-stable/set";import U from"@babel/runtime-corejs3/core-js/global-this";import Y from"@babel/runtime-corejs3/core-js-stable/instance/bind";var q,H=function(e){if("object"!==h(e)||null===e)return!1;var t=P(e);if(null===t)return!0;for(var r=t;null!==P(r);)r=P(r);return t===r},W=function(e){return!isNaN(M(e))},G=function e(t,r){var n,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=E({},t);return C(n=O(r)).call(n,(function(t){var r=v(t,2),n=r[0],s=r[1];if(n in o)if("object"===h(s)&&null!==s)if(z(s)){if(0===a.array)o[n]=s;else if(1===a.array){var i;o[n]=D(i=[]).call(i,b(o[n]),b(s))}else if(2===a.array){var l;o[n]=b(new B(D(l=[]).call(l,b(o[n]),b(s))))}}else o[n]=e(o[n],s,a);else o[n]=s;else o[n]=s})),o},J=function(e){return null===e?"Null":void 0===e?"Undefined":"function"==typeof e?"Function":e.constructor&&e.constructor.name},K=function(){function e(){u(this,e),this._callbacks=[]}var t;return f(e,[{key:"on",value:function(e){var t;_(t=this._callbacks).call(t,e)||this._callbacks.push(e)}},{key:"off",value:function(e){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:{},r=arguments.length>1?arguments[1]:void 0;if(u(this,e),this._id=t.id||(new Date).getTime().toString()+M(1e3*Math.random()),this._languages=t.languages,this._defaultLanguage=t.defaultLanguage||"cn",this._activeLanguage=t.activeLanguage,this._default=t.default,this._messages=t.messages,this._idMap=t.idMap,this._formatters=t.formatters,this._loaders=t.loaders,this._global=null,this.$cache={activeLanguage:null,typedFormatters:{},formatters:{}},!U.VoerkaI18n){var n=xe.I18nManager;U.VoerkaI18n=new n({defaultLanguage:this.defaultLanguage,activeLanguage:this.activeLanguage,languages:t.languages})}this.global=U.VoerkaI18n,this._loading=!1,this.register(r)}var t;return f(e,[{key:"id",get:function(){return this._id}},{key:"defaultLanguage",get:function(){return this._defaultLanguage}},{key:"activeLanguage",get:function(){return this._activeLanguage}},{key:"default",get:function(){return this._default}},{key:"messages",get:function(){return this._messages}},{key:"idMap",get:function(){return this._idMap}},{key:"formatters",get:function(){return this._formatters}},{key:"loaders",get:function(){return this._loaders}},{key:"global",get:function(){return this._global},set:function(e){this._global=e}},{key:"register",value:function(e){"function"===!h(e)&&(e=function(){}),this.global.register(this).then(e).catch(e)}},{key:"registerFormatter",value:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=r.language,a=void 0===n?"*":n;if("function"===!h(t)||"string"!=typeof e)throw new TypeError("Formatter must be a function");_(DataTypes).call(DataTypes,e)?this.formatters[a].$types[e]=t:this.formatters[a][e]=t}},{key:"_fallback",value:function(){this._messages=this._default,this._activeLanguage=this.defaultLanguage}},{key:"refresh",value:(t=c(k.mark((function e(t){var r,n,a;return k.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(this._loading=R.resolve(),t||(t=this.activeLanguage),t!==this.defaultLanguage){e.next=5;break}return this._messages=this._default,e.abrupt("return");case 5:if("function"!=typeof(r=this.loaders[t])){e.next=20;break}return e.prev=7,e.next=10,r();case 10:this._messages=e.sent.default,this._activeLanguage=t,e.next=18;break;case 14:e.prev=14,e.t0=e.catch(7),console.warn(D(n=D(a="Error while loading language <".concat(t,"> on i18nScope(")).call(a,this.id,"): ")).call(n,e.t0.message)),this._fallback();case 18:e.next=21;break;case 20:this._fallback();case 21:case"end":return e.stop()}}),e,this,[[7,14]])}))),function(e){return t.apply(this,arguments)})},{key:"on",get:function(){var e;return Y(e=this.global.on).call(e,this.global)}},{key:"off",get:function(){var e;return Y(e=this.global.off).call(e,this.global)}},{key:"offAll",get:function(){var e;return Y(e=this.global.offAll).call(e,this.global)}},{key:"change",get:function(){var e;return Y(e=this.global.change).call(e,this.global)}}]),e}();function X(e){var t=function(){if("undefined"==typeof Reflect||!l)return!1;if(l.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(l(Boolean,[],(function(){}))),!0}catch(e){return!1}}();return function(){var r,n=p(e);if(t){var a=p(this).constructor;r=l(n,arguments,a)}else r=n.apply(this,arguments);return g(this,r)}}function Z(e,t){var r=void 0!==s&&i(e)||e["@@iterator"];if(!r){if(z(e)||(r=function(e,t){var r;if(!e)return;if("string"==typeof e)return ee(e,t);var n=V(r=Object.prototype.toString.call(e)).call(r,8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return o(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ee(e,t)}(e))||t&&e&&"number"==typeof e.length){r&&(e=r);var n=0,a=function(){};return{s:a,n:function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}},e:function(e){throw e},f:a}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var l,c=!0,u=!1;return{s:function(){r=r.call(e)},n:function(){var e=r.next();return c=e.done,e},e:function(e){u=!0,l=e},f:function(){try{c||null==r.return||r.return()}finally{if(u)throw l}}}}function ee(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r]+)>/g,(function(e,t){return"$"+r[t]})))}if("function"==typeof t){var n=this;return o[a].call(this,e,(function(){var e=arguments;return"object"!=h(e[e.length-1])&&(e=V([]).call(e)).push(l(e,n)),t.apply(this,e)}))}return o[a].call(this,e,t)},te.apply(this,arguments)}var re=J,ne=W,ae=H,oe=G,se=K,ie=Q,le={"*":{$types:{Date:function(e){return e.toLocaleString()}},time:function(e){return e.toLocaleTimeString()},shorttime:function(e){return e.toLocaleTimeString()},date:function(e){return e.toLocaleDateString()},dict:function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0&&r.length%2!=0?r[r.length-1]:e}},cn:{$types:{Date:function(e){var t,r,n,a,o;return D(t=D(r=D(n=D(a=D(o="".concat(e.getFullYear(),"年")).call(o,e.getMonth()+1,"月")).call(a,e.getDate(),"日 ")).call(n,e.getHours(),"点")).call(r,e.getMinutes(),"分")).call(t,e.getSeconds(),"秒")}},shortime:function(e){return e.toLocaleTimeString()},time:function(e){var t,r;return D(t=D(r="".concat(e.getHours(),"点")).call(r,e.getMinutes(),"分")).call(t,e.getSeconds(),"秒")},date:function(e){var t,r;return D(t=D(r="".concat(e.getFullYear(),"年")).call(r,e.getMonth()+1,"月")).call(t,e.getDate(),"日")},shortdate:function(e){var t,r;return D(t=D(r="".concat(e.getFullYear(),"-")).call(r,e.getMonth()+1,"-")).call(t,e.getDate())},currency:function(e){return"".concat(e,"元")}},en:{currency:function(e){return"$".concat(e)}}},ce=te(/\{\s*(\w+)?((\s*\|\s*\w*(\(.*\))?\s*)*)\s*\}/g,{varname:1,formatters:2});function ue(e){return _(e).call(e,"{")&&_(e).call(e,"}")}w(q||(q=y(["{s*{varname}s*}"],["\\{\\s*{varname}\\s*\\}"])));var fe=["String","Number","Boolean","Object","Array","Function","Error","Symbol","RegExp","Date","Null","Undefined","Set","Map","WeakSet","WeakMap"];function me(e){var t,r;if(!e)return[];var n=x(t=L(r=L(e).call(e).substr(1)).call(r).split("|")).call(t,(function(e){return L(e).call(e)}));return x(n).call(n,(function(e){var t=S(e).call(e,"("),r=$(e).call(e,")");if(-1!==t&&-1!==r){var n,a,o=L(n=e.substr(t+1,r-t-1)).call(n),s=""==o?[]:x(a=o.split(",")).call(a,(function(e){if(e=L(e).call(e),!isNaN(M(e)))return M(e);if(A(e).call(e,'"')&&F(e).call(e,'"')||A(e).call(e,"'")&&F(e).call(e,"'"))return e.substr(1,e.length-2);if("true"===e.toLowerCase()||"false"===e.toLowerCase())return"true"===e.toLowerCase();if(!(A(e).call(e,"{")&&F(e).call(e,"}")||A(e).call(e,"[")&&F(e).call(e,"]")))return String(e);try{return JSON.parse(e)}catch(t){return String(e)}}));return[e.substr(0,t),s]}return[e,[]]}))}function ge(e,t){var r,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},a=e,o=E({replaceAll:!0},n);for(ce.lastIndex=0;null!==(r=ce.exec(a));){var s=r.groups.varname||"",i=me(r.groups.formatters);if("function"==typeof t)try{a=I(o)?I(a).call(a,r[0],t(s,i,r[0])):a.replace(r[0],t(s,i,r[0]))}catch(e){break}ce.lastIndex=0}return a}function pe(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e.$cache={activeLanguage:t,typedFormatters:{},formatters:{}}}function he(e,t,r){var n,a=[],o=Z(r);try{var s=function(){var r=n.value;if(r[0]){var o=function(e,t,r){if(e.$cache||pe(e),e.$cache.activeLanguage===t){if(r in e.$cache.formatters)return e.$cache.formatters[r]}else pe(e,t);for(var n=0,a=[e.formatters,e.global.formatters];n1?n-1:0),o=1;ol)return be(t,r,n,i[l++]);throw new Error}),{replaceAll:!1})}var ye={defaultLanguage:"cn",activeLanguage:"cn",languages:[{name:"cn",title:"中文",default:!0},{name:"en",title:"英文"}],formatters:formatters};function de(e){return M(e)>0}function je(e,t){try{return z(e)?e.length>t?e[t]:e[e.length-1]:e}catch(t){return z(e)?e[0]:e}}function ke(e){var t,r,n,a,o,s,i,l;return I(t=I(r=I(n=I(a=I(o=I(s=I(i=I(l=I(e).call(e,/\\(?![trnbvf'"]{1})/g,"\\\\")).call(l,"\t","\\t")).call(i,"\n","\\n")).call(s,"\b","\\b")).call(o,"\r","\\r")).call(a,"\f","\\f")).call(n,"'","\\'")).call(r,'"','\\"')).call(t,"\v","\\v")}function we(e){var t,r,n,a,o,s,i,l;return I(t=I(r=I(n=I(a=I(o=I(s=I(i=I(l=I(e).call(e,"\\t","\t")).call(l,"\\n","\n")).call(i,"\\b","\b")).call(s,"\\r","\r")).call(o,"\\f","\f")).call(a,"\\'","'")).call(n,'\\"','"')).call(r,"\\v","\v")).call(t,/\\\\(?![trnbvf'"]{1})/g,"\\")}var _e=function(e){d(o,se);var t,r,n,a=X(o);function o(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return u(this,o),e=a.call(this),null!=o.instance||(o.instance=m(e),e._settings=oe(ye,t),e._scopes=[]),g(e,o.instance)}return f(o,[{key:"settings",get:function(){return this._settings}},{key:"scopes",get:function(){return this._scopes}},{key:"activeLanguage",get:function(){return this._settings.activeLanguage}},{key:"defaultLanguage",get:function(){return this._settings.defaultLanguage}},{key:"languages",get:function(){return this._settings.languages}},{key:"formatters",get:function(){return le}},{key:"change",value:(n=c(k.mark((function e(t){var r;return k.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(t=L(t).call(t),-1===T(r=this.languages).call(r,(function(e){return e.name===t}))){e.next=9;break}return e.next=4,this._refreshScopes(t);case 4:return this._settings.activeLanguage=t,e.next=7,this.emit(t);case 7:e.next=10;break;case 9:throw new Error("Not supported language:"+t);case 10:case"end":return e.stop()}}),e,this)}))),function(e){return n.apply(this,arguments)})},{key:"_refreshScopes",value:(r=c(k.mark((function e(t){var r,n;return k.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(e.prev=0,n=x(r=this._scopes).call(r,(function(e){return e.refresh(t)})),!R.allSettled){e.next=7;break}return e.next=5,R.allSettled(n);case 5:e.next=9;break;case 7:return e.next=9,R.all(n);case 9:e.next=14;break;case 11:e.prev=11,e.t0=e.catch(0),console.warn("Error while refreshing i18n scopes:",e.t0.message);case 14:case"end":return e.stop()}}),e,this,[[0,11]])}))),function(e){return r.apply(this,arguments)})},{key:"register",value:(t=c(k.mark((function e(t){return k.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(t instanceof ie){e.next=2;break}throw new TypeError("Scope must be an instance of I18nScope");case 2:return this._scopes.push(t),e.next=5,t.refresh(this.activeLanguage);case 5:case"end":return e.stop()}}),e,this)}))),function(e){return t.apply(this,arguments)})},{key:"registerFormatter",value:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=r.language,a=void 0===n?"*":n;if("function"===!h(t)||"string"!=typeof e)throw new TypeError("Formatter must be a function");_(fe).call(fe,e)?this.formatters[a].$types[e]=t:this.formatters[a][e]=t}}]),o}(),xe={getInterpolatedVars:function(e){var t=[];return ge(e,(function(e,r,n){var a={name:e,formatters:x(r).call(r,(function(e){var t=v(e,2);return{name:t[0],args:t[1]}})),match:n};return-1===T(t).call(t,(function(e){return e.name===a.name&&a.formatters.toString()==e.formatters.toString()}))&&t.push(a),""})),t},replaceInterpolatedVars:ve,I18nManager:_e,translate:function(e){var t=this,r=t.global.activeLanguage,n=e,a=[],o=[],s=null;if("string"===!h(e))return e;try{var i,l;if(2===arguments.length&&ae(arguments[1]))C(i=O(arguments[1])).call(i,(function(e){var t=v(e,2),r=t[0],n=t[1];if("function"==typeof n)try{a[r]=n()}catch(e){a[r]=n}A(r).call(r,"$")&&"number"==typeof a[r]&&o.push(r)})),a=[arguments[1]];else if(arguments.length>=2){var c,u;a=x(c=N(u=V(Array.prototype).call(arguments)).call(u,1)).call(c,(function(e,t){try{e="function"==typeof e?e():e,ne(e)&&(s=M(e))}catch(e){}return e}))}if(r===t.defaultLanguage)de(n)&&(n=t.default[n]||e);else{var f=de(n)?n:t.idMap[ke(n)];n=t.messages[f]||n,n=z(n)?x(n).call(n,(function(e){return we(e)})):we(n)}return z(n)&&n.length>0&&(n=null!==s?je(n,s):pluralVar.length>0?je(n,M(a(pluralVar[0]))):n[0]),0==a.length?n:ve.call.apply(ve,D(l=[t,n]).call(l,b(a)))}catch(e){return n}},languages:["af","am","ar-dz","ar-iq","ar-kw","ar-ly","ar-ma","ar-sa","ar-tn","ar","az","be","bg","bi","bm","bn","bo","br","bs","ca","cs","cv","cy","da","de-at","de-ch","de","dv","el","en-au","en-ca","en-gb","en-ie","en-il","en-in","en-nz","en-sg","en-tt","en","eo","es-do","es-mx","es-pr","es-us","es","et","eu","fa","fi","fo","fr-ca","fr-ch","fr","fy","ga","gd","gl","gom-latn","gu","he","hi","hr","ht","hu","hy-am","id","is","it-ch","it","ja","jv","ka","kk","km","kn","ko","ku","ky","lb","lo","lt","lv","me","mi","mk","ml","mn","mr","ms-my","ms","mt","my","nb","ne","nl-be","nl","nn","oc-lnc","pa-in","pl","pt-br","pt","ro","ru","rw","sd","se","si","sk","sl","sq","sr-cyrl","sr","ss","sv-fi","sv","sw","ta","te","tet","tg","th","tk","tl-ph","tlh","tr","tzl","tzm-latn","tzm","ug-cn","uk","ur","uz-latn","uz","vi","x-pseudo","yo","zh-cn","zh-hk","zh-tw","zh"],i18nScope:ie,defaultLanguageSettings:ye,getDataTypeName:re,isNumber:ne,isPlainObject:ae};export{xe as default}; -//# sourceMappingURL=index.esm.js.map diff --git a/packages/runtime/dist/index.esm.js.map b/packages/runtime/dist/index.esm.js.map deleted file mode 100644 index 15e3fd7..0000000 --- a/packages/runtime/dist/index.esm.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.esm.js","sources":["../utils.js","../eventemitter.js","../scope.js","../index.js","../formatters.js"],"sourcesContent":["\r\n/**\r\n * 判断是否是JSON对象\r\n * @param {*} obj \r\n * @returns \r\n */\r\n function isPlainObject(obj){\r\n if (typeof obj !== 'object' || obj === null) return false;\r\n var proto = Object.getPrototypeOf(obj);\r\n if (proto === null) return true;\r\n var baseProto = proto;\r\n\r\n while (Object.getPrototypeOf(baseProto) !== null) {\r\n baseProto = Object.getPrototypeOf(baseProto);\r\n }\r\n return proto === baseProto; \r\n}\r\n\r\nfunction isNumber(value){\r\n return !isNaN(parseInt(value))\r\n}\r\n \r\n/**\r\n * 简单进行对象合并\r\n * \r\n * options={\r\n * array:0 , // 数组合并策略,0-替换,1-合并,2-去重合并\r\n * }\r\n * \r\n * @param {*} toObj \r\n * @param {*} formObj \r\n * @returns 合并后的对象\r\n */\r\nfunction deepMerge(toObj,formObj,options={}){\r\n let results = Object.assign({},toObj)\r\n Object.entries(formObj).forEach(([key,value])=>{\r\n if(key in results){\r\n if(typeof value === \"object\" && value !== null){\r\n if(Array.isArray(value)){\r\n if(options.array === 0){\r\n results[key] = value\r\n }else if(options.array === 1){\r\n results[key] = [...results[key],...value]\r\n }else if(options.array === 2){\r\n results[key] = [...new Set([...results[key],...value])]\r\n }\r\n }else{\r\n results[key] = deepMerge(results[key],value,options)\r\n }\r\n }else{\r\n results[key] = value\r\n }\r\n }else{\r\n results[key] = value\r\n }\r\n })\r\n return results\r\n}\r\n\r\n\r\n/**\r\n * 获取指定变量类型名称\r\n * getDataTypeName(1) == Number\r\n * getDataTypeName(\"\") == String\r\n * getDataTypeName(null) == Null\r\n * getDataTypeName(undefined) == Undefined\r\n * getDataTypeName(new Date()) == Date\r\n * getDataTypeName(new Error()) == Error\r\n * \r\n * @param {*} v \r\n * @returns \r\n */\r\n function getDataTypeName(v){\r\n\tif (v === null) return 'Null' \r\n\tif (v === undefined) return 'Undefined' \r\n if(typeof(v)===\"function\") return \"Function\"\r\n\treturn v.constructor && v.constructor.name;\r\n};\r\n\r\n\r\n\r\n\r\n\r\nmodule.exports ={\r\n isPlainObject,\r\n isNumber,\r\n deepMerge,\r\n getDataTypeName\r\n}","/**\r\n* \r\n* 简单的事件触发器\r\n* \r\n*/\r\nmodule.exports = class EventEmitter{\r\n constructor(){\r\n this._callbacks = []\r\n }\r\n on(callback){\r\n if(this._callbacks.includes(callback)) return\r\n this._callbacks.push(callback)\r\n }\r\n off(callback){\r\n for(let i=0;icb(...args)))\r\n }else{\r\n await Promise.all(this._callbacks.map(cb=>cb(...args)))\r\n }\r\n } \r\n}","\r\nmodule.exports = class i18nScope {\r\n constructor(options={},callback){\r\n // 每个作用域都有一个唯一的id\r\n this._id = options.id || (new Date().getTime().toString()+parseInt(Math.random()*1000))\r\n this._languages = options.languages // 当前作用域的语言列表\r\n this._defaultLanguage = options.defaultLanguage || \"cn\" // 默认语言名称\r\n this._activeLanguage = options.activeLanguage // 当前语言名称\r\n this._default = options.default // 默认语言包\r\n this._messages = options.messages // 当前语言包\r\n this._idMap = options.idMap // 消息id映射列表\r\n this._formatters = options.formatters // 当前作用域的格式化函数列表\r\n this._loaders = options.loaders // 异步加载语言文件的函数列表\r\n this._global = null // 引用全局VoerkaI18n配置,注册后自动引用 \r\n // 主要用来缓存格式化器的引用,当使用格式化器时可以直接引用,避免检索\r\n this.$cache={\r\n activeLanguage : null,\r\n typedFormatters: {},\r\n formatters : {},\r\n }\r\n // 如果不存在全局VoerkaI18n实例,说明当前Scope是唯一或第一个加载的作用域,\r\n // 则使用当前作用域来初始化全局VoerkaI18n实例\r\n if(!globalThis.VoerkaI18n){\r\n const { I18nManager } = require(\"./\")\r\n globalThis.VoerkaI18n = new I18nManager({\r\n defaultLanguage: this.defaultLanguage,\r\n activeLanguage : this.activeLanguage,\r\n languages: options.languages,\r\n })\r\n }\r\n this.global = globalThis.VoerkaI18n \r\n // 正在加载语言包标识\r\n this._loading=false\r\n // 在全局注册作用域\r\n this.register(callback)\r\n }\r\n // 作用域\r\n get id(){return this._id}\r\n // 默认语言名称\r\n get defaultLanguage(){return this._defaultLanguage}\r\n // 默认语言名称\r\n get activeLanguage(){return this._activeLanguage}\r\n // 默认语言包\r\n get default(){return this._default}\r\n // 当前语言包\r\n get messages(){return this._messages}\r\n // 消息id映射列表\r\n get idMap(){return this._idMap}\r\n // 当前作用域的格式化函数列表\r\n get formatters(){return this._formatters}\r\n // 异步加载语言文件的函数列表\r\n get loaders(){return this._loaders}\r\n // 引用全局VoerkaI18n配置,注册后自动引用\r\n get global(){return this._global}\r\n set global(value){this._global = value}\r\n /**\r\n * 在全局注册作用域\r\n * @param {*} callback 当注册\r\n */\r\n register(callback){\r\n if(!typeof(callback)===\"function\") callback = ()=>{} \r\n this.global.register(this).then(callback).catch(callback) \r\n }\r\n registerFormatter(name,formatter,{language=\"*\"}={}){\r\n if(!typeof(formatter)===\"function\" || typeof(name)!==\"string\"){\r\n throw new TypeError(\"Formatter must be a function\")\r\n } \r\n if(DataTypes.includes(name)){\r\n this.formatters[language].$types[name] = formatter\r\n }else{\r\n this.formatters[language][name] = formatter\r\n }\r\n }\r\n /**\r\n * 回退到默认语言\r\n */\r\n _fallback(){\r\n this._messages = this._default \r\n this._activeLanguage = this.defaultLanguage\r\n }\r\n /**\r\n * 刷新当前语言包\r\n * @param {*} newLanguage \r\n */\r\n async refresh(newLanguage){\r\n this._loading = Promise.resolve()\r\n if(!newLanguage) newLanguage = this.activeLanguage\r\n // 默认语言,默认语言采用静态加载方式,只需要简单的替换即可\r\n if(newLanguage === this.defaultLanguage){\r\n this._messages = this._default\r\n return \r\n }\r\n // 非默认语言需要异步加载语言包文件,加载器是一个异步函数\r\n // 如果没有加载器,则无法加载语言包,因此回退到默认语言\r\n const loader = this.loaders[newLanguage]\r\n if(typeof(loader) === \"function\"){\r\n try{\r\n this._messages = (await loader()).default\r\n this._activeLanguage = newLanguage\r\n }catch(e){\r\n console.warn(`Error while loading language <${newLanguage}> on i18nScope(${this.id}): ${e.message}`)\r\n this._fallback()\r\n } \r\n }else{\r\n this._fallback()\r\n } \r\n }\r\n // 以下方法引用全局VoerkaI18n实例的方法\r\n get on(){return this.global.on.bind(this.global)}\r\n get off(){return this.global.off.bind(this.global)}\r\n get offAll(){return this.global.offAll.bind(this.global)}\r\n get change(){\r\n return this.global.change.bind(this.global)\r\n }\r\n}","const { getDataTypeName,isNumber,isPlainObject,deepMerge } = require(\"./utils\")\r\nconst EventEmitter = require(\"./eventemitter\")\r\nconst i18nScope = require(\"./scope.js\")\r\nlet inlineFormatters = require(\"./formatters\") // 内置格式化器\r\n\r\n\r\n\r\n// 用来提取字符里面的插值变量参数 , 支持管道符 { var | formatter | formatter }\r\n// 不支持参数: let varWithPipeRegexp = /\\{\\s*(?\\w+)?(?(\\s*\\|\\s*\\w*\\s*)*)\\s*\\}/g\r\n\r\n// 支持参数: { var | formatter(x,x,..) | formatter }\r\nlet varWithPipeRegexp = /\\{\\s*(?\\w+)?(?(\\s*\\|\\s*\\w*(\\(.*\\)){0,1}\\s*)*)\\s*\\}/g\r\n\r\n// 有效的语言名称列表\r\nconst languages = [\"af\",\"am\",\"ar-dz\",\"ar-iq\",\"ar-kw\",\"ar-ly\",\"ar-ma\",\"ar-sa\",\"ar-tn\",\"ar\",\"az\",\"be\",\"bg\",\"bi\",\"bm\",\"bn\",\"bo\",\"br\",\"bs\",\"ca\",\"cs\",\"cv\",\"cy\",\"da\",\"de-at\",\"de-ch\",\"de\",\"dv\",\"el\",\"en-au\",\"en-ca\",\"en-gb\",\"en-ie\",\"en-il\",\"en-in\",\"en-nz\",\"en-sg\",\"en-tt\",\"en\",\"eo\",\"es-do\",\"es-mx\",\"es-pr\",\"es-us\",\"es\",\"et\",\"eu\",\"fa\",\"fi\",\"fo\",\"fr-ca\",\"fr-ch\",\"fr\",\"fy\",\"ga\",\"gd\",\"gl\",\"gom-latn\",\"gu\",\"he\",\"hi\",\"hr\",\"ht\",\"hu\",\"hy-am\",\"id\",\"is\",\"it-ch\",\"it\",\"ja\",\"jv\",\"ka\",\"kk\",\"km\",\"kn\",\"ko\",\"ku\",\"ky\",\"lb\",\"lo\",\"lt\",\"lv\",\"me\",\"mi\",\"mk\",\"ml\",\"mn\",\"mr\",\"ms-my\",\"ms\",\"mt\",\"my\",\"nb\",\"ne\",\"nl-be\",\"nl\",\"nn\",\"oc-lnc\",\"pa-in\",\"pl\",\"pt-br\",\"pt\",\"ro\",\"ru\",\"rw\",\"sd\",\"se\",\"si\",\"sk\",\"sl\",\"sq\",\"sr-cyrl\",\"sr\",\"ss\",\"sv-fi\",\"sv\",\"sw\",\"ta\",\"te\",\"tet\",\"tg\",\"th\",\"tk\",\"tl-ph\",\"tlh\",\"tr\",\"tzl\",\"tzm-latn\",\"tzm\",\"ug-cn\",\"uk\",\"ur\",\"uz-latn\",\"uz\",\"vi\",\"x-pseudo\",\"yo\",\"zh-cn\",\"zh-hk\",\"zh-tw\",\"zh\"]\r\n\r\n\r\n// 插值变量字符串替换正则\r\n\r\n//let varReplaceRegexp =String.raw`\\{\\s*(?{name}\\.?\\w*)\\s*\\}`\r\n\r\n\r\nlet varReplaceRegexp =String.raw`\\{\\s*{varname}\\s*\\}`\r\n\r\n/**\r\n * 考虑到通过正则表达式进行插件的替换可能较慢,因此提供一个简单方法来过滤掉那些\r\n * 不需要进行插值处理的字符串\r\n * 原理很简单,就是判断一下是否同时具有{和}字符,如果有则认为可能有插值变量,如果没有则一定没有插件变量,则就不需要进行正则匹配\r\n * 从而可以减少不要的正则匹配\r\n * 注意:该方法只能快速判断一个字符串不包括插值变量\r\n * @param {*} str \r\n * @returns {boolean} true=可能包含插值变量,\r\n */\r\nfunction hasInterpolation(str){\r\n return str.includes(\"{\") && str.includes(\"}\")\r\n} \r\nconst DataTypes = [\"String\",\"Number\",\"Boolean\",\"Object\",\"Array\",\"Function\",\"Error\",\"Symbol\",\"RegExp\",\"Date\",\"Null\",\"Undefined\",\"Set\",\"Map\",\"WeakSet\",\"WeakMap\"]\r\n \r\n\r\n/**\r\n 通过正则表达式对原始文本内容进行解析匹配后得到的\r\n formatters=\"| aaa(1,1) | bbb \"\r\n\r\n 需要统一解析为\r\n\r\n [\r\n [aaa,[1,1]], // [formatter'name,[args,...]]\r\n [bbb,[]],\r\n ]\r\n\r\n formatters=\"| aaa(1,1,\"dddd\") | bbb \"\r\n\r\n 目前对参数采用简单的split(\",\")来解析,因为无法正确解析aaa(1,1,\"dd,,dd\")形式的参数\r\n 在此场景下基本够用了,如果需要支持更复杂的参数解析,可以后续考虑使用正则表达式来解析\r\n \r\n @returns [[,[,,...]]]\r\n */\r\nfunction parseFormatters(formatters){\r\n if(!formatters) return []\r\n // 1. 先解析为 [\"aaa()\",\"bbb\"]形式\r\n let result = formatters.trim().substr(1).trim().split(\"|\").map(r=>r.trim()) \r\n\r\n // 2. 解析格式化器参数\r\n return result.map(formatter=>{\r\n let firstIndex = formatter.indexOf(\"(\")\r\n let lastIndex = formatter.lastIndexOf(\")\")\r\n if(firstIndex!==-1 && lastIndex!==-1){ // 带参数的格式化器\r\n const argsContent = formatter.substr(firstIndex+1,lastIndex-firstIndex-1).trim()\r\n let args = argsContent==\"\" ? [] : argsContent.split(\",\").map(arg=>{\r\n arg = arg.trim()\r\n if(!isNaN(parseInt(arg))){\r\n return parseInt(arg) // 数字\r\n }else if((arg.startsWith('\\\"') && arg.endsWith('\\\"')) || (arg.startsWith('\\'') && arg.endsWith('\\'')) ){\r\n return arg.substr(1,arg.length-2) // 字符串\r\n }else if(arg.toLowerCase()===\"true\" || arg.toLowerCase()===\"false\"){\r\n return arg.toLowerCase()===\"true\" // 布尔值\r\n }else if((arg.startsWith('{') && arg.endsWith('}')) || (arg.startsWith('[') && arg.endsWith(']'))){ \r\n try{\r\n return JSON.parse(arg)\r\n }catch(e){\r\n return String(arg)\r\n }\r\n }else{\r\n return String(arg)\r\n }\r\n })\r\n return [formatter.substr(0,firstIndex),args]\r\n }else{// 不带参数的格式化器\r\n return [formatter,[]]\r\n } \r\n }) \r\n}\r\n\r\n/** \r\n * 提取字符串中的插值变量\r\n * // [\r\n // { \r\n name:<变量名称>,formatters:[{name:<格式化器名称>,args:[<参数>,<参数>,....]]}],<匹配字符串>],\r\n // ....\r\n // \r\n * @param {*} str \r\n * @param {*} isFull =true 保留所有插值变量 =false 进行去重\r\n * @returns {Array} \r\n * [\r\n * {\r\n * name:\"<变量名称>\",\r\n * formatters:[\r\n * {name:\"<格式化器名称>\",args:[<参数>,<参数>,....]},\r\n * {name:\"<格式化器名称>\",args:[<参数>,<参数>,....]},\r\n * ],\r\n * match:\"<匹配字符串>\"\r\n * },\r\n * ...\r\n * ]\r\n */\r\nfunction getInterpolatedVars(str){\r\n let vars = []\r\n forEachInterpolatedVars(str,(varName,formatters,match)=>{\r\n let varItem = {\r\n name:varName,\r\n formatters:formatters.map(([formatter,args])=>{\r\n return {\r\n name:formatter,\r\n args:args\r\n }\r\n }),\r\n match:match\r\n }\r\n if(vars.findIndex(varDef=>((varDef.name===varItem.name) && (varItem.formatters.toString() == varDef.formatters.toString())))===-1){\r\n vars.push(varItem) \r\n }\r\n return \"\"\r\n }) \r\n return vars\r\n}\r\n/**\r\n * 遍历str中的所有插值变量传递给callback,将callback返回的结果替换到str中对应的位置\r\n * @param {*} str \r\n * @param {Function(<变量名称>,[formatters],match[0])} callback \r\n * @returns 返回替换后的字符串\r\n */\r\nfunction forEachInterpolatedVars(str,callback,options={}){\r\n let result=str, match \r\n let opts = Object.assign({\r\n replaceAll:true, // 是否替换所有插值变量,当使用命名插值时应置为true,当使用位置插值时应置为false\r\n },options)\r\n varWithPipeRegexp.lastIndex=0\r\n while ((match = varWithPipeRegexp.exec(result)) !== null) {\r\n const varname = match.groups.varname || \"\"\r\n // 解析格式化器和参数 = [,[,[,,...]]]\r\n const formatters = parseFormatters(match.groups.formatters)\r\n if(typeof(callback)===\"function\"){\r\n try{\r\n if(opts.replaceAll){\r\n result=result.replaceAll(match[0],callback(varname,formatters,match[0]))\r\n }else{\r\n result=result.replace(match[0],callback(varname,formatters,match[0]))\r\n } \r\n }catch{// callback函数可能会抛出异常,如果抛出异常,则中断匹配过程\r\n break \r\n } \r\n }\r\n varWithPipeRegexp.lastIndex=0\r\n }\r\n return result\r\n}\r\n/**\r\n * 将要翻译内容提供了一个非文本内容时进行默认的转换\r\n * - 对函数则执行并取返回结果()\r\n * - 对Array和Object使用JSON.stringify\r\n * - 其他类型使用toString\r\n * \r\n * @param {*} value \r\n * @returns \r\n */\r\nfunction transformToString(value){\r\n let result = value\r\n if(typeof(result)===\"function\") result = value()\r\n if(!(typeof(result)===\"string\")){\r\n if(Array.isArray(result) || isPlainObject(result)){\r\n result = JSON.stringify(result)\r\n }else{\r\n result = result.toString()\r\n }\r\n }\r\n return result\r\n}\r\n\r\nfunction resetScopeCache(scope,activeLanguage=null){\r\n scope.$cache = {activeLanguage,typedFormatters:{},formatters:{}}\r\n}\r\n/**\r\n * 取得指定数据类型的默认格式化器 \r\n * \r\n * 可以为每一个数据类型指定一个默认的格式化器,当传入插值变量时,\r\n * 会自动调用该格式化器来对值进行格式化转换\r\n \r\n const formatters = { \r\n \"*\":{\r\n $types:{...} // 在所有语言下只作用于特定数据类型的格式化器\r\n }, // 在所有语言下生效的格式化器 \r\n cn:{ \r\n $types:{ \r\n [数据类型]:(value)=>{...},\r\n }, \r\n [格式化器名称]:(value)=>{...},\r\n [格式化器名称]:(value)=>{...},\r\n [格式化器名称]:(value)=>{...},\r\n },\r\n }\r\n * @param {*} scope \r\n * @param {*} activeLanguage \r\n * @param {*} dataType 数字类型\r\n * @returns {Function} 格式化函数 \r\n */\r\nfunction getDataTypeDefaultFormatter(scope,activeLanguage,dataType){\r\n if(!scope.$cache) resetScopeCache(scope)\r\n if(scope.$cache.activeLanguage === activeLanguage) {\r\n if(dataType in scope.$cache.typedFormatters) return scope.$cache.typedFormatters[dataType]\r\n }else{// 当语言切换时清空缓存\r\n resetScopeCache(scope,activeLanguage)\r\n }\r\n\r\n // 先在当前作用域中查找,再在全局查找\r\n const targets = [scope.formatters,scope.global.formatters] \r\n for(const target of targets){\r\n if(!target) continue\r\n // 优先在当前语言的$types中查找\r\n if((activeLanguage in target) && isPlainObject(target[activeLanguage].$types)){ \r\n let formatters = target[activeLanguage].$types \r\n if(dataType in formatters && typeof(formatters[dataType])===\"function\"){ \r\n return scope.$cache.typedFormatters[dataType] = formatters[dataType]\r\n } \r\n }\r\n // 在所有语言的$types中查找\r\n if((\"*\" in target) && isPlainObject(target[\"*\"].$types)){\r\n let formatters = target[\"*\"].$types \r\n if(dataType in formatters && typeof(formatters[dataType])===\"function\"){ \r\n return scope.$cache.typedFormatters[dataType] = formatters[dataType]\r\n } \r\n } \r\n } \r\n}\r\n\r\n/**\r\n * 获取指定名称的格式化器函数\r\n * @param {*} scope \r\n * @param {*} activeLanguage \r\n * @param {*} name 格式化器名称\r\n * @returns {Function} 格式化函数 \r\n */ \r\nfunction getFormatter(scope,activeLanguage,name){\r\n // 缓存格式化器引用,避免重复检索\r\n if(!scope.$cache) resetScopeCache(scope)\r\n if(scope.$cache.activeLanguage === activeLanguage) {\r\n if(name in scope.$cache.formatters) return scope.$cache.formatters[name]\r\n }else{// 当语言切换时清空缓存\r\n resetScopeCache(scope,activeLanguage)\r\n }\r\n // 先在当前作用域中查找,再在全局查找\r\n const targets = [scope.formatters,scope.global.formatters] \r\n for(const target of targets){\r\n // 优先在当前语言查找\r\n if(activeLanguage in target){ \r\n let formatters = target[activeLanguage] || {} \r\n if((name in formatters) && typeof(formatters[name])===\"function\") return scope.$cache.formatters[name] = formatters[name]\r\n }\r\n // 在所有语言的$types中查找\r\n let formatters = target[\"*\"] || {} \r\n if((name in formatters) && typeof(formatters[name])===\"function\") return scope.$cache.formatters[name] = formatters[name]\r\n } \r\n}\r\n\r\n/**\r\n * 执行格式化器并返回结果\r\n * @param {*} value \r\n * @param {*} formatters 多个格式化器顺序执行,前一个输出作为下一个格式化器的输入\r\n */\r\nfunction executeFormatter(value,formatters){\r\n if(formatters.length===0) return value\r\n let result = value\r\n try{\r\n for(let formatter of formatters){\r\n if(typeof(formatter) === \"function\") {\r\n result = formatter(result)\r\n }else{// 如果碰到无效的格式化器,则跳过过续的格式化器\r\n return result \r\n }\r\n }\r\n }catch(e){\r\n console.error(`Error while execute i18n formatter for ${value}: ${e.message} ` )\r\n } \r\n return result\r\n}\r\n/**\r\n * 将 [[格式化器名称,[参数,参数,...]],[格式化器名称,[参数,参数,...]]]格式化器转化为\r\n * \r\n * \r\n * \r\n * @param {*} scope \r\n * @param {*} activeLanguage \r\n * @param {*} formatters \r\n */\r\nfunction buildFormatters(scope,activeLanguage,formatters){\r\n let results = [] \r\n for(let formatter of formatters){\r\n if(formatter[0]){\r\n const func = getFormatter(scope,activeLanguage,formatter[0])\r\n if(typeof(func)===\"function\"){\r\n results.push((v)=>{\r\n return func(v,...formatter[1])\r\n })\r\n }else{\r\n // 格式化器无效或者没有定义时,查看当前值是否具有同名的原型方法,如果有则执行调用\r\n // 比如padStart格式化器是String的原型方法,不需要配置就可以直接作为格式化器调用\r\n results.push((v)=>{\r\n if(typeof(v[formatter[0]])===\"function\"){\r\n return v[formatter[0]].call(v,...formatter[1])\r\n }else{\r\n return v\r\n } \r\n }) \r\n } \r\n }\r\n }\r\n return results\r\n} \r\n\r\n/**\r\n * 将value经过格式化器处理后返回\r\n * @param {*} scope \r\n * @param {*} activeLanguage \r\n * @param {*} formatters \r\n * @param {*} value \r\n * @returns \r\n */\r\nfunction getFormattedValue(scope,activeLanguage,formatters,value){\r\n // 1. 取得格式化器函数列表\r\n const formatterFuncs = buildFormatters(scope,activeLanguage,formatters) \r\n // 2. 查找每种数据类型默认格式化器,并添加到formatters最前面,默认数据类型格式化器优先级最高\r\n const defaultFormatter = getDataTypeDefaultFormatter(scope,activeLanguage,getDataTypeName(value)) \r\n if(defaultFormatter){\r\n formatterFuncs.splice(0,0,defaultFormatter)\r\n } \r\n // 3. 执行格式化器\r\n value = executeFormatter(value,formatterFuncs) \r\n return value\r\n}\r\n\r\n/**\r\n * 字符串可以进行变量插值替换,\r\n * replaceInterpolatedVars(\"<模板字符串>\",{变量名称:变量值,变量名称:变量值,...})\r\n * replaceInterpolatedVars(\"<模板字符串>\",[变量值,变量值,...])\r\n * replaceInterpolatedVars(\"<模板字符串>\",变量值,变量值,...])\r\n * \r\n- 当只有两个参数并且第2个参数是{}时,将第2个参数视为命名变量的字典\r\n replaceInterpolatedVars(\"this is {a}+{b},{a:1,b:2}) --> this is 1+2\r\n- 当只有两个参数并且第2个参数是[]时,将第2个参数视为位置参数\r\n replaceInterpolatedVars\"this is {}+{}\",[1,2]) --> this is 1+2\r\n- 普通位置参数替换\r\n replaceInterpolatedVars(\"this is {a}+{b}\",1,2) --> this is 1+2\r\n- \r\nthis == scope == { formatters: {}, ... }\r\n* @param {*} template \r\n* @returns \r\n*/\r\nfunction replaceInterpolatedVars(template,...args) {\r\n const scope = this\r\n // 当前激活语言\r\n const activeLanguage = scope.global.activeLanguage \r\n let result=template\r\n\r\n // 没有变量插值则的返回原字符串 \r\n if(args.length===0 || !hasInterpolation(template)) return template \r\n\r\n // ****************************变量插值****************************\r\n if(args.length===1 && isPlainObject(args[0])){ \r\n // 读取模板字符串中的插值变量列表\r\n // [[var1,[formatter,formatter,...],match],[var2,[formatter,formatter,...],match],...}\r\n let varValues = args[0]\r\n return forEachInterpolatedVars(template,(varname,formatters)=>{\r\n let value = (varname in varValues) ? varValues[varname] : ''\r\n return getFormattedValue(scope,activeLanguage,formatters,value) \r\n }) \r\n }else{ \r\n // ****************************位置插值****************************\r\n // 如果只有一个Array参数,则认为是位置变量列表,进行展开\r\n const params=(args.length===1 && Array.isArray(args[0])) ? [...args[0]] : args \r\n if(params.length===0) return template // 没有变量则不需要进行插值处理,返回原字符串 \r\n let i = 0\r\n return forEachInterpolatedVars(template,(varname,formatters)=>{\r\n if(params.length>i){ \r\n return getFormattedValue(scope,activeLanguage,formatters,params[i++]) \r\n }else{\r\n throw new Error() // 抛出异常,停止插值处理\r\n }\r\n },{replaceAll:false})\r\n \r\n }\r\n return result\r\n} \r\n\r\n// 默认语言配置\r\nconst defaultLanguageSettings = { \r\n defaultLanguage: \"cn\",\r\n activeLanguage: \"cn\",\r\n languages:[\r\n {name:\"cn\",title:\"中文\",default:true},\r\n {name:\"en\",title:\"英文\"}\r\n ],\r\n formatters\r\n}\r\n\r\nfunction isMessageId(content){\r\n return parseInt(content)>0\r\n}\r\n/**\r\n * 根据值的单数和复数形式,从messages中取得相应的消息\r\n * \r\n * @param {*} messages 复数形式的文本内容 = [<=0时的内容>,<=1时的内容>,<=2时的内容>,...]\r\n * @param {*} value \r\n */\r\nfunction getPluraMessage(messages,value){\r\n try{\r\n if(Array.isArray(messages)){\r\n return messages.length > value ? messages[value] : messages[messages.length-1]\r\n }else{\r\n return messages\r\n }\r\n }catch{\r\n return Array.isArray(messages) ? messages[0] : messages\r\n }\r\n}\r\nfunction escape(str){\r\n return str.replaceAll(/\\\\(?![trnbvf'\"]{1})/g,\"\\\\\\\\\")\r\n .replaceAll(\"\\t\",\"\\\\t\")\r\n .replaceAll(\"\\n\",\"\\\\n\")\r\n .replaceAll(\"\\b\",\"\\\\b\")\r\n .replaceAll(\"\\r\",\"\\\\r\")\r\n .replaceAll(\"\\f\",\"\\\\f\")\r\n .replaceAll(\"\\'\",\"\\\\'\")\r\n .replaceAll('\\\"','\\\\\"')\r\n .replaceAll('\\v','\\\\v') \r\n}\r\nfunction unescape(str){\r\n return str\r\n .replaceAll(\"\\\\t\",\"\\t\")\r\n .replaceAll(\"\\\\n\",\"\\n\")\r\n .replaceAll(\"\\\\b\",\"\\b\")\r\n .replaceAll(\"\\\\r\",\"\\r\")\r\n .replaceAll(\"\\\\f\",\"\\f\")\r\n .replaceAll(\"\\\\'\",\"\\'\")\r\n .replaceAll('\\\\\"','\\\"')\r\n .replaceAll('\\\\v','\\v') \r\n .replaceAll(/\\\\\\\\(?![trnbvf'\"]{1})/g,\"\\\\\")\r\n}\r\n/**\r\n * 翻译函数\r\n * \r\n* translate(\"要翻译的文本内容\") 如果默认语言是中文,则不会进行翻译直接返回\r\n* translate(\"I am {} {}\",\"man\") == I am man 位置插值\r\n* translate(\"I am {p}\",{p:\"man\"}) 字典插值\r\n* translate(\"total {$count} items\", {$count:1}) //复数形式 \r\n* translate(\"total {} {} {} items\",a,b,c) // 位置变量插值\r\n * \r\n * this===scope 当前绑定的scope\r\n * \r\n */\r\nfunction translate(message) { \r\n const scope = this\r\n const activeLanguage = scope.global.activeLanguage \r\n let content = message\r\n let vars=[] // 插值变量列表\r\n let pluralVars= [] // 复数变量\r\n let pluraValue = null // 复数值\r\n if(!typeof(message)===\"string\") return message\r\n try{\r\n // 1. 预处理变量: 复数变量保存至pluralVars中 , 变量如果是Function则调用 \r\n if(arguments.length === 2 && isPlainObject(arguments[1])){\r\n Object.entries(arguments[1]).forEach(([name,value])=>{\r\n if(typeof(value)===\"function\"){\r\n try{\r\n vars[name] = value()\r\n }catch(e){\r\n vars[name] = value\r\n }\r\n } \r\n // 以$开头的视为复数变量\r\n if(name.startsWith(\"$\") && typeof(vars[name])===\"number\") pluralVars.push(name)\r\n })\r\n vars = [arguments[1]]\r\n }else if(arguments.length >= 2){\r\n vars = [...arguments].splice(1).map((arg,index)=>{\r\n try{\r\n arg = typeof(arg)===\"function\" ? arg() : arg \r\n // 位置参数中以第一个数值变量为复数变量\r\n if(isNumber(arg)) pluraValue = parseInt(arg) \r\n }catch(e){ }\r\n return arg \r\n })\r\n \r\n }\r\n \r\n \r\n \r\n\r\n // 3. 取得翻译文本模板字符串\r\n if(activeLanguage === scope.defaultLanguage){\r\n // 2.1 从默认语言中取得翻译文本模板字符串\r\n // 如果当前语言就是默认语言,不需要查询加载,只需要做插值变换即可\r\n // 当源文件运用了babel插件后会将原始文本内容转换为msgId\r\n // 如果是msgId则从scope.default中读取,scope.default=默认语言包={:}\r\n if(isMessageId(content)){\r\n content = scope.default[content] || message\r\n }\r\n }else{ \r\n // 2.2 从当前语言包中取得翻译文本模板字符串\r\n // 如果没有启用babel插件将源文本转换为msgId,需要先将文本内容转换为msgId\r\n // JSON.stringify在进行转换时会将\\t\\n\\r转换为\\\\t\\\\n\\\\r,这样在进行匹配时就出错 \r\n let msgId = isMessageId(content) ? content : scope.idMap[escape(content)] \r\n content = scope.messages[msgId] || content\r\n content = Array.isArray(content) ? content.map(v=>unescape(v)) : unescape(content)\r\n }\r\n // 2. 处理复数\r\n // 经过上面的处理,content可能是字符串或者数组\r\n // content = \"原始文本内容\" || 复数形式[\"原始文本内容\",\"原始文本内容\"....]\r\n // 如果是数组说明要启用复数机制,需要根据插值变量中的某个变量来判断复数形式\r\n if(Array.isArray(content) && content.length>0){\r\n // 如果存在复数命名变量,只取第一个复数变量\r\n if(pluraValue!==null){ // 启用的是位置插值,pluraIndex=第一个数字变量的位置\r\n content = getPluraMessage(content,pluraValue)\r\n }else if(pluralVar.length>0){\r\n content = getPluraMessage(content,parseInt(vars(pluralVar[0])))\r\n }else{ // 如果找不到复数变量,则使用第一个内容\r\n content = content[0]\r\n }\r\n } \r\n \r\n // 进行插值处理\r\n if(vars.length==0){\r\n return content\r\n }else{\r\n return replaceInterpolatedVars.call(scope,content,...vars)\r\n } \r\n }catch(e){\r\n return content // 出错则返回原始文本\r\n } \r\n}\r\n \r\n/** \r\n * 多语言管理类\r\n * \r\n * 当导入编译后的多语言文件时(import(\"./languages\")),会自动生成全局实例VoerkaI18n\r\n * \r\n * VoerkaI18n.languages // 返回支持的语言列表\r\n * VoerkaI18n.defaultLanguage // 默认语言\r\n * VoerkaI18n.language // 当前语言\r\n * VoerkaI18n.change(language) // 切换到新的语言 \r\n * \r\n * \r\n * VoerkaI18n.on(\"change\",(language)=>{}) // 注册语言切换事件\r\n * VoerkaI18n.off(\"change\",(language)=>{}) \r\n * \r\n * */ \r\n class I18nManager extends EventEmitter{\r\n constructor(settings={}){\r\n super()\r\n if(I18nManager.instance!=null){\r\n return I18nManager.instance;\r\n }\r\n I18nManager.instance = this;\r\n this._settings = deepMerge(defaultLanguageSettings,settings)\r\n this._scopes=[] \r\n return I18nManager.instance;\r\n }\r\n get settings(){ return this._settings }\r\n get scopes(){ return this._scopes }\r\n // 当前激活语言\r\n get activeLanguage(){ return this._settings.activeLanguage}\r\n // 默认语言\r\n get defaultLanguage(){ return this._settings.defaultLanguage}\r\n // 支持的语言列表\r\n get languages(){ return this._settings.languages}\r\n // 内置格式化器\r\n get formatters(){ return inlineFormatters }\r\n /**\r\n * 切换语言\r\n */\r\n async change(value){\r\n value=value.trim()\r\n if(this.languages.findIndex(lang=>lang.name === value)!==-1){\r\n // 通知所有作用域刷新到对应的语言包\r\n await this._refreshScopes(value)\r\n this._settings.activeLanguage = value\r\n /// 触发语言切换事件\r\n await this.emit(value) \r\n }else{\r\n throw new Error(\"Not supported language:\"+value)\r\n }\r\n }\r\n /**\r\n * 当切换语言时调用此方法来加载更新语言包\r\n * @param {*} newLanguage \r\n */\r\n async _refreshScopes(newLanguage){ \r\n // 并发执行所有作用域语言包的加载\r\n try{\r\n const scopeRefreshers = this._scopes.map(scope=>{\r\n return scope.refresh(newLanguage)\r\n })\r\n if(Promise.allSettled){\r\n await Promise.allSettled(scopeRefreshers)\r\n }else{\r\n await Promise.all(scopeRefreshers)\r\n } \r\n }catch(e){\r\n console.warn(\"Error while refreshing i18n scopes:\",e.message)\r\n } \r\n }\r\n /**\r\n * \r\n * 注册一个新的作用域\r\n * \r\n * 每一个库均对应一个作用域,每个作用域可以有多个语言包,且对应一个翻译函数\r\n * 除了默认语言外,其他语言采用动态加载的方式\r\n * \r\n * @param {*} scope \r\n */\r\n async register(scope){\r\n if(!(scope instanceof i18nScope)){\r\n throw new TypeError(\"Scope must be an instance of I18nScope\")\r\n }\r\n this._scopes.push(scope) \r\n await scope.refresh(this.activeLanguage) \r\n }\r\n /**\r\n * 注册全局格式化器\r\n * 格式化器是一个简单的同步函数value=>{...},用来对输入进行格式化后返回结果\r\n * \r\n * registerFormatters(name,value=>{...}) // 适用于所有语言\r\n * registerFormatters(name,value=>{...},{langauge:\"cn\"}) // 适用于cn语言\r\n * registerFormatters(name,value=>{...},{langauge:\"en\"}) // 适用于en语言 \r\n \r\n * @param {*} formatters \r\n */\r\n registerFormatter(name,formatter,{language=\"*\"}={}){\r\n if(!typeof(formatter)===\"function\" || typeof(name)!==\"string\"){\r\n throw new TypeError(\"Formatter must be a function\")\r\n } \r\n if(DataTypes.includes(name)){\r\n this.formatters[language].$types[name] = formatter\r\n }else{\r\n this.formatters[language][name] = formatter\r\n }\r\n }\r\n}\r\n\r\nmodule.exports ={\r\n getInterpolatedVars,\r\n replaceInterpolatedVars,\r\n I18nManager,\r\n translate,\r\n languages,\r\n i18nScope,\r\n defaultLanguageSettings,\r\n getDataTypeName,\r\n isNumber,\r\n isPlainObject \r\n}","/**\r\n * 内置的格式化器\r\n * \r\n */\r\n\r\n\r\n/**\r\n * 字典格式化器\r\n * 根据输入data的值,返回后续参数匹配的结果\r\n * dict(data,,,,,,,...)\r\n * \r\n * \r\n * dict(1,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == \"one\"\r\n * dict(2,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == \"two\"\r\n * dict(3,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == \"three\"\r\n * dict(4,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == \"four\"\r\n * // 无匹配时返回原始值\r\n * dict(5,1,\"one\",2,\"two\",3,\"three\",4,\"four\") == 5 \r\n * // 无匹配时并且后续参数个数是奇数,则返回最后一个参数\r\n * dict(5,1,\"one\",2,\"two\",3,\"three\",4,\"four\",\"more\") == \"more\" \r\n * \r\n * 在翻译中使用\r\n * I have { value | dict(1,\"one\",2,\"two\",3,\"three\",4,\"four\")} apples\r\n * \r\n * @param {*} value \r\n * @param {...any} args \r\n * @returns \r\n */\r\n function dict(value,...args){\r\n for(let i=0;i0 && (args.length % 2!==0)) return args[args.length-1]\r\n return value\r\n}\r\n\r\nfunction formatCurrency(value,symbol,retainDots){\r\n\r\n}\r\n\r\nmodule.exports = { \r\n \"*\":{\r\n $types:{\r\n Date:(value)=>value.toLocaleString()\r\n },\r\n time:(value)=> value.toLocaleTimeString(), \r\n shorttime:(value)=> value.toLocaleTimeString(), \r\n date: (value)=> value.toLocaleDateString(), \r\n dict, //字典格式化器\r\n }, \r\n cn:{ \r\n $types:{\r\n Date:(value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日 ${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`\r\n },\r\n shortime:(value)=> value.toLocaleTimeString(), \r\n time:(value)=>`${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`, \r\n date: (value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日`,\r\n shortdate: (value)=> `${value.getFullYear()}-${value.getMonth()+1}-${value.getDate()}`,\r\n currency:(value)=>`${value}元`,\r\n },\r\n en:{\r\n currency:(value)=>{\r\n return `$${value}`\r\n }\r\n }\r\n}"],"names":["utils","obj","_typeof","proto","_Object$getPrototypeOf","baseProto","value","isNaN","_parseInt","deepMerge","toObj","formObj","_context","options","results","_Object$assign","_ref","_ref2","_slicedToArray","key","_Array$isArray","array","_context2","_concatInstanceProperty","call","_toConsumableArray","_context3","_Set","v","undefined","constructor","name","eventemitter","EventEmitter","_classCallCheck","this","_callbacks","_emit","_createClass","callback","_includesInstanceProperty","push","i","length","_spliceInstanceProperty","_asyncToGenerator","_regeneratorRuntime","mark","_callee","_len","args","_key","_context4","_args","arguments","wrap","_context5","prev","next","Array","_Promise","allSettled","_mapInstanceProperty","cb","apply","all","stop","scope","i18nScope","_id","id","Date","getTime","toString","Math","random","_languages","languages","_defaultLanguage","defaultLanguage","_activeLanguage","activeLanguage","_default","_messages","messages","_idMap","idMap","_formatters","formatters","_loaders","loaders","_global","$cache","typedFormatters","_globalThis","VoerkaI18n","I18nManager","require$$0","global","_loading","register","_refresh","get","set","then","formatter","_ref$language","language","TypeError","DataTypes","$types","newLanguage","loader","resolve","abrupt","sent","t0","console","warn","message","_fallback","_x","_bindInstanceProperty","on","off","_context6","offAll","_context7","change","getDataTypeName","isNumber","isPlainObject","require$$1","require$$2","inlineFormatters","toLocaleString","time","toLocaleTimeString","shorttime","date","toLocaleDateString","dict","cn","concat","getFullYear","getMonth","getDate","getHours","getMinutes","getSeconds","shortime","_context8","_context9","shortdate","_context10","_context11","currency","en","varWithPipeRegexp","varname","hasInterpolation","str","_String$raw","_templateObject","_taggedTemplateLiteral","parseFormatters","result","_trimInstanceProperty","substr","split","r","firstIndex","_indexOfInstanceProperty","lastIndex","_lastIndexOfInstanceProperty","argsContent","arg","_startsWithInstanceProperty","_endsWithInstanceProperty","toLowerCase","String","JSON","parse","e","forEachInterpolatedVars","match","opts","replaceAll","exec","groups","_replaceAllInstanceProperty","replace","_unused","resetScopeCache","buildFormatters","_step2","_iterator2","_createForOfIteratorHelper","_loop","func","_i2","_targets2","target","getFormatter","_v$formatter$","s","n","done","err","f","getFormattedValue","formatterFuncs","defaultFormatter","dataType","_i","_targets","getDataTypeDefaultFormatter","_step","_iterator","error","executeFormatter","replaceInterpolatedVars","template","varValues","params","Error","defaultLanguageSettings","title","default","isMessageId","content","getPluraMessage","_unused2","escape","_context12","_context13","_context14","_context15","unescape","_context16","_context17","_context18","_context19","_context20","_context21","_context22","_context23","_register","_refreshScopes2","_change","_this2","settings","_super2","instance","_assertThisInitialized","_settings","_scopes","_context28","_context29","_findIndexInstanceProperty","lang","_refreshScopes","emit","_callee2","_context30","scopeRefreshers","_context31","refresh","_callee3","_context32","_ref5","_ref5$language","runtime","getInterpolatedVars","vars","varName","varItem","varDef","translate","pluralVars","pluraValue","_context24","_context27","_forEachInstanceProperty","_Object$entries","_ref3","_ref4","_context25","_context26","_sliceInstanceProperty","prototype","index","msgId","pluralVar"],"mappings":"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"} \ No newline at end of file diff --git a/packages/runtime/dist/runtime.cjs b/packages/runtime/dist/runtime.cjs deleted file mode 100644 index d289a38..0000000 --- a/packages/runtime/dist/runtime.cjs +++ /dev/null @@ -1,942 +0,0 @@ -'use strict'; - -/** - * 判断是否是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;icb(...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 || "cn"; // 默认语言名称 - 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,,,,,,,...) - * - * - * 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;i0 && (args.length % 2!==0)) return args[args.length-1] - return value -} - -var formatters$1 = { - "*":{ - $types:{ - Date:(value)=>value.toLocaleString() - }, - time:(value)=> value.toLocaleTimeString(), - shorttime:(value)=> value.toLocaleTimeString(), - date: (value)=> value.toLocaleDateString(), - dict, //字典格式化器 - }, - cn:{ - $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$1; // 内置格式化器 - - - -// 用来提取字符里面的插值变量参数 , 支持管道符 { var | formatter | formatter } -// 不支持参数: let varWithPipeRegexp = /\{\s*(?\w+)?(?(\s*\|\s*\w*\s*)*)\s*\}/g - -// 支持参数: { var | formatter(x,x,..) | formatter } -let varWithPipeRegexp = /\{\s*(?\w+)?(?(\s*\|\s*\w*(\(.*\)){0,1}\s*)*)\s*\}/g; - -// 有效的语言名称列表 -const languages = ["af","am","ar-dz","ar-iq","ar-kw","ar-ly","ar-ma","ar-sa","ar-tn","ar","az","be","bg","bi","bm","bn","bo","br","bs","ca","cs","cv","cy","da","de-at","de-ch","de","dv","el","en-au","en-ca","en-gb","en-ie","en-il","en-in","en-nz","en-sg","en-tt","en","eo","es-do","es-mx","es-pr","es-us","es","et","eu","fa","fi","fo","fr-ca","fr-ch","fr","fy","ga","gd","gl","gom-latn","gu","he","hi","hr","ht","hu","hy-am","id","is","it-ch","it","ja","jv","ka","kk","km","kn","ko","ku","ky","lb","lo","lt","lv","me","mi","mk","ml","mn","mr","ms-my","ms","mt","my","nb","ne","nl-be","nl","nn","oc-lnc","pa-in","pl","pt-br","pt","ro","ru","rw","sd","se","si","sk","sl","sq","sr-cyrl","sr","ss","sv-fi","sv","sw","ta","te","tet","tg","th","tk","tl-ph","tlh","tr","tzl","tzm-latn","tzm","ug-cn","uk","ur","uz-latn","uz","vi","x-pseudo","yo","zh-cn","zh-hk","zh-tw","zh"]; - -/** - * 考虑到通过正则表达式进行插件的替换可能较慢,因此提供一个简单方法来过滤掉那些 - * 不需要进行插值处理的字符串 - * 原理很简单,就是判断一下是否同时具有{和}字符,如果有则认为可能有插值变量,如果没有则一定没有插件变量,则就不需要进行正则匹配 - * 从而可以减少不要的正则匹配 - * 注意:该方法只能快速判断一个字符串不包括插值变量 - * @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 [[,[,,...]]] - */ -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 || ""; - // 解析格式化器和参数 = [,[,[,,...]]] - 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:{...} // 在所有语言下只作用于特定数据类型的格式化器 - }, // 在所有语言下生效的格式化器 - cn:{ - $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: "cn", - activeLanguage: "cn", - languages:[ - {name:"cn",title:"中文",default:true}, - {name:"en",title:"英文"} - ], - formatters -}; - -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=默认语言包={:} - 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:"cn"}) // 适用于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, - languages, - i18nScope, - defaultLanguageSettings, - getDataTypeName, - isNumber, - isPlainObject -}; - -module.exports = runtime; diff --git a/packages/runtime/dist/runtime.mjs b/packages/runtime/dist/runtime.mjs deleted file mode 100644 index c42620e..0000000 --- a/packages/runtime/dist/runtime.mjs +++ /dev/null @@ -1,940 +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;icb(...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 || "cn"; // 默认语言名称 - 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,,,,,,,...) - * - * - * 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;i0 && (args.length % 2!==0)) return args[args.length-1] - return value -} - -var formatters$1 = { - "*":{ - $types:{ - Date:(value)=>value.toLocaleString() - }, - time:(value)=> value.toLocaleTimeString(), - shorttime:(value)=> value.toLocaleTimeString(), - date: (value)=> value.toLocaleDateString(), - dict, //字典格式化器 - }, - cn:{ - $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$1; // 内置格式化器 - - - -// 用来提取字符里面的插值变量参数 , 支持管道符 { var | formatter | formatter } -// 不支持参数: let varWithPipeRegexp = /\{\s*(?\w+)?(?(\s*\|\s*\w*\s*)*)\s*\}/g - -// 支持参数: { var | formatter(x,x,..) | formatter } -let varWithPipeRegexp = /\{\s*(?\w+)?(?(\s*\|\s*\w*(\(.*\)){0,1}\s*)*)\s*\}/g; - -// 有效的语言名称列表 -const languages = ["af","am","ar-dz","ar-iq","ar-kw","ar-ly","ar-ma","ar-sa","ar-tn","ar","az","be","bg","bi","bm","bn","bo","br","bs","ca","cs","cv","cy","da","de-at","de-ch","de","dv","el","en-au","en-ca","en-gb","en-ie","en-il","en-in","en-nz","en-sg","en-tt","en","eo","es-do","es-mx","es-pr","es-us","es","et","eu","fa","fi","fo","fr-ca","fr-ch","fr","fy","ga","gd","gl","gom-latn","gu","he","hi","hr","ht","hu","hy-am","id","is","it-ch","it","ja","jv","ka","kk","km","kn","ko","ku","ky","lb","lo","lt","lv","me","mi","mk","ml","mn","mr","ms-my","ms","mt","my","nb","ne","nl-be","nl","nn","oc-lnc","pa-in","pl","pt-br","pt","ro","ru","rw","sd","se","si","sk","sl","sq","sr-cyrl","sr","ss","sv-fi","sv","sw","ta","te","tet","tg","th","tk","tl-ph","tlh","tr","tzl","tzm-latn","tzm","ug-cn","uk","ur","uz-latn","uz","vi","x-pseudo","yo","zh-cn","zh-hk","zh-tw","zh"]; - -/** - * 考虑到通过正则表达式进行插件的替换可能较慢,因此提供一个简单方法来过滤掉那些 - * 不需要进行插值处理的字符串 - * 原理很简单,就是判断一下是否同时具有{和}字符,如果有则认为可能有插值变量,如果没有则一定没有插件变量,则就不需要进行正则匹配 - * 从而可以减少不要的正则匹配 - * 注意:该方法只能快速判断一个字符串不包括插值变量 - * @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 [[,[,,...]]] - */ -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 || ""; - // 解析格式化器和参数 = [,[,[,,...]]] - 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:{...} // 在所有语言下只作用于特定数据类型的格式化器 - }, // 在所有语言下生效的格式化器 - cn:{ - $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: "cn", - activeLanguage: "cn", - languages:[ - {name:"cn",title:"中文",default:true}, - {name:"en",title:"英文"} - ], - formatters -}; - -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=默认语言包={:} - 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:"cn"}) // 适用于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, - languages, - i18nScope, - defaultLanguageSettings, - getDataTypeName, - isNumber, - isPlainObject -}; - -export { runtime as default }; diff --git a/packages/runtime/formatters.js b/packages/runtime/formatters.js index 94f685b..e32bd2e 100644 --- a/packages/runtime/formatters.js +++ b/packages/runtime/formatters.js @@ -50,7 +50,7 @@ module.exports = { date: (value)=> value.toLocaleDateString(), dict, //字典格式化器 }, - cn:{ + zh:{ $types:{ Date:(value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日 ${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒` }, diff --git a/packages/runtime/index.js b/packages/runtime/index.js index 404755e..f877649 100644 --- a/packages/runtime/index.js +++ b/packages/runtime/index.js @@ -11,10 +11,6 @@ let inlineFormatters = require("./formatters") // 内置格式化器 // 支持参数: { var | formatter(x,x,..) | formatter } let varWithPipeRegexp = /\{\s*(?\w+)?(?(\s*\|\s*\w*(\(.*\)){0,1}\s*)*)\s*\}/g -// 有效的语言名称列表 -const languages = ["af","am","ar-dz","ar-iq","ar-kw","ar-ly","ar-ma","ar-sa","ar-tn","ar","az","be","bg","bi","bm","bn","bo","br","bs","ca","cs","cv","cy","da","de-at","de-ch","de","dv","el","en-au","en-ca","en-gb","en-ie","en-il","en-in","en-nz","en-sg","en-tt","en","eo","es-do","es-mx","es-pr","es-us","es","et","eu","fa","fi","fo","fr-ca","fr-ch","fr","fy","ga","gd","gl","gom-latn","gu","he","hi","hr","ht","hu","hy-am","id","is","it-ch","it","ja","jv","ka","kk","km","kn","ko","ku","ky","lb","lo","lt","lv","me","mi","mk","ml","mn","mr","ms-my","ms","mt","my","nb","ne","nl-be","nl","nn","oc-lnc","pa-in","pl","pt-br","pt","ro","ru","rw","sd","se","si","sk","sl","sq","sr-cyrl","sr","ss","sv-fi","sv","sw","ta","te","tet","tg","th","tk","tl-ph","tlh","tr","tzl","tzm-latn","tzm","ug-cn","uk","ur","uz-latn","uz","vi","x-pseudo","yo","zh-cn","zh-hk","zh-tw","zh"] - - // 插值变量字符串替换正则 //let varReplaceRegexp =String.raw`\{\s*(?{name}\.?\w*)\s*\}` @@ -199,7 +195,7 @@ function resetScopeCache(scope,activeLanguage=null){ "*":{ $types:{...} // 在所有语言下只作用于特定数据类型的格式化器 }, // 在所有语言下生效的格式化器 - cn:{ + zh:{ $types:{ [数据类型]:(value)=>{...}, }, @@ -402,13 +398,13 @@ function replaceInterpolatedVars(template,...args) { // 默认语言配置 const defaultLanguageSettings = { - defaultLanguage: "cn", - activeLanguage: "cn", + defaultLanguage: "zh", + activeLanguage: "zh", languages:[ - {name:"cn",title:"中文",default:true}, + {name:"zh",title:"中文",default:true}, {name:"en",title:"英文"} ], - formatters + formatters:inlineFormatters } function isMessageId(content){ @@ -638,7 +634,7 @@ function translate(message) { * 格式化器是一个简单的同步函数value=>{...},用来对输入进行格式化后返回结果 * * registerFormatters(name,value=>{...}) // 适用于所有语言 - * registerFormatters(name,value=>{...},{langauge:"cn"}) // 适用于cn语言 + * registerFormatters(name,value=>{...},{langauge:"zh"}) // 适用于cn语言 * registerFormatters(name,value=>{...},{langauge:"en"}) // 适用于en语言 * @param {*} formatters @@ -659,8 +655,7 @@ module.exports ={ getInterpolatedVars, replaceInterpolatedVars, I18nManager, - translate, - languages, + translate i18nScope, defaultLanguageSettings, getDataTypeName, diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 5e2a266..eb01eb0 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,37 +1,39 @@ { - "name": "@voerkai18n/runtime", - "version": "1.0.9", - "description": "Voerkai18n Runtime", - "main": "./dist/index.cjs", - "module": "dist/index.esm.js", - "homepage": "https://gitee.com/zhangfisher/voerka-i18n", - "repository": { - "type": "git", - "url": "git+https://gitee.com/zhangfisher/voerka-i18n.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "build": "rollup -c", - "release": "npm version patch && pnpm publish --no-git-checks --access public" - }, - "exports": { - "import": "./dist/index.esm.js", - "require": "./dist/index.cjs" - }, - "author": "wxzhang", - "license": "MIT", - "devDependencies": { - "@babel/cli": "^7.17.6", - "@babel/core": "^7.17.5", - "@babel/plugin-transform-runtime": "^7.17.0", - "@babel/preset-env": "^7.16.11", - "@babel/runtime": "^7.17.8", - "@rollup/plugin-babel": "^5.3.1", - "@rollup/plugin-commonjs": "^21.0.2", - "@rollup/plugin-node-resolve": "^13.1.3", - "deepmerge": "^4.2.2", - "rollup": "^2.69.0", - "rollup-plugin-clear": "^2.0.7", - "rollup-plugin-terser": "^7.0.2" - } -} + "name": "@voerkai18n/runtime", + "version": "1.0.16", + "description": "Voerkai18n Runtime", + "main": "./dist/index.cjs", + "module": "dist/index.esm.js", + "homepage": "https://gitee.com/zhangfisher/voerka-i18n", + "repository": { + "type": "git", + "url": "git+https://gitee.com/zhangfisher/voerka-i18n.git" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "rollup -c", + "release": "pnpm autopublish" + }, + "exports": { + "import": "./dist/index.esm.js", + "require": "./dist/index.cjs" + }, + "author": "wxzhang", + "license": "MIT", + "devDependencies": { + "@babel/cli": "^7.17.6", + "@babel/core": "^7.17.5", + "@babel/plugin-transform-runtime": "^7.17.0", + "@babel/preset-env": "^7.16.11", + "@babel/runtime": "^7.17.8", + "@rollup/plugin-babel": "^5.3.1", + "@rollup/plugin-commonjs": "^21.0.2", + "@rollup/plugin-node-resolve": "^13.1.3", + "deepmerge": "^4.2.2", + "rollup": "^2.69.0", + "rollup-plugin-clear": "^2.0.7", + "rollup-plugin-terser": "^7.0.2", + "@voerkai18n/autopublish": "workspace:^1.0.2" + }, + "lastPublish": "2022-04-07T19:14:01+08:00" +} \ No newline at end of file diff --git a/packages/runtime/scope.js b/packages/runtime/scope.js index 63cd5eb..04b2cc4 100644 --- a/packages/runtime/scope.js +++ b/packages/runtime/scope.js @@ -4,7 +4,7 @@ module.exports = class i18nScope { // 每个作用域都有一个唯一的id this._id = options.id || (new Date().getTime().toString()+parseInt(Math.random()*1000)) this._languages = options.languages // 当前作用域的语言列表 - this._defaultLanguage = options.defaultLanguage || "cn" // 默认语言名称 + this._defaultLanguage = options.defaultLanguage || "zh" // 默认语言名称 this._activeLanguage = options.activeLanguage // 当前语言名称 this._default = options.default // 默认语言包 this._messages = options.messages // 当前语言包 diff --git a/packages/utils/index.js b/packages/utils/index.js index 84239f6..ade256c 100644 --- a/packages/utils/index.js +++ b/packages/utils/index.js @@ -121,9 +121,7 @@ function getProjectRootFolder(folder="./",exclueCurrent=false){ /** * 自动获取当前项目的languages - * - * 1. - * + * * @param {*} location */ function getProjectLanguageFolder(location="./"){ @@ -188,7 +186,7 @@ function getProjectRootFolder(folder="./",exclueCurrent=false){ * @returns */ function getCurrentPackageJson(folder,exclueCurrent=true){ - let projectFolder = getCurrentProjectRootFolder(folder,exclueCurrent) + let projectFolder = getProjectRootFolder(folder,exclueCurrent) if(projectFolder){ return fs.readJSONSync(path.join(projectFolder,"package.json")) } @@ -231,6 +229,28 @@ function isInstallDependent(url){ } } +/** + * 获取当前包的版本号 + */ +function getInstalledPackages(){ + const packages = { + "@voerkai18n/runtime":"未安装", + "@voerkai18n/babel":"未安装", + "@voerkai18n/vue":"未安装", + "@voerkai18n/react":"未安装", + "@voerkai18n/vite":"未安装", + "@voerkai18n/formatters":"未安装" + } + for(let package of Object.keys(packages)){ + try{ + require(package) + }catch{ + packages[package] = "已安装" + } + } + +} + /** * 判断是否是JSON对象 * @param {*} obj @@ -333,6 +353,21 @@ function deepMerge(toObj,formObj,options={}){ shelljs.exec("npm install @voerkai18n/runtime") } } +/** + * 在当前工程升级@voerkai18n/runtime + * @param {*} srcPath + * @param {*} opts + */ +function updateVoerkai18nRuntime(srcPath){ + const projectFolder = getCurrentProjectRootFolder(srcPath || process.cwd()) + if(fs.existsSync("pnpm-lock.yaml")){ + shelljs.exec("pnpm update --latest @voerkai18n/runtime") + }else if(fs.existsSync("yarn.lock")){ + shelljs.exec("yarn upgrade @voerkai18n/runtime") + }else{ + shelljs.exec("npm update --save @voerkai18n/runtime") + } +} /** @@ -368,6 +403,7 @@ module.exports = { findModuleType, // 获取当前项目的模块类型 isInstallDependent, // 判断是否已经安装了依赖 installVoerkai18nRuntime, // 在当前工程自动安装@voerkai18n/runtime + updateVoerkai18nRuntime, // 在当前工程升级@voerkai18n/runtime isPlainObject, // 判断是否是普通对象 isNumber, // 判断是否是数字 deepMerge, // 深度合并对象 diff --git a/packages/utils/package.json b/packages/utils/package.json index f1d6f07..f565ae5 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,16 +1,20 @@ { - "name": "@voerkai18n/utils", - "version": "1.0.2", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "release": "npm version patch && pnpm publish --no-git-checks --access public" - }, - "author": "", - "license": "ISC", - "dependencies": { - "fs-extra": "^10.0.1", - "shelljs": "^0.8.5" - } -} + "name": "@voerkai18n/utils", + "version": "1.0.10", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "release": "pnpm autopublish" + }, + "author": "", + "license": "ISC", + "dependencies": { + "fs-extra": "^10.0.1", + "shelljs": "^0.8.5" + }, + "devDependencies": { + "@voerkai18n/autopublish": "workspace:^1.0.2" + }, + "lastPublish": "2022-04-10T17:21:16+08:00" +} \ No newline at end of file diff --git a/packages/vite/package.json b/packages/vite/package.json index 6254a1f..65f3ff0 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -1,15 +1,19 @@ { - "name": "@voerkai18n/vite", - "version": "1.0.1", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "release": "npm version patch && pnpm publish --no-git-checks --access public" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@voerkai18n/utils": "workspace:^1.0.0" - } -} + "name": "@voerkai18n/vite", + "version": "1.0.7", + "description": "VoerkaI18n plugin for Vite", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "release": "pnpm autopublish" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@voerkai18n/utils": "workspace:^1.0.0" + }, + "devDependencies": { + "@voerkai18n/autopublish": "workspace:^1.0.2" + }, + "lastPublish": "2022-04-10T17:21:48+08:00" +} \ No newline at end of file diff --git a/packages/vue/package.json b/packages/vue/package.json index 8ffc572..d3445a6 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,26 +1,16 @@ { "name": "@voerkai18n/vue", - "version": "1.0.1", + "version": "1.0.4", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "release": "npm version patch && pnpm publish --no-git-checks --access public" - }, - "exports": { - ".": "./index.js", - "./vite-plugin-voerkai18n": "./vite-plugin-voerkai18n.js" + "release": "pnpm autopublish" }, "author": "", "license": "ISC", "devDependencies": { - "deepmerge": "^4.2.2", - "gulp": "^4.0.2", - "vinyl": "^2.2.1" + "@voerkai18n/autopublish": "workspace:^1.0.2" }, - "dependencies": { - "minimatch": "^5.0.1", - "vite": "^2.8.6", - "vite-plugin-inspect": "^0.4.3" - } -} + "lastPublish": "2022-04-06T20:55:01+08:00" +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8bb25f..bdd8c5e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,6 +9,8 @@ importers: '@babel/preset-env': ^7.16.11 '@rollup/plugin-babel': ^5.3.1 '@rollup/plugin-commonjs': ^21.0.2 + '@voerkai18n/autopublish': ^1.0.3 + cross-env: ^7.0.3 dayjs: ^1.11.0 deepmerge: ^4.2.2 fs-extra: ^10.0.1 @@ -20,7 +22,9 @@ importers: rollup-plugin-clear: ^2.0.7 shelljs: ^0.8.5 vinyl: ^2.2.1 + vuepress: ^2.0.0-beta.38 dependencies: + cross-env: 7.0.3 inquirer: registry.npmmirror.com/inquirer/8.2.2 devDependencies: '@babel/core': 7.17.8 @@ -28,6 +32,7 @@ importers: '@babel/preset-env': 7.16.11_@babel+core@7.17.8 '@rollup/plugin-babel': 5.3.1_@babel+core@7.17.8+rollup@2.70.1 '@rollup/plugin-commonjs': 21.0.2_rollup@2.70.1 + '@voerkai18n/autopublish': 1.0.3 dayjs: 1.11.0 deepmerge: 4.2.2 fs-extra: 10.0.1 @@ -38,6 +43,7 @@ importers: rollup-plugin-clear: 2.0.7 shelljs: 0.8.5 vinyl: 2.2.1 + vuepress: 2.0.0-beta.38 packages/apps/app: specifiers: @@ -89,24 +95,29 @@ importers: packages/autopublish: specifiers: commander: ^9.0.0 - semver: ^7.3.5 + fast-glob: ^3.2.11 dependencies: commander: registry.npmmirror.com/commander/9.0.0 - semver: 7.3.5 + fast-glob: 3.2.11 packages/babel: specifiers: - '@voerkai18n/utils': workspace:^1.0.0 + '@voerkai18n/autopublish': workspace:^1.0.2 + '@voerkai18n/utils': workspace:^1.0.6 dependencies: '@voerkai18n/utils': link:../utils + devDependencies: + '@voerkai18n/autopublish': link:../autopublish packages/cli: specifiers: '@babel/cli': ^7.17.6 '@babel/core': ^7.17.5 - '@voerkai18n/runtime': workspace:^1.0.8 - '@voerkai18n/utils': workspace:^1.0.0 + '@voerkai18n/autopublish': workspace:^1.0.2 + '@voerkai18n/runtime': workspace:^1.0.14 + '@voerkai18n/utils': workspace:^1.0.6 art-template: ^4.13.2 + axios: ^0.26.1 commander: ^9.0.0 cross-env: ^7.0.3 deepmerge: ^4.2.2 @@ -114,6 +125,8 @@ importers: glob: ^7.2.0 gulp: ^4.0.2 logsets: ^1.0.8 + md5: ^2.3.0 + qs: ^6.10.3 shelljs: ^0.8.5 through2: ^4.0.2 vinyl: ^2.2.1 @@ -123,6 +136,7 @@ importers: '@voerkai18n/runtime': link:../runtime '@voerkai18n/utils': link:../utils art-template: 4.13.2 + axios: 0.26.1 commander: 9.0.0 cross-env: 7.0.3 deepmerge: 4.2.2 @@ -130,19 +144,22 @@ importers: glob: 7.2.0 gulp: 4.0.2 logsets: 1.0.8 + md5: 2.3.0 + qs: 6.10.3 shelljs: 0.8.5 through2: 4.0.2 vinyl: 2.2.1 + devDependencies: + '@voerkai18n/autopublish': link:../autopublish packages/formatters: specifiers: - deepmerge: ^4.2.2 - gulp: ^4.0.2 - vinyl: ^2.2.1 + '@voerkai18n/autopublish': workspace:^1.0.2 + dayjs: ^1.11.0 + dependencies: + dayjs: 1.11.0 devDependencies: - deepmerge: 4.2.2 - gulp: 4.0.2 - vinyl: 2.2.1 + '@voerkai18n/autopublish': link:../autopublish packages/react: specifiers: @@ -164,6 +181,7 @@ importers: '@rollup/plugin-babel': ^5.3.1 '@rollup/plugin-commonjs': ^21.0.2 '@rollup/plugin-node-resolve': ^13.1.3 + '@voerkai18n/autopublish': workspace:^1.0.2 deepmerge: ^4.2.2 rollup: ^2.69.0 rollup-plugin-clear: ^2.0.7 @@ -177,6 +195,7 @@ importers: '@rollup/plugin-babel': 5.3.1_@babel+core@7.17.5+rollup@2.69.0 '@rollup/plugin-commonjs': 21.0.2_rollup@2.69.0 '@rollup/plugin-node-resolve': 13.1.3_rollup@2.69.0 + '@voerkai18n/autopublish': link:../autopublish deepmerge: 4.2.2 rollup: 2.69.0 rollup-plugin-clear: 2.0.7 @@ -184,34 +203,29 @@ importers: packages/utils: specifiers: + '@voerkai18n/autopublish': workspace:^1.0.2 fs-extra: ^10.0.1 shelljs: ^0.8.5 dependencies: fs-extra: registry.npmmirror.com/fs-extra/10.0.1 shelljs: registry.npmmirror.com/shelljs/0.8.5 + devDependencies: + '@voerkai18n/autopublish': link:../autopublish packages/vite: specifiers: + '@voerkai18n/autopublish': workspace:^1.0.2 '@voerkai18n/utils': workspace:^1.0.0 dependencies: '@voerkai18n/utils': link:../utils + devDependencies: + '@voerkai18n/autopublish': link:../autopublish packages/vue: specifiers: - deepmerge: ^4.2.2 - gulp: ^4.0.2 - minimatch: ^5.0.1 - vinyl: ^2.2.1 - vite: ^2.8.6 - vite-plugin-inspect: ^0.4.3 - dependencies: - minimatch: registry.npmmirror.com/minimatch/5.0.1 - vite: 2.8.6 - vite-plugin-inspect: 0.4.3_vite@2.8.6 + '@voerkai18n/autopublish': workspace:^1.0.2 devDependencies: - deepmerge: 4.2.2 - gulp: 4.0.2 - vinyl: 2.2.1 + '@voerkai18n/autopublish': link:../autopublish packages: @@ -690,6 +704,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + /@babel/parser/7.17.9: + resolution: {integrity: sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==} + engines: {node: '>=6.0.0'} + hasBin: true + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.16.7_@babel+core@7.17.5: resolution: {integrity: sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==} engines: {node: '>=6.9.0'} @@ -2625,8 +2644,27 @@ packages: requiresBuild: true optional: true + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.13.0 + /@polka/url/1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} + dev: true /@rollup/plugin-babel/5.3.1_@babel+core@7.17.5+rollup@2.69.0: resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} @@ -2739,6 +2777,7 @@ packages: dependencies: estree-walker: 2.0.2 picomatch: 2.3.1 + dev: true /@sinonjs/commons/1.8.3: resolution: {integrity: sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==} @@ -2786,6 +2825,12 @@ packages: '@babel/types': 7.17.0 dev: true + /@types/debug/4.1.7: + resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} + dependencies: + '@types/ms': 0.7.31 + dev: true + /@types/estree/0.0.39: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} dev: true @@ -2794,12 +2839,22 @@ packages: resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} dev: true + /@types/fs-extra/9.0.13: + resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + dependencies: + '@types/node': 17.0.23 + dev: true + /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: '@types/node': 17.0.23 dev: true + /@types/hash-sum/1.0.0: + resolution: {integrity: sha512-FdLBT93h3kcZ586Aee66HPCVJ6qvxVjBlDWNmxSGSbCZe9hTsjRKdSsl4y1T+3zfujxo9auykQMnFsfyHWD7wg==} + dev: true + /@types/istanbul-lib-coverage/2.0.4: resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} dev: true @@ -2816,8 +2871,23 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: true - /@types/node/17.0.21: - resolution: {integrity: sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==} + /@types/linkify-it/3.0.2: + resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==} + dev: true + + /@types/markdown-it/12.2.3: + resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==} + dependencies: + '@types/linkify-it': 3.0.2 + '@types/mdurl': 1.0.2 + dev: true + + /@types/mdurl/1.0.2: + resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} + dev: true + + /@types/ms/0.7.31: + resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true /@types/node/17.0.23: @@ -2831,7 +2901,7 @@ packages: /@types/resolve/1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@types/node': 17.0.21 + '@types/node': 17.0.23 dev: true /@types/stack-utils/2.0.1: @@ -2873,26 +2943,44 @@ packages: vue: 3.2.31 dev: true + /@vitejs/plugin-vue/2.3.1_vite@2.9.1+vue@3.2.31: + resolution: {integrity: sha512-YNzBt8+jt6bSwpt7LP890U1UcTOIZZxfpE5WOJ638PNxSEKOqAi0+FSKS0nVeukfdZ0Ai/H7AFd6k3hayfGZqQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + vite: ^2.5.10 + vue: ^3.2.25 + dependencies: + vite: 2.9.1 + vue: 3.2.31 + dev: true + + /@voerkai18n/autopublish/1.0.3: + resolution: {integrity: sha512-6J264vifk4M7r8/nEL+uti3WqJ69fMTWRFndU7UVU4kRCB5kGKlHFTT5FLkVojazLUcLm7EPMKOBzW6w8he2Ag==} + hasBin: true + dependencies: + commander: 9.0.0 + fast-glob: 3.2.11 + semver: 7.3.5 + dev: true + /@vue/compiler-core/3.2.31: resolution: {integrity: sha512-aKno00qoA4o+V/kR6i/pE+aP+esng5siNAVQ422TkBNM6qA4veXiZbSe8OTXHXquEi/f6Akc+nLfB4JGfe4/WQ==} dependencies: - '@babel/parser': 7.17.8 + '@babel/parser': 7.17.9 '@vue/shared': 3.2.31 estree-walker: 2.0.2 source-map: 0.6.1 - dev: false /@vue/compiler-dom/3.2.31: resolution: {integrity: sha512-60zIlFfzIDf3u91cqfqy9KhCKIJgPeqxgveH2L+87RcGU/alT6BRrk5JtUso0OibH3O7NXuNOQ0cDc9beT0wrg==} dependencies: '@vue/compiler-core': 3.2.31 '@vue/shared': 3.2.31 - dev: false /@vue/compiler-sfc/3.2.31: resolution: {integrity: sha512-748adc9msSPGzXgibHiO6T7RWgfnDcVQD+VVwYgSsyyY8Ans64tALHZANrKtOzvkwznV/F4H7OAod/jIlp/dkQ==} dependencies: - '@babel/parser': 7.17.8 + '@babel/parser': 7.17.9 '@vue/compiler-core': 3.2.31 '@vue/compiler-dom': 3.2.31 '@vue/compiler-ssr': 3.2.31 @@ -2902,37 +2990,36 @@ packages: magic-string: 0.25.9 postcss: 8.4.12 source-map: 0.6.1 - dev: false /@vue/compiler-ssr/3.2.31: resolution: {integrity: sha512-mjN0rqig+A8TVDnsGPYJM5dpbjlXeHUm2oZHZwGyMYiGT/F4fhJf/cXy8QpjnLQK4Y9Et4GWzHn9PS8AHUnSkw==} dependencies: '@vue/compiler-dom': 3.2.31 '@vue/shared': 3.2.31 - dev: false + + /@vue/devtools-api/6.1.4: + resolution: {integrity: sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ==} + dev: true /@vue/reactivity-transform/3.2.31: resolution: {integrity: sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA==} dependencies: - '@babel/parser': 7.17.8 + '@babel/parser': 7.17.9 '@vue/compiler-core': 3.2.31 '@vue/shared': 3.2.31 estree-walker: 2.0.2 magic-string: 0.25.9 - dev: false /@vue/reactivity/3.2.31: resolution: {integrity: sha512-HVr0l211gbhpEKYr2hYe7hRsV91uIVGFYNHj73njbARVGHQvIojkImKMaZNDdoDZOIkMsBc9a1sMqR+WZwfSCw==} dependencies: '@vue/shared': 3.2.31 - dev: false /@vue/runtime-core/3.2.31: resolution: {integrity: sha512-Kcog5XmSY7VHFEMuk4+Gap8gUssYMZ2+w+cmGI6OpZWYOEIcbE0TPzzPHi+8XTzAgx1w/ZxDFcXhZeXN5eKWsA==} dependencies: '@vue/reactivity': 3.2.31 '@vue/shared': 3.2.31 - dev: false /@vue/runtime-dom/3.2.31: resolution: {integrity: sha512-N+o0sICVLScUjfLG7u9u5XCjvmsexAiPt17GNnaWHJUfsKed5e85/A3SWgKxzlxx2SW/Hw7RQxzxbXez9PtY3g==} @@ -2940,7 +3027,6 @@ packages: '@vue/runtime-core': 3.2.31 '@vue/shared': 3.2.31 csstype: 2.6.20 - dev: false /@vue/server-renderer/3.2.31_vue@3.2.31: resolution: {integrity: sha512-8CN3Zj2HyR2LQQBHZ61HexF5NReqngLT3oahyiVRfSSvak+oAvVmu8iNLSu6XR77Ili2AOpnAt1y8ywjjqtmkg==} @@ -2950,11 +3036,291 @@ packages: '@vue/compiler-ssr': 3.2.31 '@vue/shared': 3.2.31 vue: 3.2.31 - dev: false /@vue/shared/3.2.31: resolution: {integrity: sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ==} - dev: false + + /@vuepress/bundler-vite/2.0.0-beta.38: + resolution: {integrity: sha512-CoFwtheF7v7iYuDrGwlLGoKoc91YgK+NpXolaq4UjfWhhqOdkfHjCz4oEj3EPl0cwm/8qs3V7JwVzqtIW8ovRg==} + dependencies: + '@vitejs/plugin-vue': 2.3.1_vite@2.9.1+vue@3.2.31 + '@vue/compiler-sfc': 3.2.31 + '@vue/server-renderer': 3.2.31_vue@3.2.31 + '@vuepress/client': 2.0.0-beta.38 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/shared': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + autoprefixer: 10.4.4_postcss@8.4.12 + connect-history-api-fallback: 1.6.0 + postcss: 8.4.12 + postcss-csso: 6.0.0_postcss@8.4.12 + rollup: 2.70.1 + vite: 2.9.1 + vue: 3.2.31 + vue-router: 4.0.14_vue@3.2.31 + transitivePeerDependencies: + - less + - sass + - stylus + - supports-color + dev: true + + /@vuepress/cli/2.0.0-beta.38: + resolution: {integrity: sha512-gP/MYjhZQ/ehvni7oo25GMp7yCL7HhCjxOh2yT1h1MRjXJAA4SStSN2okqQbDw8YbkCWvgGuRqRJjny+wpbZLw==} + hasBin: true + dependencies: + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + cac: 6.7.12 + chokidar: 3.5.3 + envinfo: 7.8.1 + esbuild: 0.14.34 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/client/2.0.0-beta.38: + resolution: {integrity: sha512-siwZECsly5Rzn8yTo7u3R/vZWyPoh1yR8VESPflwfi3dIRhQLVfUsnyCC0OBz5INqB+etUiQtuY4WpNPYJcNuA==} + dependencies: + '@vue/devtools-api': 6.1.4 + '@vuepress/shared': 2.0.0-beta.38 + vue: 3.2.31 + vue-router: 4.0.14_vue@3.2.31 + dev: true + + /@vuepress/core/2.0.0-beta.38: + resolution: {integrity: sha512-NgTeDdhspM6mxwAafThzMYO4rhkeT3bQYdPzcZ2uEaK36zbEqRhsnrzN9X3QXfefIlX8//HF9BdAJx0+gPJErQ==} + dependencies: + '@vuepress/client': 2.0.0-beta.38 + '@vuepress/markdown': 2.0.0-beta.38 + '@vuepress/shared': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + gray-matter: 4.0.3 + toml: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/markdown/2.0.0-beta.38: + resolution: {integrity: sha512-FB4md4zONcFELYkfppGlnrQl3fOtNhHsHG3X7jj8boOW/GmUROy3A0RBGIklf4Ox6q4Se1qjdcdI/1lZy9mcsQ==} + dependencies: + '@types/markdown-it': 12.2.3 + '@vuepress/shared': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + markdown-it: 12.3.2 + markdown-it-anchor: 8.6.2_d643ca6eb40ae68ab966a77bead78073 + markdown-it-emoji: 2.0.0 + mdurl: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-active-header-links/2.0.0-beta.38: + resolution: {integrity: sha512-cQIglb/zRkd1Dyc2W69LHmKI5cbf1FaMpWwTxXrOKPY4/DFIV5bS0/8QbBBt/dEr+oydfJBpydFeyaDRZVm6Ng==} + dependencies: + '@vuepress/client': 2.0.0-beta.38 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + ts-debounce: 4.0.0 + vue: 3.2.31 + vue-router: 4.0.14_vue@3.2.31 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-back-to-top/2.0.0-beta.38: + resolution: {integrity: sha512-tWkhCB632OFKXqDDT0rKwTqQJOpiUxRpWhfNs1tzS4yNBzGkj5LGEubcwQbNQR0ujHkw/N6V+ehmWBC/RCNwjw==} + dependencies: + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + ts-debounce: 4.0.0 + vue: 3.2.31 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-container/2.0.0-beta.38: + resolution: {integrity: sha512-3CNiBzCBKLjfH/8IVeb9hT6QG8CVNuoiMdZ8mlaKrwAq4F0KkViwJLNSI/DyuFfIGMGfEMX2smkpCvtY7okAbg==} + dependencies: + '@types/markdown-it': 12.2.3 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/markdown': 2.0.0-beta.38 + '@vuepress/shared': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + markdown-it: 12.3.2 + markdown-it-container: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-external-link-icon/2.0.0-beta.38: + resolution: {integrity: sha512-vQNpVqkZ0uo7pPMpZ+GwxdxJCKhNcCBYGQBOQsBlFJjFL6ZDLlF5Gp5lZoRRMsGCkusNCMFaBGVAeGP9gDjC6A==} + dependencies: + '@vuepress/client': 2.0.0-beta.38 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/markdown': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + vue: 3.2.31 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-git/2.0.0-beta.38: + resolution: {integrity: sha512-3pWsTdo87JakN0j3ztAT/eSrdF+y1zTd4ASeA4feGnRyt4cobzy1DHoScb5QwI9AfEHKMBAomDJhNLXIk4QzNg==} + dependencies: + '@vuepress/core': 2.0.0-beta.38 + execa: 5.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-medium-zoom/2.0.0-beta.38: + resolution: {integrity: sha512-ERuvdkaPSbloHUBAUjJBj1pXWluEZdC5j18eQ478jtYdC/QLd/BDyM2KP1xwWcn+cOrLJ9L8/7NBTjfxUWBpWg==} + dependencies: + '@vuepress/client': 2.0.0-beta.38 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + medium-zoom: 1.0.6 + vue: 3.2.31 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-nprogress/2.0.0-beta.38: + resolution: {integrity: sha512-0P43/DK5w8IUzXaKXjeIALRCWNjzS+VcIBaJatHn56oR0kZHSaeQTL6mpfztXghXEcW5okUAnz8owYdZd1hyLA==} + dependencies: + '@vuepress/client': 2.0.0-beta.38 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + nprogress: 0.2.0 + vue: 3.2.31 + vue-router: 4.0.14_vue@3.2.31 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-palette/2.0.0-beta.38: + resolution: {integrity: sha512-V14jK0M8scRLwExsOeWAWJEAXk1GVA69522DtEilFBJ0WiId21i68gbPWoeOI9ZcdJQuA/NnCuF4/ogLv6O3Fw==} + dependencies: + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + chokidar: 3.5.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-prismjs/2.0.0-beta.38: + resolution: {integrity: sha512-zQQ138gqIMfO52UV67L2KA4MgiUl7TDTLwQKdm96+8+Om9iUe8qpOPzxyZRaO2WVZSXVkJDnvTjon2jqVkhm8A==} + dependencies: + '@vuepress/core': 2.0.0-beta.38 + prismjs: 1.27.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/plugin-theme-data/2.0.0-beta.38: + resolution: {integrity: sha512-mhGMjntB90RYCaJLYAtvM7BOs8OvABG5ganXKBdH6hIvvcQ5SETgGP1tsyoHPbXpG7M1b8YseDA4yDJCYcZ26w==} + dependencies: + '@vue/devtools-api': 6.1.4 + '@vuepress/client': 2.0.0-beta.38 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/shared': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + vue: 3.2.31 + transitivePeerDependencies: + - supports-color + dev: true + + /@vuepress/shared/2.0.0-beta.38: + resolution: {integrity: sha512-IWZPZkQwGI94iX8mjhMJa6CR7fyGQ5zAmjbM0hEBxw1BY5Q7RJSkwJTi5vdh1wUeF1CQx88+dfKYpWb1Wogwhg==} + dependencies: + '@vue/shared': 3.2.31 + dev: true + + /@vuepress/theme-default/2.0.0-beta.38: + resolution: {integrity: sha512-vdZiaQg40oqOPx7n8z+zHiPNur5pqGu5xMi8m/kiKHsPoWc3uO+1xoNlpOjGDDTcZhLoXDXE7Grm4rOzsx8+0w==} + dependencies: + '@vuepress/client': 2.0.0-beta.38 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/plugin-active-header-links': 2.0.0-beta.38 + '@vuepress/plugin-back-to-top': 2.0.0-beta.38 + '@vuepress/plugin-container': 2.0.0-beta.38 + '@vuepress/plugin-external-link-icon': 2.0.0-beta.38 + '@vuepress/plugin-git': 2.0.0-beta.38 + '@vuepress/plugin-medium-zoom': 2.0.0-beta.38 + '@vuepress/plugin-nprogress': 2.0.0-beta.38 + '@vuepress/plugin-palette': 2.0.0-beta.38 + '@vuepress/plugin-prismjs': 2.0.0-beta.38 + '@vuepress/plugin-theme-data': 2.0.0-beta.38 + '@vuepress/shared': 2.0.0-beta.38 + '@vuepress/utils': 2.0.0-beta.38 + '@vueuse/core': 8.2.5_vue@3.2.31 + sass: 1.50.0 + sass-loader: 12.6.0_sass@1.50.0 + vue: 3.2.31 + vue-router: 4.0.14_vue@3.2.31 + transitivePeerDependencies: + - '@vue/composition-api' + - fibers + - node-sass + - sass-embedded + - supports-color + - webpack + dev: true + + /@vuepress/utils/2.0.0-beta.38: + resolution: {integrity: sha512-qc8roc+9KJjKGHHRXnP7Yef7P6Zc3ABRiHeeBVJ0TBhoKSlguHIfDvOnUzkAvV2FWAHw3hEk71drJwRO+/zrPw==} + dependencies: + '@types/debug': 4.1.7 + '@types/fs-extra': 9.0.13 + '@types/hash-sum': 1.0.0 + '@vuepress/shared': 2.0.0-beta.38 + chalk: 4.1.2 + debug: 4.3.4 + fs-extra: 10.0.1 + globby: 11.1.0 + hash-sum: 2.0.0 + ora: 5.4.1 + upath: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@vueuse/core/8.2.5_vue@3.2.31: + resolution: {integrity: sha512-5prZAA1Ji2ltwNUnzreu6WIXYqHYP/9U2BiY5mD/650VYLpVcwVlYznJDFcLCmEWI3o3Vd34oS1FUf+6Mh68GQ==} + peerDependencies: + '@vue/composition-api': ^1.1.0 + vue: ^2.6.0 || ^3.2.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + vue: + optional: true + dependencies: + '@vueuse/metadata': 8.2.5 + '@vueuse/shared': 8.2.5_vue@3.2.31 + vue: 3.2.31 + vue-demi: 0.12.5_vue@3.2.31 + dev: true + + /@vueuse/metadata/8.2.5: + resolution: {integrity: sha512-Lk9plJjh9cIdiRdcj16dau+2LANxIdFCiTgdfzwYXbflxq0QnMBeOD2qHgKDE7fuVrtPcVWj8VSuZEx1HRfNQA==} + dev: true + + /@vueuse/shared/8.2.5_vue@3.2.31: + resolution: {integrity: sha512-lNWo+7sk6JCuOj4AiYM+6HZ6fq4xAuVq1sVckMQKgfCJZpZRe4i8es+ZULO5bYTKP+VrOCtqrLR2GzEfrbr3YQ==} + peerDependencies: + '@vue/composition-api': ^1.1.0 + vue: ^2.6.0 || ^3.2.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + vue: + optional: true + dependencies: + vue: 3.2.31 + vue-demi: 0.12.5_vue@3.2.31 + dev: true /abab/2.0.5: resolution: {integrity: sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==} @@ -3081,6 +3447,10 @@ packages: sprintf-js: 1.0.3 dev: true + /argparse/2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + /arr-diff/4.0.0: resolution: {integrity: sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=} engines: {node: '>=0.10.0'} @@ -3134,6 +3504,11 @@ packages: get-value: 2.0.6 kind-of: 5.1.0 + /array-union/2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + /array-unique/0.3.2: resolution: {integrity: sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=} engines: {node: '>=0.10.0'} @@ -3183,6 +3558,30 @@ packages: engines: {node: '>= 4.5.0'} hasBin: true + /autoprefixer/10.4.4_postcss@8.4.12: + resolution: {integrity: sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.20.2 + caniuse-lite: 1.0.30001327 + fraction.js: 4.2.0 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.12 + postcss-value-parser: 4.2.0 + dev: true + + /axios/0.26.1: + resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} + dependencies: + follow-redirects: 1.14.9 + transitivePeerDependencies: + - debug + dev: false + /babel-code-frame/6.26.0: resolution: {integrity: sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=} dependencies: @@ -3766,6 +4165,10 @@ packages: mixin-deep: 1.3.2 pascalcase: 0.1.1 + /base64-js/1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + /binary-extensions/1.13.1: resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} engines: {node: '>=0.10.0'} @@ -3773,7 +4176,6 @@ packages: /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - optional: true /bindings/1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} @@ -3782,6 +4184,14 @@ packages: file-uri-to-path: 1.0.0 optional: true + /bl/4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: true + /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -3857,11 +4267,23 @@ packages: /buffer-from/1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + /buffer/5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + /builtin-modules/3.2.0: resolution: {integrity: sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==} engines: {node: '>=6'} dev: true + /cac/6.7.12: + resolution: {integrity: sha512-rM7E2ygtMkJqD9c7WnFU6fruFcN3xe4FM5yUmgxhZzIKJk4uHl9U/fhwdajGFQbQuv43FAUo1Fe8gX/oIKDeSA==} + engines: {node: '>=8'} + dev: true + /cache-base/1.0.1: resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} engines: {node: '>=0.10.0'} @@ -3915,6 +4337,10 @@ packages: resolution: {integrity: sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA==} dev: true + /caniuse-lite/1.0.30001327: + resolution: {integrity: sha512-1/Cg4jlD9qjZzhbzkzEaAC2JHsP0WrOc8Rd/3a3LuajGzGWR/hD7TVyvq99VqmTy99eVh8Zkmdq213OgvgXx7w==} + dev: true + /chalk/1.1.3: resolution: {integrity: sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=} engines: {node: '>=0.10.0'} @@ -3947,6 +4373,10 @@ packages: engines: {node: '>=10'} dev: true + /charenc/0.0.2: + resolution: {integrity: sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=} + dev: false + /chokidar/2.1.8: resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies @@ -3979,7 +4409,6 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.2 - optional: true /ci-info/3.3.0: resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==} @@ -4005,6 +4434,18 @@ packages: source-map: registry.npmmirror.com/source-map/0.6.1 dev: false + /cli-cursor/3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: true + + /cli-spinners/2.6.1: + resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==} + engines: {node: '>=6'} + dev: true + /cliui/3.2.0: resolution: {integrity: sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=} dependencies: @@ -4027,6 +4468,11 @@ packages: /clone-stats/1.0.0: resolution: {integrity: sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=} + /clone/1.0.4: + resolution: {integrity: sha1-2jCcwmPfFZlMaIypAheco8fNfH4=} + engines: {node: '>=0.8'} + dev: true + /clone/2.1.2: resolution: {integrity: sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=} engines: {node: '>=0.8'} @@ -4115,7 +4561,6 @@ packages: /commander/9.0.0: resolution: {integrity: sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw==} engines: {node: ^12.20.0 || >=14} - dev: false /commondir/1.0.1: resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=} @@ -4136,6 +4581,11 @@ packages: readable-stream: 2.3.7 typedarray: 0.0.6 + /connect-history-api-fallback/1.6.0: + resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} + engines: {node: '>=0.8'} + dev: true + /convert-source-map/1.8.0: resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} dependencies: @@ -4191,6 +4641,25 @@ packages: shebang-command: 2.0.0 which: 2.0.2 + /crypt/0.0.2: + resolution: {integrity: sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=} + dev: false + + /css-tree/2.0.4: + resolution: {integrity: sha512-b4IS9ZUMtGBiNjzYbcj9JhYbyei99R3ai2CSxlu8GQDnoPA/P+NU85hAm0eKDc/Zp660rpK6tFJQ2OSdacMHVg==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + dependencies: + mdn-data: 2.0.23 + source-map-js: 1.0.2 + dev: true + + /csso/5.0.3: + resolution: {integrity: sha512-93gBHTJ6EQlLNhIX5Ho8VAJD2t2T2wg1xHDjbIUm/oQ7iFiSUTo9jSojiQK0pEZ3lMhYDrQO7Rcd70M68+VrtA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + dependencies: + css-tree: 2.0.4 + dev: true + /cssom/0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} dev: true @@ -4208,7 +4677,6 @@ packages: /csstype/2.6.20: resolution: {integrity: sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==} - dev: false /d/1.0.1: resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} @@ -4227,7 +4695,6 @@ packages: /dayjs/1.11.0: resolution: {integrity: sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==} - dev: true /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -4289,6 +4756,12 @@ packages: resolution: {integrity: sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=} engines: {node: '>= 0.10'} + /defaults/1.0.3: + resolution: {integrity: sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=} + dependencies: + clone: 1.0.4 + dev: true + /define-properties/1.1.3: resolution: {integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==} engines: {node: '>= 0.4'} @@ -4333,6 +4806,13 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dev: true + /dir-glob/3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + /domexception/2.0.1: resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} engines: {node: '>=8'} @@ -4371,6 +4851,16 @@ packages: dependencies: once: 1.4.0 + /entities/2.1.0: + resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==} + dev: true + + /envinfo/7.8.1: + resolution: {integrity: sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==} + engines: {node: '>=4'} + hasBin: true + dev: true + /error-ex/1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -4406,32 +4896,421 @@ packages: es6-iterator: 2.0.3 es6-symbol: 3.1.3 + /esbuild-android-64/0.14.28: + resolution: {integrity: sha512-A52C3zq+9tNwCqZ+4kVLBxnk/WnrYM8P2+QNvNE9B6d2OVPs214lp3g6UyO+dKDhUdefhfPCuwkP8j2A/+szNA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /esbuild-android-64/0.14.34: + resolution: {integrity: sha512-XfxcfJqmMYsT/LXqrptzFxmaR3GWzXHDLdFNIhm6S00zPaQF1TBBWm+9t0RZ6LRR7iwH57DPjaOeW20vMqI4Yw==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /esbuild-android-arm64/0.14.28: + resolution: {integrity: sha512-sm0fDEGElZhMC3HLZeECI2juE4aG7uPfMBMqNUhy9CeX399Pz8rC6e78OXMXInGjSdEAwQmCOHmfsP7uv3Q8rA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /esbuild-android-arm64/0.14.34: + resolution: {integrity: sha512-T02+NXTmSRL1Mc6puz+R9CB54rSPICkXKq6+tw8B6vxZFnCPzbJxgwIX4kcluz9p8nYBjF3+lSilTGWb7+Xgew==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-64/0.14.28: + resolution: {integrity: sha512-nzDd7mQ44FvsFHtOafZdBgn3Li5SMsnMnoz1J2MM37xJmR3wGNTFph88KypjHgWqwbxCI7MXS1U+sN4qDeeW6Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-64/0.14.34: + resolution: {integrity: sha512-pLRip2Bh4Ng7Bf6AMgCrSp3pPe/qZyf11h5Qo2mOfJqLWzSVjxrXW+CFRJfrOVP7TCnh/gmZSM2AFdCPB72vtw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-arm64/0.14.28: + resolution: {integrity: sha512-XEq/bLR/glsUl+uGrBimQzOVs/CmwI833fXUhP9xrLI3IJ+rKyrZ5IA8u+1crOEf1LoTn8tV+hInmX6rGjbScw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-arm64/0.14.34: + resolution: {integrity: sha512-vpidSJEBxx6lf1NWgXC+DCmGqesJuZ5Y8aQVVsaoO4i8tRXbXb0whChRvop/zd3nfNM4dIl5EXAky0knRX5I6w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-64/0.14.28: + resolution: {integrity: sha512-rTKLgUj/HEcPeE5XZ7IZwWpFx7IWMfprN7QRk/TUJE1s1Ipb58esboIesUpjirJz/BwrgHq+FDG9ChAI8dZAtQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-64/0.14.34: + resolution: {integrity: sha512-m0HBjePhe0hAQJgtMRMNV9kMgIyV4/qSnzPx42kRMQBcPhgjAq1JRu4Il26czC+9FgpMbFkUktb07f/Lwnc6CA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-arm64/0.14.28: + resolution: {integrity: sha512-sBffxD1UMOsB7aWMoExmipycjcy3HJGwmqE4GQZUTZvdiH4GhjgUiVdtPyt7kSCdL40JqnWQJ4b1l8Y51oCF4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-arm64/0.14.34: + resolution: {integrity: sha512-cpRc2B94L1KvMPPYB4D6G39jLqpKlD3noAMY4/e86iXXXkhUYJJEtTuyNFTa9JRpWM0xCAp4mxjHjoIiLuoCLA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-32/0.14.28: + resolution: {integrity: sha512-+Wxidh3fBEQ9kHcCsD4etlBTMb1n6QY2uXv3rFhVn88CY/JP782MhA57/ipLMY4kOLeSKEuFGN4rtjHuhmRMig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-32/0.14.34: + resolution: {integrity: sha512-8nQaEaoW7MH/K/RlozJa+lE1ejHIr8fuPIHhc513UebRav7HtXgQvxHQ6VZRUkWtep23M6dd7UqhwO1tMOfzQQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-64/0.14.28: + resolution: {integrity: sha512-7+xgsC4LvR6cnzaBdiljNnPDjbkwzahogN+S9uy9AoYw7ZjPnnXc6sjQAVCbqGb7MEgrWdpa6u/Tao79i4lWxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-64/0.14.34: + resolution: {integrity: sha512-Y3of4qQoLLlAgf042MlrY1P+7PnN9zWj8nVtw9XQG5hcLOZLz7IKpU35oeu7n4wvyaZHwvQqDJ93gRLqdJekcQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm/0.14.28: + resolution: {integrity: sha512-L5isjmlLbh9E0WVllXiVETbScgMbth/+XkXQii1WwgO1RvLIfaGrVFz8d2n6EH/ImtgYxPYGx+OcvIKQBc91Rg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm/0.14.34: + resolution: {integrity: sha512-9lpq1NcJqssAF7alCO6zL3gvBVVt/lKw4oetUM7OgNnRX0OWpB+ZIO9FwCrSj/dMdmgDhPLf+119zB8QxSMmAg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm64/0.14.28: + resolution: {integrity: sha512-EjRHgwg+kgXABzyoPGPOPg4d5wZqRnZ/ZAxBDzLY+i6DS8OUfTSlZHWIOZzU4XF7125WxRBg9ULbrFJBl+57Eg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm64/0.14.34: + resolution: {integrity: sha512-IlWaGtj9ir7+Nrume1DGcyzBDlK8GcnJq0ANKwcI9pVw8tqr+6GD0eqyF9SF1mR8UmAp+odrx1H5NdR2cHdFHA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-mips64le/0.14.28: + resolution: {integrity: sha512-krx9SSg7yfiUKk64EmjefOyiEF6nv2bRE4um/LiTaQ6Y/6FP4UF3/Ou/AxZVyR154uSRq63xejcAsmswXAYRsw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-mips64le/0.14.34: + resolution: {integrity: sha512-k3or+01Rska1AjUyNjA4buEwB51eyN/xPQAoOx1CjzAQC3l8rpjUDw55kXyL63O/1MUi4ISvtNtl8gLwdyEcxw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-ppc64le/0.14.28: + resolution: {integrity: sha512-LD0Xxu9g+DNuhsEBV5QuVZ4uKVBMup0xPIruLweuAf9/mHXFnaCuNXUBF5t0DxKl7GQ5MSioKtnb92oMo+QXEw==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-ppc64le/0.14.34: + resolution: {integrity: sha512-+qxb8M9FfM2CJaVU7GgYpJOHM1ngQOx+/VrtBjb4C8oVqaPcESCeg2anjl+HRZy8VpYc71q/iBYausPPbJ+Keg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-riscv64/0.14.28: + resolution: {integrity: sha512-L/DWfRh2P0vxq4Y+qieSNXKGdMg+e9Qe8jkbN2/8XSGYDTPzO2OcAxSujob4qIh7iSl+cknbXV+BvH0YFR0jbg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-riscv64/0.14.34: + resolution: {integrity: sha512-Y717ltBdQ5j5sZIHdy1DV9kieo0wMip0dCmVSTceowCPYSn1Cg33Kd6981+F/3b9FDMzNWldZFOBRILViENZSA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-s390x/0.14.28: + resolution: {integrity: sha512-rrgxmsbmL8QQknWGnAL9bGJRQYLOi2AzXy5OTwfhxnj9eqjo5mSVbJXjgiq5LPUAMQZGdPH5yaNK0obAXS81Zw==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-s390x/0.14.34: + resolution: {integrity: sha512-bDDgYO4LhL4+zPs+WcBkXph+AQoPcQRTv18FzZS0WhjfH8TZx2QqlVPGhmhZ6WidrY+jKthUqO6UhGyIb4MpmA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-netbsd-64/0.14.28: + resolution: {integrity: sha512-h8wntIyOR8/xMVVM6TvJxxWKh4AjmLK87IPKpuVi8Pq0kyk0RMA+eo4PFGk5j2XK0D7dj8PcSF5NSlP9kN/j0A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-netbsd-64/0.14.34: + resolution: {integrity: sha512-cfaFGXdRt0+vHsjNPyF0POM4BVSHPSbhLPe8mppDc7GDDxjIl08mV1Zou14oDWMp/XZMjYN1kWYRSfftiD0vvQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-openbsd-64/0.14.28: + resolution: {integrity: sha512-HBv18rVapbuDx52/fhZ/c/w6TXyaQAvRxiDDn5Hz/pBcwOs3cdd2WxeIKlWmDoqm2JMx5EVlq4IWgoaRX9mVkw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-openbsd-64/0.14.34: + resolution: {integrity: sha512-vmy9DxXVnRiI14s8GKuYBtess+EVcDALkbpTqd5jw4XITutIzyB7n4x0Tj5utAkKsgZJB22lLWGekr0ABnSLow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-sunos-64/0.14.28: + resolution: {integrity: sha512-zlIxePhZxKYheR2vBCgPVvTixgo/ozOfOMoP6RZj8dxzquU1NgeyhjkcRXucbLCtmoNJ+i4PtWwPZTLuDd3bGg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /esbuild-sunos-64/0.14.34: + resolution: {integrity: sha512-eNPVatNET1F7tRMhii7goL/eptfxc0ALRjrj9SPFNqp0zmxrehBFD6BaP3R4LjMn6DbMO0jOAnTLFKr8NqcJAA==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-32/0.14.28: + resolution: {integrity: sha512-am9DIJxXlld1BOAY/VlvBQHMUCPL7S3gB/lnXIY3M4ys0gfuRqPf4EvMwZMzYUbFKBY+/Qb8SRgPRRGhwnJ8Kg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-32/0.14.34: + resolution: {integrity: sha512-EFhpXyHEcnqWYe2rAHFd8dRw8wkrd9U+9oqcyoEL84GbanAYjiiIjBZsnR8kl0sCQ5w6bLpk7vCEIA2VS32Vcg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-64/0.14.28: + resolution: {integrity: sha512-78PhySDnmRZlsPNp/W/5Fim8iivlBQQxfhBFIqR7xwvfDmCFUSByyMKP7LCHgNtb04yNdop8nJJkJaQ8Xnwgiw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-64/0.14.34: + resolution: {integrity: sha512-a8fbl8Ky7PxNEjf1aJmtxdDZj32/hC7S1OcA2ckEpCJRTjiKslI9vAdPpSjrKIWhws4Galpaawy0nB7fjHYf5Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-arm64/0.14.28: + resolution: {integrity: sha512-VhXGBTo6HELD8zyHXynV6+L2jWx0zkKnGx4TmEdSBK7UVFACtOyfUqpToG0EtnYyRZ0HESBhzPSVpP781ovmvA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-arm64/0.14.34: + resolution: {integrity: sha512-EYvmKbSa2B3sPnpC28UEu9jBK5atGV4BaVRE7CYGUci2Hlz4AvtV/LML+TcDMT6gBgibnN2gcltWclab3UutMg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /esbuild/0.14.28: resolution: {integrity: sha512-YLNprkCcMVKQ5sekmCKEQ3Obu/L7s6+iij38xNKyBeSmSsTWur4Ky/9zB3XIGT8SCJITG/bZwAR2l7YOAXch4Q==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - esbuild-android-64: registry.npmmirror.com/esbuild-android-64/0.14.28 - esbuild-android-arm64: registry.npmmirror.com/esbuild-android-arm64/0.14.28 - esbuild-darwin-64: registry.npmmirror.com/esbuild-darwin-64/0.14.28 - esbuild-darwin-arm64: registry.npmmirror.com/esbuild-darwin-arm64/0.14.28 - esbuild-freebsd-64: registry.npmmirror.com/esbuild-freebsd-64/0.14.28 - esbuild-freebsd-arm64: registry.npmmirror.com/esbuild-freebsd-arm64/0.14.28 - esbuild-linux-32: registry.npmmirror.com/esbuild-linux-32/0.14.28 - esbuild-linux-64: registry.npmmirror.com/esbuild-linux-64/0.14.28 - esbuild-linux-arm: registry.npmmirror.com/esbuild-linux-arm/0.14.28 - esbuild-linux-arm64: registry.npmmirror.com/esbuild-linux-arm64/0.14.28 - esbuild-linux-mips64le: registry.npmmirror.com/esbuild-linux-mips64le/0.14.28 - esbuild-linux-ppc64le: registry.npmmirror.com/esbuild-linux-ppc64le/0.14.28 - esbuild-linux-riscv64: registry.npmmirror.com/esbuild-linux-riscv64/0.14.28 - esbuild-linux-s390x: registry.npmmirror.com/esbuild-linux-s390x/0.14.28 - esbuild-netbsd-64: registry.npmmirror.com/esbuild-netbsd-64/0.14.28 - esbuild-openbsd-64: registry.npmmirror.com/esbuild-openbsd-64/0.14.28 - esbuild-sunos-64: registry.npmmirror.com/esbuild-sunos-64/0.14.28 - esbuild-windows-32: registry.npmmirror.com/esbuild-windows-32/0.14.28 - esbuild-windows-64: registry.npmmirror.com/esbuild-windows-64/0.14.28 - esbuild-windows-arm64: registry.npmmirror.com/esbuild-windows-arm64/0.14.28 + esbuild-android-64: 0.14.28 + esbuild-android-arm64: 0.14.28 + esbuild-darwin-64: 0.14.28 + esbuild-darwin-arm64: 0.14.28 + esbuild-freebsd-64: 0.14.28 + esbuild-freebsd-arm64: 0.14.28 + esbuild-linux-32: 0.14.28 + esbuild-linux-64: 0.14.28 + esbuild-linux-arm: 0.14.28 + esbuild-linux-arm64: 0.14.28 + esbuild-linux-mips64le: 0.14.28 + esbuild-linux-ppc64le: 0.14.28 + esbuild-linux-riscv64: 0.14.28 + esbuild-linux-s390x: 0.14.28 + esbuild-netbsd-64: 0.14.28 + esbuild-openbsd-64: 0.14.28 + esbuild-sunos-64: 0.14.28 + esbuild-windows-32: 0.14.28 + esbuild-windows-64: 0.14.28 + esbuild-windows-arm64: 0.14.28 + dev: true + + /esbuild/0.14.34: + resolution: {integrity: sha512-QIWdPT/gFF6hCaf4m7kP0cJ+JIuFkdHibI7vVFvu3eJS1HpVmYHWDulyN5WXwbRA0SX/7ZDaJ/1DH8SdY9xOJg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + esbuild-android-64: 0.14.34 + esbuild-android-arm64: 0.14.34 + esbuild-darwin-64: 0.14.34 + esbuild-darwin-arm64: 0.14.34 + esbuild-freebsd-64: 0.14.34 + esbuild-freebsd-arm64: 0.14.34 + esbuild-linux-32: 0.14.34 + esbuild-linux-64: 0.14.34 + esbuild-linux-arm: 0.14.34 + esbuild-linux-arm64: 0.14.34 + esbuild-linux-mips64le: 0.14.34 + esbuild-linux-ppc64le: 0.14.34 + esbuild-linux-riscv64: 0.14.34 + esbuild-linux-s390x: 0.14.34 + esbuild-netbsd-64: 0.14.34 + esbuild-openbsd-64: 0.14.34 + esbuild-sunos-64: 0.14.34 + esbuild-windows-32: 0.14.34 + esbuild-windows-64: 0.14.34 + esbuild-windows-arm64: 0.14.34 + dev: true /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} @@ -4451,7 +5330,7 @@ packages: esutils: 2.0.3 optionator: 0.8.3 optionalDependencies: - source-map: registry.npmmirror.com/source-map/0.6.1 + source-map: 0.6.1 dev: false /escodegen/2.0.0: @@ -4584,6 +5463,16 @@ packages: parse-node-version: 1.0.1 time-stamp: 1.1.0 + /fast-glob/3.2.11: + resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + /fast-json-stable-stringify/2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true @@ -4594,6 +5483,11 @@ packages: /fast-levenshtein/2.0.6: resolution: {integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=} + /fastq/1.13.0: + resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + dependencies: + reusify: 1.0.4 + /fb-watchman/2.0.1: resolution: {integrity: sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==} dependencies: @@ -4673,6 +5567,16 @@ packages: inherits: 2.0.4 readable-stream: 2.3.7 + /follow-redirects/1.14.9: + resolution: {integrity: sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + /for-in/1.0.2: resolution: {integrity: sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=} engines: {node: '>=0.10.0'} @@ -4692,6 +5596,10 @@ packages: mime-types: 2.1.35 dev: true + /fraction.js/4.2.0: + resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} + dev: true + /fragment-cache/0.2.1: resolution: {integrity: sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=} engines: {node: '>=0.10.0'} @@ -4784,7 +5692,6 @@ packages: engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - optional: true /glob-stream/6.1.0: resolution: {integrity: sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=} @@ -4850,15 +5757,40 @@ packages: engines: {node: '>=0.10.0'} dev: true + /globby/11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.11 + ignore: 5.2.0 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + /glogg/1.0.2: resolution: {integrity: sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==} engines: {node: '>= 0.10'} dependencies: sparkles: 1.0.1 + /graceful-fs/4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + /graceful-fs/4.2.9: resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==} + /gray-matter/4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + dependencies: + js-yaml: 3.14.1 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + dev: true + /gulp-cli/2.3.0: resolution: {integrity: sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==} engines: {node: '>= 0.10'} @@ -4952,6 +5884,10 @@ packages: dependencies: function-bind: 1.1.1 + /hash-sum/2.0.0: + resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} + dev: true + /he/1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -5017,6 +5953,19 @@ packages: engines: {node: '>=10.17.0'} dev: true + /ieee754/1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + + /ignore/5.2.0: + resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} + engines: {node: '>= 4'} + dev: true + + /immutable/4.0.0: + resolution: {integrity: sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==} + dev: true + /import-local/3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} @@ -5090,7 +6039,6 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - optional: true /is-buffer/1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} @@ -5165,6 +6113,11 @@ packages: dependencies: is-extglob: 2.1.1 + /is-interactive/1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + dev: true + /is-keyword-js/1.0.3: resolution: {integrity: sha1-rDDc81tnH0snsX9ctXI1EmAhEy0=} engines: {node: '>=0.10.0'} @@ -5233,6 +6186,11 @@ packages: dependencies: unc-path-regex: 0.1.2 + /is-unicode-supported/0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + /is-utf8/0.2.1: resolution: {integrity: sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=} @@ -5746,7 +6704,7 @@ packages: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 17.0.21 + '@types/node': 17.0.23 merge-stream: 2.0.0 supports-color: 7.2.0 dev: true @@ -5902,8 +6860,14 @@ packages: engines: {node: '>=6'} dev: true + /klona/2.0.5: + resolution: {integrity: sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==} + engines: {node: '>= 8'} + dev: true + /kolorist/1.5.1: resolution: {integrity: sha512-lxpCM3HTvquGxKGzHeknB/sUjuVoUElLlfYnXZT73K8geR9jQbroGlSCFBax9/0mpGoD3kzcMLnOlGQPJJNyqQ==} + dev: true /last-run/1.1.1: resolution: {integrity: sha1-RblpQsF7HHnHchmCWbqUO+v4yls=} @@ -5959,11 +6923,17 @@ packages: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true + /linkify-it/3.0.3: + resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==} + dependencies: + uc.micro: 1.0.6 + dev: true + /load-json-file/1.1.0: resolution: {integrity: sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=} engines: {node: '>=0.10.0'} dependencies: - graceful-fs: 4.2.9 + graceful-fs: 4.2.10 parse-json: 2.2.0 pify: 2.3.0 pinkie-promise: 2.0.1 @@ -5984,6 +6954,14 @@ packages: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true + /log-symbols/4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + /logsets/1.0.8: resolution: {integrity: sha512-9XuCtIjGvAWbi+JgF2+NI5Bb55uvzwgCFvlo/pafXdZjVC0DDri2k+Jzv7hWg0audTrw4FTnIBiSo3yOlEpmHQ==} dependencies: @@ -6009,6 +6987,7 @@ packages: engines: {node: '>=10'} dependencies: yallist: 4.0.0 + dev: true /magic-string/0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} @@ -6051,6 +7030,35 @@ packages: dependencies: object-visit: 1.0.1 + /markdown-it-anchor/8.6.2_d643ca6eb40ae68ab966a77bead78073: + resolution: {integrity: sha512-JNaekTlIwwyYGBN3zifZDxgz4bSL8sbEj58fdTZGmPSMMGXBZapFjcZk2I33Jy79c1fvCKHpF7MA/67FOTjvzA==} + peerDependencies: + '@types/markdown-it': '*' + markdown-it: '*' + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 12.3.2 + dev: true + + /markdown-it-container/3.0.0: + resolution: {integrity: sha512-y6oKTq4BB9OQuY/KLfk/O3ysFhB3IMYoIWhGJEidXt1NQFocFK2sA2t0NYZAMyMShAGL6x5OPIbrmXPIqaN9rw==} + dev: true + + /markdown-it-emoji/2.0.0: + resolution: {integrity: sha512-39j7/9vP/CPCKbEI44oV8yoPJTpvfeReTn/COgRhSpNrjWF3PfP/JUxxB0hxV6ynOY8KH8Y8aX9NMDdo6z+6YQ==} + dev: true + + /markdown-it/12.3.2: + resolution: {integrity: sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==} + hasBin: true + dependencies: + argparse: 2.0.1 + entities: 2.1.0 + linkify-it: 3.0.3 + mdurl: 1.0.1 + uc.micro: 1.0.6 + dev: true + /matchdep/2.0.0: resolution: {integrity: sha1-xvNINKDY28OzfCfui7yyfHd1WC4=} engines: {node: '>= 0.10.0'} @@ -6060,6 +7068,26 @@ packages: resolve: 1.22.0 stack-trace: 0.0.10 + /md5/2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + dev: false + + /mdn-data/2.0.23: + resolution: {integrity: sha512-IonVb7pfla2U4zW8rc7XGrtgq11BvYeCxWN8HS+KFBnLDE7XDK9AAMVhRuG6fj9BBsjc69Fqsp6WEActEdNTDQ==} + dev: true + + /mdurl/1.0.1: + resolution: {integrity: sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=} + dev: true + + /medium-zoom/1.0.6: + resolution: {integrity: sha512-UdiUWfvz9fZMg1pzf4dcuqA0W079o0mpqbTnOz5ip4VGYX96QjmbM+OgOU/0uOzAytxC0Ny4z+VcYQnhdifimg==} + dev: true + /merge-source-map/1.1.0: resolution: {integrity: sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==} dependencies: @@ -6070,6 +7098,10 @@ packages: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + /micromatch/3.1.10: resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} engines: {node: '>=0.10.0'} @@ -6094,7 +7126,6 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true /mime-db/1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} @@ -6131,6 +7162,7 @@ packages: /mrmime/1.0.0: resolution: {integrity: sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==} engines: {node: '>=10'} + dev: true /ms/2.0.0: resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=} @@ -6147,8 +7179,8 @@ packages: requiresBuild: true optional: true - /nanoid/3.3.1: - resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==} + /nanoid/3.3.2: + resolution: {integrity: sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -6172,6 +7204,10 @@ packages: resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=} dev: true + /neo-async/2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true + /next-tick/1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} @@ -6206,6 +7242,11 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + /normalize-range/0.1.2: + resolution: {integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=} + engines: {node: '>=0.10.0'} + dev: true + /now-and-later/2.0.1: resolution: {integrity: sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==} engines: {node: '>= 0.10'} @@ -6219,6 +7260,10 @@ packages: path-key: 3.1.1 dev: true + /nprogress/0.2.0: + resolution: {integrity: sha1-y480xTIT2JVyP8urkH6UIq28r7E=} + dev: true + /number-is-nan/1.0.1: resolution: {integrity: sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=} engines: {node: '>=0.10.0'} @@ -6235,6 +7280,10 @@ packages: define-property: 0.2.5 kind-of: 3.2.2 + /object-inspect/1.12.0: + resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==} + dev: false + /object-keys/1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -6306,6 +7355,21 @@ packages: type-check: 0.3.2 word-wrap: 1.2.3 + /ora/5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.6.1 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + dev: true + /ordered-read-streams/1.0.1: resolution: {integrity: sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=} dependencies: @@ -6421,10 +7485,15 @@ packages: resolution: {integrity: sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=} engines: {node: '>=0.10.0'} dependencies: - graceful-fs: 4.2.9 + graceful-fs: 4.2.10 pify: 2.3.0 pinkie-promise: 2.0.1 + /path-type/4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + /picocolors/1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -6466,11 +7535,25 @@ packages: resolution: {integrity: sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=} engines: {node: '>=0.10.0'} + /postcss-csso/6.0.0_postcss@8.4.12: + resolution: {integrity: sha512-LsrU+LVR0mNIYauoTEbYVC81i+yXcGWa9kqW6Lvm+gYUZTaNTJmJT6Dbv+fqT8gOnwXAH1RV+5RXvAVoRtwO+g==} + engines: {node: ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + csso: 5.0.3 + postcss: 8.4.12 + dev: true + + /postcss-value-parser/4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: true + /postcss/8.4.12: resolution: {integrity: sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.1 + nanoid: 3.3.2 picocolors: 1.0.0 source-map-js: 1.0.2 @@ -6491,6 +7574,11 @@ packages: resolution: {integrity: sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=} engines: {node: '>= 0.8'} + /prismjs/1.27.0: + resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} + engines: {node: '>=6'} + dev: true + /private/0.1.8: resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} engines: {node: '>= 0.6'} @@ -6529,6 +7617,16 @@ packages: engines: {node: '>=6'} dev: true + /qs/6.10.3: + resolution: {integrity: sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: false + + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /randombytes/2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -6570,15 +7668,14 @@ packages: engines: {node: '>= 6'} dependencies: inherits: 2.0.4 - string_decoder: 1.1.1 + string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: false /readdirp/2.2.1: resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} engines: {node: '>=0.10'} dependencies: - graceful-fs: 4.2.9 + graceful-fs: 4.2.10 micromatch: 3.1.10 readable-stream: 2.3.7 @@ -6587,7 +7684,6 @@ packages: engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - optional: true /rechoir/0.6.2: resolution: {integrity: sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=} @@ -6768,10 +7864,22 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /restore-cursor/3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + /ret/0.1.15: resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} engines: {node: '>=0.12'} + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + /rimraf/2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} hasBin: true @@ -6818,6 +7926,12 @@ packages: hasBin: true optionalDependencies: fsevents: 2.3.2 + dev: true + + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 /safe-buffer/5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -6830,6 +7944,40 @@ packages: dependencies: ret: 0.1.15 + /sass-loader/12.6.0_sass@1.50.0: + resolution: {integrity: sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==} + engines: {node: '>= 12.13.0'} + peerDependencies: + fibers: '>= 3.1.0' + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + sass: ^1.3.0 + sass-embedded: '*' + webpack: ^5.0.0 + peerDependenciesMeta: + fibers: + optional: true + node-sass: + optional: true + sass: + optional: true + sass-embedded: + optional: true + dependencies: + klona: 2.0.5 + neo-async: 2.6.2 + sass: 1.50.0 + dev: true + + /sass/1.50.0: + resolution: {integrity: sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + immutable: 4.0.0 + source-map-js: 1.0.2 + dev: true + /saxes/5.0.1: resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} engines: {node: '>=10'} @@ -6837,6 +7985,14 @@ packages: xmlchars: 2.2.0 dev: true + /section-matter/1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + dev: true + /semver-greatest-satisfied-range/1.1.0: resolution: {integrity: sha1-E+jCZYq5aRywzXEJMkAoDTb3els=} engines: {node: '>= 0.10'} @@ -6862,6 +8018,7 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 + dev: true /serialize-javascript/4.0.0: resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} @@ -6900,6 +8057,14 @@ packages: interpret: 1.4.0 rechoir: 0.6.2 + /side-channel/1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.1 + object-inspect: 1.12.0 + dev: false + /signal-exit/3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true @@ -6911,6 +8076,7 @@ packages: '@polka/url': 1.0.0-next.21 mrmime: 1.0.0 totalist: 3.0.0 + dev: true /sisteransi/1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -7078,6 +8244,11 @@ packages: dependencies: safe-buffer: 5.1.2 + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + /strip-ansi/3.0.1: resolution: {integrity: sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=} engines: {node: '>=0.10.0'} @@ -7091,6 +8262,11 @@ packages: ansi-regex: 5.0.1 dev: true + /strip-bom-string/1.0.0: + resolution: {integrity: sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=} + engines: {node: '>=0.10.0'} + dev: true + /strip-bom/2.0.0: resolution: {integrity: sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=} engines: {node: '>=0.10.0'} @@ -7271,9 +8447,14 @@ packages: dependencies: through2: 2.0.5 + /toml/3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + dev: true + /totalist/3.0.0: resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==} engines: {node: '>=6'} + dev: true /tough-cookie/4.0.0: resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==} @@ -7291,6 +8472,10 @@ packages: punycode: 2.1.1 dev: true + /ts-debounce/4.0.0: + resolution: {integrity: sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==} + dev: true + /type-check/0.3.2: resolution: {integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=} engines: {node: '>= 0.8.0'} @@ -7322,8 +8507,13 @@ packages: /typedarray/0.0.6: resolution: {integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=} + /uc.micro/1.0.6: + resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + dev: true + /ufo/0.7.11: resolution: {integrity: sha512-IT3q0lPvtkqQ8toHQN/BkOi4VIqoqheqM1FnkNWT9y0G8B3xJhwnoKBu5OHx8zHDOvveQzfKuFowJ0VSARiIDg==} + dev: true /uglify-js/3.4.10: resolution: {integrity: sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==} @@ -7415,6 +8605,11 @@ packages: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} + /upath/2.0.1: + resolution: {integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==} + engines: {node: '>=4'} + dev: true + /upper-case/1.1.3: resolution: {integrity: sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=} dev: false @@ -7524,6 +8719,7 @@ packages: vite: 2.8.6 transitivePeerDependencies: - supports-color + dev: true /vite/2.8.6: resolution: {integrity: sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug==} @@ -7546,7 +8742,56 @@ packages: resolve: 1.22.0 rollup: 2.70.1 optionalDependencies: - fsevents: registry.npmmirror.com/fsevents/2.3.2 + fsevents: 2.3.2 + dev: true + + /vite/2.9.1: + resolution: {integrity: sha512-vSlsSdOYGcYEJfkQ/NeLXgnRv5zZfpAsdztkIrs7AZHV8RCMZQkwjo4DS5BnrYTqoWqLoUe1Cah4aVO4oNNqCQ==} + engines: {node: '>=12.2.0'} + hasBin: true + peerDependencies: + less: '*' + sass: '*' + stylus: '*' + peerDependenciesMeta: + less: + optional: true + sass: + optional: true + stylus: + optional: true + dependencies: + esbuild: 0.14.34 + postcss: 8.4.12 + resolve: 1.22.0 + rollup: 2.70.1 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vue-demi/0.12.5_vue@3.2.31: + resolution: {integrity: sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.2.31 + dev: true + + /vue-router/4.0.14_vue@3.2.31: + resolution: {integrity: sha512-wAO6zF9zxA3u+7AkMPqw9LjoUCjSxfFvINQj3E/DceTt6uEz1XZLraDhdg2EYmvVwTBSGlLYsUw8bDmx0754Mw==} + peerDependencies: + vue: ^3.2.0 + dependencies: + '@vue/devtools-api': 6.1.4 + vue: 3.2.31 + dev: true /vue/3.2.31: resolution: {integrity: sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw==} @@ -7556,7 +8801,43 @@ packages: '@vue/runtime-dom': 3.2.31 '@vue/server-renderer': 3.2.31_vue@3.2.31 '@vue/shared': 3.2.31 - dev: false + + /vuepress-vite/2.0.0-beta.38: + resolution: {integrity: sha512-jta0bZx+5smMkHI2s7bq+PJdvFK2jn08UsNL81IdLPNw34zwpdRthfT2v2lqtZnJOe2/E4ktWAhzwS3Oxu2GCw==} + hasBin: true + dependencies: + '@vuepress/bundler-vite': 2.0.0-beta.38 + '@vuepress/cli': 2.0.0-beta.38 + '@vuepress/core': 2.0.0-beta.38 + '@vuepress/theme-default': 2.0.0-beta.38 + transitivePeerDependencies: + - '@vue/composition-api' + - fibers + - less + - node-sass + - sass + - sass-embedded + - stylus + - supports-color + - webpack + dev: true + + /vuepress/2.0.0-beta.38: + resolution: {integrity: sha512-NM6ekt5/aBsfPsp1VzuR8dEnia1nicmxFus/HMAe1x222jFGIr6XbX89jYYJuaPFMA4QwMcblY/PD6MCE65SrQ==} + hasBin: true + dependencies: + vuepress-vite: 2.0.0-beta.38 + transitivePeerDependencies: + - '@vue/composition-api' + - fibers + - less + - node-sass + - sass + - sass-embedded + - stylus + - supports-color + - webpack + dev: true /w3c-hr-time/1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} @@ -7577,6 +8858,12 @@ packages: makeerror: 1.0.12 dev: true + /wcwidth/1.0.1: + resolution: {integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=} + dependencies: + defaults: 1.0.3 + dev: true + /webidl-conversions/5.0.0: resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} engines: {node: '>=8'} @@ -7689,6 +8976,7 @@ packages: /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true /yargs-parser/20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} @@ -7814,14 +9102,6 @@ packages: concat-map: registry.npmmirror.com/concat-map/0.0.1 dev: false - registry.npmmirror.com/brace-expansion/2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz} - name: brace-expansion - version: 2.0.1 - dependencies: - balanced-match: registry.npmmirror.com/balanced-match/1.0.2 - dev: false - registry.npmmirror.com/buffer/5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz} name: buffer @@ -7936,206 +9216,6 @@ packages: name: emoji-regex version: 8.0.0 - registry.npmmirror.com/esbuild-android-64/0.14.28: - resolution: {integrity: sha512-A52C3zq+9tNwCqZ+4kVLBxnk/WnrYM8P2+QNvNE9B6d2OVPs214lp3g6UyO+dKDhUdefhfPCuwkP8j2A/+szNA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.14.28.tgz} - name: esbuild-android-64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-android-arm64/0.14.28: - resolution: {integrity: sha512-sm0fDEGElZhMC3HLZeECI2juE4aG7uPfMBMqNUhy9CeX399Pz8rC6e78OXMXInGjSdEAwQmCOHmfsP7uv3Q8rA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.28.tgz} - name: esbuild-android-arm64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-darwin-64/0.14.28: - resolution: {integrity: sha512-nzDd7mQ44FvsFHtOafZdBgn3Li5SMsnMnoz1J2MM37xJmR3wGNTFph88KypjHgWqwbxCI7MXS1U+sN4qDeeW6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.28.tgz} - name: esbuild-darwin-64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-darwin-arm64/0.14.28: - resolution: {integrity: sha512-XEq/bLR/glsUl+uGrBimQzOVs/CmwI833fXUhP9xrLI3IJ+rKyrZ5IA8u+1crOEf1LoTn8tV+hInmX6rGjbScw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.28.tgz} - name: esbuild-darwin-arm64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-freebsd-64/0.14.28: - resolution: {integrity: sha512-rTKLgUj/HEcPeE5XZ7IZwWpFx7IWMfprN7QRk/TUJE1s1Ipb58esboIesUpjirJz/BwrgHq+FDG9ChAI8dZAtQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.28.tgz} - name: esbuild-freebsd-64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-freebsd-arm64/0.14.28: - resolution: {integrity: sha512-sBffxD1UMOsB7aWMoExmipycjcy3HJGwmqE4GQZUTZvdiH4GhjgUiVdtPyt7kSCdL40JqnWQJ4b1l8Y51oCF4Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.28.tgz} - name: esbuild-freebsd-arm64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-linux-32/0.14.28: - resolution: {integrity: sha512-+Wxidh3fBEQ9kHcCsD4etlBTMb1n6QY2uXv3rFhVn88CY/JP782MhA57/ipLMY4kOLeSKEuFGN4rtjHuhmRMig==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.14.28.tgz} - name: esbuild-linux-32 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-linux-64/0.14.28: - resolution: {integrity: sha512-7+xgsC4LvR6cnzaBdiljNnPDjbkwzahogN+S9uy9AoYw7ZjPnnXc6sjQAVCbqGb7MEgrWdpa6u/Tao79i4lWxg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.14.28.tgz} - name: esbuild-linux-64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-linux-arm/0.14.28: - resolution: {integrity: sha512-L5isjmlLbh9E0WVllXiVETbScgMbth/+XkXQii1WwgO1RvLIfaGrVFz8d2n6EH/ImtgYxPYGx+OcvIKQBc91Rg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.28.tgz} - name: esbuild-linux-arm - version: 0.14.28 - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-linux-arm64/0.14.28: - resolution: {integrity: sha512-EjRHgwg+kgXABzyoPGPOPg4d5wZqRnZ/ZAxBDzLY+i6DS8OUfTSlZHWIOZzU4XF7125WxRBg9ULbrFJBl+57Eg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.28.tgz} - name: esbuild-linux-arm64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-linux-mips64le/0.14.28: - resolution: {integrity: sha512-krx9SSg7yfiUKk64EmjefOyiEF6nv2bRE4um/LiTaQ6Y/6FP4UF3/Ou/AxZVyR154uSRq63xejcAsmswXAYRsw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.28.tgz} - name: esbuild-linux-mips64le - version: 0.14.28 - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-linux-ppc64le/0.14.28: - resolution: {integrity: sha512-LD0Xxu9g+DNuhsEBV5QuVZ4uKVBMup0xPIruLweuAf9/mHXFnaCuNXUBF5t0DxKl7GQ5MSioKtnb92oMo+QXEw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.28.tgz} - name: esbuild-linux-ppc64le - version: 0.14.28 - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-linux-riscv64/0.14.28: - resolution: {integrity: sha512-L/DWfRh2P0vxq4Y+qieSNXKGdMg+e9Qe8jkbN2/8XSGYDTPzO2OcAxSujob4qIh7iSl+cknbXV+BvH0YFR0jbg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.28.tgz} - name: esbuild-linux-riscv64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-linux-s390x/0.14.28: - resolution: {integrity: sha512-rrgxmsbmL8QQknWGnAL9bGJRQYLOi2AzXy5OTwfhxnj9eqjo5mSVbJXjgiq5LPUAMQZGdPH5yaNK0obAXS81Zw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.28.tgz} - name: esbuild-linux-s390x - version: 0.14.28 - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-netbsd-64/0.14.28: - resolution: {integrity: sha512-h8wntIyOR8/xMVVM6TvJxxWKh4AjmLK87IPKpuVi8Pq0kyk0RMA+eo4PFGk5j2XK0D7dj8PcSF5NSlP9kN/j0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.28.tgz} - name: esbuild-netbsd-64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-openbsd-64/0.14.28: - resolution: {integrity: sha512-HBv18rVapbuDx52/fhZ/c/w6TXyaQAvRxiDDn5Hz/pBcwOs3cdd2WxeIKlWmDoqm2JMx5EVlq4IWgoaRX9mVkw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.28.tgz} - name: esbuild-openbsd-64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-sunos-64/0.14.28: - resolution: {integrity: sha512-zlIxePhZxKYheR2vBCgPVvTixgo/ozOfOMoP6RZj8dxzquU1NgeyhjkcRXucbLCtmoNJ+i4PtWwPZTLuDd3bGg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.28.tgz} - name: esbuild-sunos-64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-windows-32/0.14.28: - resolution: {integrity: sha512-am9DIJxXlld1BOAY/VlvBQHMUCPL7S3gB/lnXIY3M4ys0gfuRqPf4EvMwZMzYUbFKBY+/Qb8SRgPRRGhwnJ8Kg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.14.28.tgz} - name: esbuild-windows-32 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-windows-64/0.14.28: - resolution: {integrity: sha512-78PhySDnmRZlsPNp/W/5Fim8iivlBQQxfhBFIqR7xwvfDmCFUSByyMKP7LCHgNtb04yNdop8nJJkJaQ8Xnwgiw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.14.28.tgz} - name: esbuild-windows-64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - optional: true - - registry.npmmirror.com/esbuild-windows-arm64/0.14.28: - resolution: {integrity: sha512-VhXGBTo6HELD8zyHXynV6+L2jWx0zkKnGx4TmEdSBK7UVFACtOyfUqpToG0EtnYyRZ0HESBhzPSVpP781ovmvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.28.tgz} - name: esbuild-windows-arm64 - version: 0.14.28 - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - optional: true - registry.npmmirror.com/escape-string-regexp/1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz} name: escape-string-regexp @@ -8187,15 +9267,6 @@ packages: version: 1.0.0 dev: false - registry.npmmirror.com/fsevents/2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz} - name: fsevents - version: 2.3.2 - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - optional: true - registry.npmmirror.com/function-bind/1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz} name: function-bind @@ -8338,7 +9409,7 @@ packages: dependencies: universalify: registry.npmmirror.com/universalify/2.0.0 optionalDependencies: - graceful-fs: registry.npmmirror.com/graceful-fs/4.2.9 + graceful-fs: 4.2.9 dev: false registry.npmmirror.com/lodash/4.17.21: @@ -8382,15 +9453,6 @@ packages: brace-expansion: registry.npmmirror.com/brace-expansion/1.1.11 dev: false - registry.npmmirror.com/minimatch/5.0.1: - resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/minimatch/-/minimatch-5.0.1.tgz} - name: minimatch - version: 5.0.1 - engines: {node: '>=10'} - dependencies: - brace-expansion: registry.npmmirror.com/brace-expansion/2.0.1 - dev: false - registry.npmmirror.com/mute-stream/0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mute-stream/-/mute-stream-0.0.8.tgz} name: mute-stream diff --git a/readme.md b/readme.md index 1bc6134..3ac6138 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,3 @@ - -# ** 测试阶段,有问题请issues ** - [![star](https://gitee.com/zhangfisher/voerka-i18n/badge/star.svg?theme=white)](https://gitee.com/zhangfisher/voerka-i18n/stargazers) # 前言 @@ -17,15 +14,17 @@ - 基于此就开始造出`VoerkaI18n`这个全新的国际化多语言解决方案,主要特性包括: + 基于此就开始造出`VoerkaI18n`这个**全新的国际化多语言解决方案**,主要特性包括: -- 简单易用 + + +- 全面工程化解决方案,提供初始化、提取文本、自动翻译、编译等工具链支持。 - 符合直觉,不需要手动定义文本`Key`映射。 -- 完整的自动化工具链支持,包括项目初始化、提取文本、编译语言等。 +- 强大的插值变量`格式化器`机制,可以扩展出强大的多语言特性。 -- 支持`babel`插件自动导入t翻译函数。 +- 支持`babel`插件自动导入`t`翻译函数。 - 支持`nodejs`、浏览器(`vue`/`react`)前端环境。 @@ -33,12 +32,12 @@ - 高度可扩展的`复数`、`货币`、`数字`等常用的多语言处理机制。 -- 通过`格式化器`可以扩展出强大的多语言特性。 - - 翻译过程内,提取文本可以自动进行同步,并保留已翻译的内容。 - 可以随时添加支持的语言 +- 支持调用在线自动翻译对提取文本进行翻译。 + # 安装 @@ -126,16 +125,16 @@ console.log(t("中华人民共和国成立于{}",1949)) { "languages": [ { - "name": "cn", - "title": "cn" + "name": "zh", + "title": "zh" }, { "name": "en", "title": "en" } ], - "defaultLanguage": "cn", - "activeLanguage": "cn", + "defaultLanguage": "zh", + "activeLanguage": "zh", "namespaces": {} } ``` @@ -181,13 +180,13 @@ myapp **如果略过第一步中的`voerkai18n init`,也可以使用以下命令来为创建和更新`settinbgs.json`** ```javascript -myapp>voerkai18n extract -D -lngs cn en de jp -d cn -a cn +myapp>voerkai18n extract -D -lngs zh en de jp -d zh -a zh ``` 以上命令代表: - 扫描当前文件夹下所有源码文件,默认是`js`、`jsx`、`html`、`vue`文件类型。 -- 计划支持`cn`、`en`、`de`、`jp`四种语言 +- 计划支持`zh`、`en`、`de`、`jp`四种语言 - 默认语言是中文。(指在源码文件中我们直接使用中文即可) - 激活语言是中文(即默认切换到中文) - `-D`代表显示扫描调试信息 @@ -223,6 +222,14 @@ myapp>voerkai18n extract -D -lngs cn en de jp -d cn -a cn 因此,反复执行`voerkai18n extract`命令是安全的,不会导致进行了一半的翻译内容丢失,可以放心执行。 +大部分国际化解决方案至此就需要交给人工进行翻译了,但是`voerkai18n`除了手动翻译外,通过`voerkai18n translate`命令来实现**调用在线翻译服务**进行自动翻译。 + +```javascript +>voerkai18n translate --provider baidu --appkey <在百度翻译上申请的密钥> --appid <在百度翻译上申请的appid> +``` + + 在项目文件夹下执行上面的语句,将会自动调用百度的在线翻译API进行翻译,以现在的翻译水平而言,您只需要进行少量的微调即可。关于`voerkai18n translate`命令的使用请查阅后续介绍。 + ## 第五步:编译语言包 当我们完成`myapp/languages/translates`下的所有`JSON语言文件`的翻译后(如果配置了名称空间后,每一个名称空间会对应生成一个文件,详见后续`名称空间`介绍),接下来需要对翻译后的文件进行编译。 @@ -239,7 +246,7 @@ myapp> voerkai18n compile |-- idMap.js // 文本信息id映射表 |-- runtime.js // 运行时源码 |-- index.js // 包含该应用作用域下的翻译函数等 - |-- cn.js // 语言包 + |-- zh.js // 语言包 |-- en.js |-- jp.js |-- de.js @@ -258,7 +265,9 @@ myapp> voerkai18n compile import { t } from "./languages" ``` -因此,我们需要在需要进行翻译时导入该函数即可。但是如果源码文件很多,重次重复导入`t`函数也是比较麻烦的,所以我们也提供了一个`babel插件`来自动导入`t`函数。 +因此,我们需要在需要进行翻译时导入该函数即可。 + +但是如果源码文件很多,重次重复导入`t`函数也是比较麻烦的,所以我们也提供了一个`babel/vite`等插件来自动导入`t`函数。 ## 第六步:切换语言 @@ -362,8 +371,6 @@ t("我姓名叫{name},我今年{age}岁","tom",()=>12) `voerka-i18n`支持强大的插值变量格式化机制,可以在插值变量中使用`{变量名称 | 格式化器名称 | 格式化器名称(...参数) | ... }`类似管道操作符的语法,将上一个输出作为下一个输入,从而实现对变量值的转换。此机制是`voerka-i18n`实现复数、货币、数字等多语言支持的基础。 -### **格式化器语法** - 我们假设定义以下格式化器(如果定义格式化器,详见后续)来进行示例。 - **UpperCase**:将字符转换为大写 @@ -408,8 +415,6 @@ t("My name is { name | UpperCase | mr }",{name:"tom"}) `{data | f1 | f2 | f3(1)}`等效于` f3(f2(f1(data)),1)` - - ## 日期时间 `@voerkai18n/runtime`内置了对日期时间进行处理的格式化器,可以直接使用,不需要额外的安装。 @@ -519,7 +524,7 @@ t("{name}有{$count}辆车",{name:"张三",$count:1}) "Chapter Five","Chapter Six","Chapter Seven","Chapter Eight","Chapter Nine", "Chapter {}" ], - cn:["起始","第一章", "第二章", "第三章","第四章","第五章","第六章","第七章","第八章","第九章",“第{}章”] + zh:["起始","第一章", "第二章", "第三章","第四章","第五章","第六章","第七章","第八章","第九章",“第{}章”] } } // 翻译函数 @@ -827,7 +832,7 @@ module.exports = { // [数据类型名称]:(value)=>{...}, // [数据类型名称]:(value)=>{...}, }, - cn:{ + zh:{ $types:{ // 所有类型的默认格式化器 "*":{ @@ -890,7 +895,7 @@ t("灯状态:{status}",false) // === 灯状态:OFF ```javascript //formatters.js module.exports = { - cn:{ + zh:{ $types:{ Boolean:(value)=> value ? "开" : "关" } @@ -918,7 +923,7 @@ t("灯状态:{status}",false) // === 灯状态:OFF "*":{ $types:{...} }, - cn:{ + zh:{ $types:{...} }, en:{ @@ -947,7 +952,7 @@ module.exports = { $types:{...}, [格式化名称]:(value)=>{.....}, }, - cn:{ + zh:{ $types:{...}, [格式化名称]:(value)=>{.....}, }, @@ -966,7 +971,7 @@ module.exports = { "*":{ uppercase:(value)=>value }, - cn:{ + zh:{ uppercase:(value)=>["一","二","三","四","五","六","七","八","九","十"][value-1] }, en:{ @@ -1015,7 +1020,7 @@ t("{value | uppercase}",3) // == 3 当使用`webpack`、`rollup`、`esbuild`进行项目打包时,默认语言包采用静态加载,会被打包进行源码中,而其他语言则采用异步打包方式。在`languages/index.js`中。 ```javascript -const defaultMessages = require("./cn.js") +const defaultMessages = require("./zh.js") const activeMessages = defaultMessages // 语言作用域 @@ -1031,6 +1036,18 @@ const scope = new i18nScope({ }) ``` +## 自动翻译 + +内置的`voerkai18n translate`命令能调用在线翻译服务完成对提取的文本的自动翻译。 + +目前支持访问百度在线API进行自动翻译。百度提供了免费的在线API,虽然只支持`QPS=1`,即每秒调用一次。但是`voerkai18n translate`命令会对要翻译的文本进行合并后再调用,因此大部分情况下,均足够使用了。 + +执行`voerkai18n translate`命令后,将大大提高您国际化的效率。 + +## 语言代码 + +请参阅https://fanyi-api.baidu.com/doc/21。 + # 扩展工具 ## babel插件 @@ -1191,7 +1208,6 @@ app.use(i18nPlugin,{ ``` - 当`forceUpdate=true`时,`@voerkai18n/vue`插件在切换语言时会调用`app._instance.update()`对整个应用进行强制重新渲染。大部分情况下,切换语言时强制对整个应用进行重新渲染的行为是符合预期的。您也可以能够通过设`forceUpdate=false`来禁用强制重新渲染,此时,界面就不会马上看到语言的切换,需要您自己控制进行重新渲染。 -- ## Vite插件 @@ -1226,8 +1242,7 @@ export default defineConfig({ ``` -- ` vite-plugin-inspect`是开发`vite`插件时的调试插件,启用后就可以通过`localhost:3000/__inspect/ `查看Vue源码文件经过插件处理前后的内容,一般是Vite插件开发者使用。上例中安装后,就可以查看`Voerkai18nPlugin`对Vue文件干了什么事,可以加深理解,**正常使用不需要安装**。 -- `vite`插件 +- ` vite-plugin-inspect`是开发`vite`插件时的调试插件,启用后就可以通过`localhost:3000/__inspect/ `查看Vue源码文件经过插件处理前后的内容,一般是Vite插件开发者使用。上例中安装后,就可以查看`Voerkai18nPlugin`对`Vue`文件干了什么事,可以加深理解,**正常使用不需要安装**。 ### 插件功能 @@ -1284,10 +1299,10 @@ export default defineConfig({ - `正则表达式`比较容易理解,匹配上的就进行处理。 - `正则表达式字符串`支持一些简单的语法扩展,包括: - - 可以通过前置`!`符号来进行排除匹配。 - - 将`**`替换为`.*`,允许使用类似`"/code/apps/test/**/node_modules/**"`的形式来匹配连续路径。 - - 将`?`替换为`[^\/]?` - - 将`*`替换为`[^\/]*` + - `!`符号:添加在字符串前面来进行排除匹配。 + - `**`:将`**`替换为`.*`,允许使用类似`"/code/apps/test/**/node_modules/**"`的形式来匹配连续路径。 + - `?`:将`?`替换为`[^\/]?`,用来匹配单个字符 + - `*`:将`*`替换为`[^\/]*`,匹配路径名称 ## React扩展 @@ -1335,7 +1350,7 @@ Arguments: Options: -D, --debug 输出调试信息 -r, --reset 重新生成当前项目的语言配置 - -lngs, --languages 支持的语言列表 (default: ["cn","en"]) + -lngs, --languages 支持的语言列表 (default: ["zh","en"]) -d, --defaultLanguage 默认语言 -a, --activeLanguage 激活语言 -h, --help display help for command @@ -1347,7 +1362,7 @@ Options: ```javascript //- `lngs`参数用来指定拟支持的语言名称列表 -> voerkai18n init . -lngs cn en jp de -d cn +> voerkai18n init . -lngs zh en jp de -d zh ``` 运行`voerkai18n init`命令后,会在当前工程中创建相应配置文件。 @@ -1367,7 +1382,7 @@ module.exports = { // 拟支持的语言列表 "languages": [ { - "name": "cn", + "name": "zh", "title": "中文" }, { @@ -1376,9 +1391,9 @@ module.exports = { } ], // 默认语言,即准备在源码中写的语言,一般我们可以直接使用中文 - "defaultLanguage": "cn", + "defaultLanguage": "zh", // 激活语言,即默认要启用的语言,一般等于defaultLanguage - "activeLanguage": "cn", + "activeLanguage": "zh", // 翻译名称空间定义,详见后续介绍。 "namespaces": {} } @@ -1442,6 +1457,61 @@ Options: > >如果想添加新的语言支持,也`voerkai18n extract`也可以如预期的正常工作。 +## translate + +在工程文件夹下执行`voerkai18n translate`命令,该命令会读取`languages/settings.json`配置文件,并调用在线翻译服务(如百度在线翻译)对提取的文本(`languages/translates/*.json`)进行自动翻译。 + +```shell +Usage: voerkai18n translate [options] [location] + +调用在线翻译服务商的API翻译译指定项目的语言包,如使用百度云翻译服务 + +Arguments: + location 工程项目所在目录 + +Options: + -p, --provider 在线翻译服务提供者名称或翻译脚本文件 (default: "baidu") + -m, --max-package-size 将多个文本合并提交的最大包字节数 (default: 3000) + --appkey [key] API密钥 + --appid [id] API ID + --no-backup 备份原始文件 + --mode 翻译模式,取值auto=仅翻译未翻译的,full=全部翻译 + -q, --qps 翻译速度限制,即每秒可调用的API次数 (default: 1) + -h, --help 显示帮助 +``` + +- 内置支持调用百度的在线翻译服务,您需要百度的网站上(http://api.fanyi.baidu.com/)申请开通服务,开通后可以得到`appid`和`appkey`(密钥)。 + +- `--provider`用来指定在线翻译服务提供者,内置支持的是百度在线翻译。也可以传入一个js脚本,如下: + + ```javascript + // youdao.js + module.exports = async function(options){ + let { appkey,appid } = options + return { + translate:async (texts,from,to){ + // texts是一个Array + // from,to代表要从哪一种语言翻译到何种语言 + ..... + // 在此对texts内容调用在线翻译API + // 翻译结果应该返回与texts对应的数组 + // 如果出错则应该throw new Error() + return [...] + } + } + } + ``` + +- `qps`用来指定调用在线翻译API的速度,默认是1,代表每秒调用一次;此参数的引入是考虑到有些翻译平台的免费API有QPS限制。比如百度在线翻译免费版本限制`QPS`就是1,即每秒只能调用一次。如果您购买了服务,则可以将`QPS`调高。 + +- 默认情况下,每次运行时均会备份原始的翻译文件至`languages/translates/backup`,`--no-backup`可以禁止备份。 + +- 默认情况下,`voerkai18n translate`会在每次运行时跳过已经翻译过的内容,这样可以保留翻译成果。此特性在您对自动翻译的内容进行修改后,再多次运行`voerkai18n translate`命令时均能保留翻译内容,不会导致您修改调整过的内容丢失。`--mode full`参数可以完全覆盖翻译,请慎用。 + +- 为了提高在线翻译的速度,`voerkai18n translate`并不是一条文本调用一次API,而是将多条文本合并起来进行调用,但是单次调用也是有数据包大小的限制的,`--max-package-size`参数用来指定数据包的最大值。比如百度建议,为保证翻译质量,请将单次请求长度控制在 6000 bytes以内(汉字约为输入参数 2000 个)。 + +- 需要注意的是,自动翻译虽然准确性还不错,真实场景还是需要进行手工调整的,特别是自动翻译一般不能识别插值变量。 + ## compile 编译当前工程的语言包,编译结果输出在.`/langauges`文件夹。 @@ -1457,6 +1527,7 @@ Arguments: Options: -D, --debug 输出调试信息 -m, --moduleType [types] 输出模块类型,取值auto,esm,cjs (default: "esm") + --no-inline-runtime 不嵌入运行时源码 -h, --help display help for command ``` @@ -1468,7 +1539,7 @@ myapp |-- index.js // 当前作用域的源码 |-- idMap.js // 翻译文本与id的映射文件 |-- formatters.js // 自定义格式化器 - |-- cn.js // 中文语言包 + |-- zh.js // 中文语言包 |-- en.js // 英文语言包 |-- xx.js // 其他语言包 |-- ... @@ -1478,7 +1549,8 @@ myapp - 在当前工程目录下,一般不需要指定参数就可以反复多次进行编译。 - 您每次修改了源码并`extract`后,均应该再次运行`compile`命令。 -- 如果您修改了`formatters.js`,执行compile命令不会修改该文件。 +- 如果您修改了`formatters.js`,执行`compile`命令不会重新生成和修改该文件。 +- `--no-inline-runtime `参数用来指示如何引用运行时。默认会将运行时代码生成保存在`languages/runtime.js`,应用以源码形式引用。当启用`--no-inline-runtime `参数时会采用`require("@voerkai18n/runtime")`的方式。 # API @@ -1496,12 +1568,12 @@ i18nScope.off(callback) // 当前作用域配置 i18nScope.settings // 当前语言 -i18nScope.activeLanguage // 如cn +i18nScope.activeLanguage // 如zh // 默认语言 i18nScope.defaultLanguage // 返回当前支持的语言列表,可以用来显示 -i18nScope.languages // [{name:"cn",title:"中文"},{name:"en",title:"英文"},...] +i18nScope.languages // [{name:"zh",title:"中文"},{name:"en",title:"英文"},...] // 返回当前作用域的格式化器 i18nScope.formatters // 当前作用id diff --git a/test/app.test.js b/test/app.test.js new file mode 100644 index 0000000..cb44982 --- /dev/null +++ b/test/app.test.js @@ -0,0 +1,145 @@ +/** + * 测试demp app的语言运行环境 + * + * > pnpm test:app + * + * 执行本测试用例时需要确保packages/apps/test文件夹没有被占用 + * + */ + +const path = require("path"); +const fs = require("fs-extra"); +const shelljs = require("shelljs"); +const os = require("os") + + + +// 演示的项目名称 + + +const APP_FOLDER = path.join(__dirname, "../packages/apps/test"); +const LANGUAGE_FOLDER = path.join(APP_FOLDER, "languages"); +const TRANSLATES_FOLDER = path.join(LANGUAGE_FOLDER, "translates"); + +let SUPPORTED_LANGUAGES = ["zh", "en","de","jp","fr"]; +let DEFAULT_LANGUAGE = "zh" +let ACTIVE_LANGUAGE = "zh" + +const CN_TEXTS = ["一","二","三","四","五"]; +const EN_TEXTS = ["One","Two","Three","Four","Five"]; + +function createTestApp(){ + if(fs.existsSync(APP_FOLDER)) resetTestApp() + fs.mkdirSync(APP_FOLDER); + // 创建package.json + const pkgFile = path.join(APP_FOLDER, "package.json"); + fs.writeFileSync(pkgFile, JSON.stringify({ + name: "@voerkai18n/testapp", + main:"./index.js", + scripts: { + "release": "pnpm autopublish" + } + },null,4)) + // 创建index.js + const indexFile = path.join(APP_FOLDER, "index.js"); + fs.writeFileSync(indexFile, ` +const { t,i18nScope } = require("./languages/index.js"); +let cn_messages, en_messages +async function output(){ + cn_messages = t("一")+t("二")+t("三")+t("四")+t("五") + console.log(cn_messages) + await i18nScope.change("en") + en_messages = t("一")+t("二")+t("三")+t("四")+t("五") + console.log(en_messages) +} +output().then(()=>{}) +module.exports = { + change:async (lang)=> await i18nScope.change(lang), + getMessages:()=>{ + return t("一")+t("二")+t("三")+t("四")+t("五") + } +} +`) +} + +function resetTestApp(){ + fs.removeSync(APP_FOLDER); +} + +beforeAll(() => { + shelljs.exec("pnpm update -g @voerkai18n/utils") + shelljs.exec("pnpm update -g @voerkai18n/runtime ") + shelljs.exec("pnpm update -g @voerkai18n/cli ") + createTestApp() + shelljs.cd(APP_FOLDER); +}) + + +test("工程目录国际化",done=>{ + let { code } = shelljs.exec(`voerkai18n init -lngs ${SUPPORTED_LANGUAGES.join(" ")} -r -a ${ACTIVE_LANGUAGE} -d ${DEFAULT_LANGUAGE}`,{silent:true}) + expect(code).toBe(0) + expect(fs.existsSync(LANGUAGE_FOLDER)).toBe(true) + + const settingsFile = path.join(LANGUAGE_FOLDER, "settings.json"); + expect(fs.existsSync(settingsFile)).toBe(true) + + const langSettings = fs.readJSONSync(settingsFile); + expect(langSettings.languages.map(lng=>lng.name).join(",")).toEqual(SUPPORTED_LANGUAGES.join(",")); + expect(langSettings.defaultLanguage).toEqual(DEFAULT_LANGUAGE); + expect(langSettings.activeLanguage).toEqual(ACTIVE_LANGUAGE); + done() +}) + +test("提取文本",(done) =>{ + + let code = shelljs.exec(`voerkai18n extract`).code; + expect(code).toEqual(0); + + // 翻译文件夹 + expect(fs.existsSync(TRANSLATES_FOLDER)).toBe(true); + // 翻译文件 + const msgFile = path.join(TRANSLATES_FOLDER,"default.json") + expect(fs.existsSync(msgFile)).toBe(true); + let messages = fs.readJSONSync(msgFile) + messages = fs.readJSONSync(msgFile) + + expect(CN_TEXTS.every(text=>text in messages)).toBeTruthy(); + + for(let [text,lngs] of Object.entries(messages)){ + expect(SUPPORTED_LANGUAGES.every(lng=>lng===DEFAULT_LANGUAGE || (lng in lngs))).toBeTruthy(); + } + + done() +}) + + +test("编译多语言",(done) =>{ + // 模拟翻译英文文件 + const msgFile = path.join(TRANSLATES_FOLDER,"default.json") + let messages = fs.readJSONSync(msgFile) + messages["一"]["en"] = "One" + messages["二"]["en"] = "Two" + messages["三"]["en"] = "Three" + messages["四"]["en"] = "Four" + messages["五"]["en"] = "Five" + fs.writeFileSync(msgFile,JSON.stringify(messages,null,2)) + + const code = shelljs.exec(`voerkai18n compile -m cjs`).code + expect(code).toEqual(0); + // 是否生成所有的文件 + const filesIsGenerated = ["index.js","idMap.js","formatters.js","runtime.js"].every(filename=>fs.existsSync(path.join(LANGUAGE_FOLDER,filename))); + expect(filesIsGenerated).toBeTruthy(); + expect(SUPPORTED_LANGUAGES.every(lng=>fs.existsSync(path.join(LANGUAGE_FOLDER,`${lng}.js`)))).toBe(true); + done() +}) + + +test("切换语言",async () =>{ + const { change,getMessages } = require(path.join(APP_FOLDER,"index.js")) + expect(getMessages()).toEqual(CN_TEXTS.join("")); + await change("en"); + expect(getMessages()).toEqual(EN_TEXTS.join("")); +}) + + + diff --git a/test/cli.test.js b/test/cli.test.js deleted file mode 100644 index cca39de..0000000 --- a/test/cli.test.js +++ /dev/null @@ -1,163 +0,0 @@ -/** - * 测试demp app的语言运行环境 - */ - -const path = require("path"); -const fs = require("fs-extra"); -const shelljs = require("shelljs"); - -const APP_FOLDER = path.join(__dirname, "../demo/apps/app"); -const LANGUAGE_FOLDER = path.join(APP_FOLDER, "languages"); -const TRANSLATES_FOLDER = path.join(LANGUAGE_FOLDER, "translates"); - -const CLI_INDEX_FILE = path.join(__dirname, "../cli/index.js"); - -let SUPPORTED_LANGUAGES = ["cn", "en"]; -let DEFAULT_LANGUAGE = "cn" -let ACTIVE_LANGUAGE = "cn" -let MODULE_TYPE = "module" - - - -async function importModule(url,onlyDefault=true) { - try{ - return require(url) - }catch(e){ - const result = await import(`file:///${url}`) - return onlyDefault ? result.default : result - } -} - -function createAppIndexFile(){ - fs.writeFileSync(path.join(APP_FOLDER, "index.js"), ` - t("a") - t("b") - t("c") - t("d") - t("e") - `) -} - -// 重置演示应用 -function resetDemoApp(){ - fs.removeSync(LANGUAGE_FOLDER) -} -// 清除提取结果 -function clearExtractResults(){ - fs.emptyDirSync(path.join(LANGUAGE_FOLDER, "translates")) -} -// 清除编译结果 -function clearCompileResults(){ - fs.removeSync(path.join(LANGUAGE_FOLDER, "package.json")) - fs.removeSync(path.join(LANGUAGE_FOLDER, "index.js")) - fs.removeSync(path.join(LANGUAGE_FOLDER, "idMap.js")) - fs.removeSync(path.join(LANGUAGE_FOLDER, "formatters.js")) - fs.removeSync(path.join(LANGUAGE_FOLDER, "cn.js")) - fs.removeSync(path.join(LANGUAGE_FOLDER, "en.js")) -} - -// 更新主工程的package.json文件 -function updateProjectPackageJson(pkg={}){ - pkg = Object.assign({type:MODULE_TYPE}, pkg) - fs.writeJsonSync(path.join(APP_FOLDER, "package.json"), pkg) -} - -function initCommonjsApp(){ - shelljs.cd(APP_FOLDER); - resetDemoApp() - updateProjectPackageJson({type:"commonjs"}) - shelljs.exec(`node ${CLI_INDEX_FILE} init . -lngs ${SUPPORTED_LANGUAGES.join(" ")} -default ${DEFAULT_LANGUAGE} -active ${ACTIVE_LANGUAGE}`).code -} - -function initESMApp(){ - shelljs.cd(APP_FOLDER); - resetDemoApp() - updateProjectPackageJson({type:"module"}) - shelljs.exec(`node ${CLI_INDEX_FILE} init . -lngs ${SUPPORTED_LANGUAGES.join(" ")} -default ${DEFAULT_LANGUAGE} -active ${ACTIVE_LANGUAGE}`).code -} - -beforeAll(() => { - resetDemoApp(); -}) - -beforeEach(() => { - shelljs.cd(APP_FOLDER); - updateProjectPackageJson({type:"module"}) - createAppIndexFile() -}) - -test("清空工程目录国际化",done=>{ - resetDemoApp(); - expect(fs.existsSync(LANGUAGE_FOLDER)).toBe(false); - done(); -}) - - -test("初始化工程(esm)",async () =>{ - let code = shelljs.exec(`node ${CLI_INDEX_FILE} init . -lngs ${SUPPORTED_LANGUAGES.join(" ")} -default ${DEFAULT_LANGUAGE} -active ${ACTIVE_LANGUAGE}`).code - expect(code).toEqual(0); - expect(fs.existsSync(path.join(LANGUAGE_FOLDER,"package.json"))).toBe(true); - expect(fs.existsSync(path.join(LANGUAGE_FOLDER,"settings.json"))).toBe(true); - expect(fs.readJSONSync(path.join(LANGUAGE_FOLDER,"package.json")).type || "commonjs").toEqual(MODULE_TYPE); - const langSettings = await importModule(path.join(LANGUAGE_FOLDER,"settings.json")); - - expect(langSettings.languages.map(lng=>lng.name).join(",")).toEqual(SUPPORTED_LANGUAGES.join(",")); - expect(langSettings.defaultLanguage).toEqual(DEFAULT_LANGUAGE); - expect(langSettings.activeLanguage).toEqual(ACTIVE_LANGUAGE); -}) -test("初始化工程(cjs)",async () =>{ - updateProjectPackageJson({type:"commonjs"}) - let code = shelljs.exec(`node ${CLI_INDEX_FILE} init . -lngs ${SUPPORTED_LANGUAGES.join(" ")} -default ${DEFAULT_LANGUAGE} -active ${ACTIVE_LANGUAGE}`).code - expect(code).toEqual(0); - expect(fs.existsSync(path.join(LANGUAGE_FOLDER,"package.json"))).toBe(true); - expect(fs.existsSync(path.join(LANGUAGE_FOLDER,"settings.json"))).toBe(true); - expect(fs.readJSONSync(path.join(LANGUAGE_FOLDER,"package.json")).type || "commonjs").toEqual("commonjs"); - const langSettings = await importModule(path.join(LANGUAGE_FOLDER,"settings.json")); - - expect(langSettings.languages.map(lng=>lng.name).join(",")).toEqual(SUPPORTED_LANGUAGES.join(",")); - expect(langSettings.defaultLanguage).toEqual(DEFAULT_LANGUAGE); - expect(langSettings.activeLanguage).toEqual(ACTIVE_LANGUAGE); -}) - - - - - -test("提取文本(esm)",(done) =>{ - let code = shelljs.exec(`node ${CLI_INDEX_FILE} extract`).code - expect(code).toEqual(0); - // 翻译文件夹 - expect(fs.existsSync(TRANSLATES_FOLDER)).toBe(true); - // 翻译文件 - const msgFile = path.join(TRANSLATES_FOLDER,"default.json") - expect(fs.existsSync(msgFile)).toBe(true); - let messages = fs.readJSONSync(msgFile) - messages = fs.readJSONSync(msgFile) - expect("a" in messages).toBeTruthy(); - expect("b" in messages).toBeTruthy(); - expect("c" in messages).toBeTruthy(); - expect("d" in messages).toBeTruthy(); - expect("e" in messages).toBeTruthy(); - done() -}) - - -test("编译命令(esm)",(done) =>{ - shelljs.exec(`node ${CLI_INDEX_FILE} extract`).code - let code = shelljs.exec(`node ${CLI_INDEX_FILE} compile`).code - expect(code).toEqual(0); - expect(fs.existsSync(path.join(LANGUAGE_FOLDER,"index.js"))).toBe(true); - expect(fs.existsSync(path.join(LANGUAGE_FOLDER,"formatters.js"))).toBe(true); - expect(fs.existsSync(path.join(LANGUAGE_FOLDER,"cn.js"))).toBe(true); - expect(fs.existsSync(path.join(LANGUAGE_FOLDER,"en.js"))).toBe(true); - done() -}) - - - - - - - - - diff --git a/test/extract.test.js b/test/extract.test.js index 9a48aa9..8d96254 100644 --- a/test/extract.test.js +++ b/test/extract.test.js @@ -5,7 +5,7 @@ const Vinyl = require('vinyl'); const { getTranslateTexts, normalizeLanguageOptions } = require("../packages/cli/extract.plugin"); -const languages = [{name:'en',title:"英文"},{name:'cn',title:"中文",default:true},{name:'de',title:"德语"},{name:'jp',title:"日本語"}] +const languages = [{name:'en',title:"英文"},{name:'zh',title:"中文",default:true},{name:'de',title:"德语"},{name:'jp',title:"日本語"}] test("扫描提取翻译文本",(done)=>{ const file = new Vinyl({cwd: '/',base: '/test/',path: '/test/file.js',contents: Buffer.from("")}); diff --git a/test/translate.test.js b/test/translate.test.js index fcba771..20e1a48 100644 --- a/test/translate.test.js +++ b/test/translate.test.js @@ -2,7 +2,7 @@ const dayjs = require('dayjs'); const { getInterpolatedVars, replaceInterpolatedVars , translate} = require('../packages/runtime/index.js') const messages = { - cn:{ + zh:{ 1:"你好", 2:"现在是{}", 3:"我出生于{year}年,今年{age}岁", @@ -27,9 +27,9 @@ const idMap = { let scope1 ={ - defaultLanguage: "cn", // 默认语言名称 - default: messages.cn, - messages :messages.cn, + defaultLanguage: "zh", // 默认语言名称 + default: messages.zh, + messages :messages.zh, idMap, formatters:{ // 当前作用域的格式化函数列表 "*":{ @@ -42,7 +42,7 @@ let scope1 ={ upper:(v)=>v.toUpperCase(), lower:(v)=>v.toLowerCase() }, - cn:{ + zh:{ $types:{ Date:(v)=>dayjs(v).format('YYYY年MM月DD日 HH点mm分ss秒'), Boolean:(v)=>v?"是":"否", @@ -58,10 +58,10 @@ let scope1 ={ }, loaders:{}, // 异步加载语言文件的函数列表 global:{// 引用全局VoerkaI18n配置 - defaultLanguage: "cn", - activeLanguage: "cn", + defaultLanguage: "zh", + activeLanguage: "zh", languages:[ - {name:"cn",title:"中文",default:true}, + {name:"zh",title:"中文",default:true}, {name:"en",title:"英文"}, {name:"de",title:"德语"}, {name:"jp",title:"日语"} @@ -72,7 +72,7 @@ let scope1 ={ } }, - cn:{ + zh:{ $types:{ } @@ -97,7 +97,7 @@ function changeLanguage(language){ } beforeEach(() => { - scope1.global.activeLanguage = "cn" // 切换到中文 + scope1.global.activeLanguage = "zh" // 切换到中文 });