This commit is contained in:
wxzhang 2022-03-25 19:36:16 +08:00
parent 562c71a0a2
commit 50446a1614
70 changed files with 2896 additions and 667 deletions

View File

@ -1 +0,0 @@
{"type":"module"}

View File

@ -1,7 +0,0 @@
const compile = require('@voerkai18n/cli/compile.command');
const path = require("path")
compile(path.resolve(__dirname,"./apps/app/languages")).then(()=>{})

View File

@ -1,19 +0,0 @@
module.exports = {
"name" : "张三丰",
"age" : 12,
"active" : true,
"address" : [
"北京市",
"福建省泉州市\n洛阳镇"
],
"posts" : {
"title" : "标题",
"content": "内容"
},
"产品清单\t{}": 2,
"产品价格" : {
"手机" : 1299,
"电脑\t:": 3999
},
"产品\\清\\单": 1
}

View File

@ -1,37 +0,0 @@
const gulp = require('gulp');
const extract = require('@voerkai18n/cli/extract.plugin');
const path = require('path');
const soucePath = path.join(__dirname,'./apps/app')
gulp.src([
soucePath+ '/**',
"!"+ soucePath+ '/languages/**'
]).pipe(extract({
debug:true,
// output: path.join(soucePath , 'languages'),
languages: [
{name:'en',title:"英文"},
{name:'cn',title:"中文",default:true},
{name:'de',title:"德语"},
{name:'fr',title:"法语"},
{name:'es',title:"西班牙语"},
{name:'it',title:"意大利语"},
{name:'jp',title:"日語"}
],
// extractor:{
// default:[new RegExp()], // 默认匹配器,当文件类型没有对应的提取器时使用
// "*" : [new RegExp()], // 所有类型均会执行的提取器
// js:new RegExp(), // 只有一个正则表达式,js文件提取正则表达式
// html:[new RegExp(),new RegExp()] // 多个表达式可以用数组
// "js,jsx":[new RegExp(),(content,file)=>{...})] // 提取器也可以是一个函数,传入文件和文件内容,返回提取结果
// },
namespaces:{
"a":"a",
"b":"b",
}
}))
.pipe(gulp.dest(path.join(__dirname,'./apps/app/languages')));

View File

@ -1,20 +0,0 @@
{
"name": "@voerkai18n/demo",
"version": "1.0.0",
"description": "",
"main": "babel.plugin.demo.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@voerkai18n/runtime": "workspace:^1.0.0",
"@voerkai18n/cli": "workspace:^1.0.0"
},
"devDependencies": {
"deepmerge": "^4.2.2",
"gulp": "^4.0.2",
"vinyl": "^2.2.1"
}
}

View File

@ -1,59 +0,0 @@
const { objectStringify } = require("@voerkai18n/cli/stringify")
const path = require("path");
const fs = require("fs");
const k1 = "产品清单\t{}"
const k2 = "产品\\清\\单"
const newTexts = {
[k1]:1,
[k2]:2
}
let data = {
name:"张三丰",
age:12,
active:true,
address:[
"北京市",
"福建省泉州市\n洛阳镇"
],
posts:{
title:"标题",
content:"内容",
//comments:[]
},
[k1]:[
"手机",
"电脑"
],
"产品清单\t{}":2,
"产品价格":{
"手机":1299,
"电脑\t:":3999
},
"产品\\清\\单":1
}
const result = objectStringify(data)
console.log(result)
fs.writeFileSync(path.join(__dirname,"./data.js"),`module.exports = ${result}`)
const loaded = require("./data.js")
Object.entries(loaded).forEach(([key,value])=>{
if(key===k1){
console.log("k1=",value)
}else if(key===k2){
console.log("k2=",value)
console.log("k2 in data",k2 in data)
}
})
console.log(loaded[k1])
console.log(loaded[k2])

View File

@ -0,0 +1,32 @@
module.exports = {
"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": "相片"
}

View File

@ -0,0 +1,32 @@
module.exports = {
"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": "相片"
}

View File

@ -0,0 +1,106 @@
/**
格式化器用来对翻译文本内容中的插值变量进行格式化
比如将一个数字格式化为货币格式或者将一个日期格式化为友好的日期格式
- 以下定义了一些格式化器在中文场景下会启用这些格式化器
import dayjs from "dayjs";
const formatters = {
"*":{ // 在所有语言下生效的格式化器
$types:{...}, // 只作用于特定数据类型的默认格式化器
.... // 全局格式化器
},
cn:{
// 只作用于特定数据类型的格式化器
$types:{
Date:(value)=>dayjs(value).format("YYYY年MM月DD日 HH:mm:ss"),
},
date:(value)=>dayjs(value).format("YYYY年MM月DD日")
bjTime:(value)=>"北京时间"+ value,
[格式化器名称]:(value)=>{...},
[格式化器名称]:(value)=>{...},
[格式化器名称]:(value)=>{...},
},
en:{
$types:{
Date:(value)=>dayjs(value).format("YYYY/MM/DD HH:mm:ss"), // 默认的格式化器
},
date:(value)=>dayjs(value).format("YYYY/MM/DD")
bjTime:(value)=>"BeiJing "+ value,
[格式化器名称]:(value)=>{...},
[格式化器名称]:(value)=>{...},
[格式化器名称]:(value)=>{...},
}
}
- 在翻译函数中使用格式化器的方法,示例如下
t("Now is { value | date | bjTime }",{value: new Date()})
其等效于
t(`Now is ${bjTime(date(value))",{value: new Date()})
由于value分别经过两个管道符转换上一个管道符的输出作为下一个管道符的输入,可以多次使用管道符
最终的输出结果
中文: "现在是北京时间2022年3月1日"
英文: "Now is BeiJing 2022/03/01"
*
*/
module.exports = {
// 在所有语言下生效的格式化器
"*":{
//[格式化名称]:(value)=>{...},
//[格式化名称]:(value,arg)=>{...},
},
// 在所有语言下只作用于特定数据类型的格式化器
$types:{
},
cn:{
$types:{
// 所有类型的默认格式化器
// "*":{
// },
// Date:{
// },
// Number:{
// },
// String:{
// },
// Array:{
// },
// Object:{
// }
}
},
en:{
$types:{
// 所有类型的默认格式化器
// "*":{
// },
// Date:{
// },
// Number:{
// },
// String:{
// },
// Array:{
// },
// Object:{
// }
}
}
}

View File

@ -0,0 +1,32 @@
module.exports = {
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
"请输入旧密码:": 6,
"请再次输入旧密码:": 7,
"请输入新密码:": 8,
"请再次输入新密码:": 9,
"密码至少需要6位并且至少包含数字、字符或特殊符号中的两种": 10,
"密码强度: {strength}": 11,
"用户名或密码错误": 12,
"请输入用户名:": 13,
"请输入密码:": 14,
"欢迎您: {}": 15,
"数据库类型:{}、{}、{}": 16,
"数据库密码:{pwd}": 17,
"数据库地址:{url}": 18,
"编码:{encode}": 19,
"编码": 20,
"名称": 21,
"描述": 22,
"文件名称": 23,
"您有{}条未读消息": 24,
"消息总数:{$count}": 25,
"消息类型:{type}": 26,
"登录": 27,
"请输入密码:": 28,
"头像": 29,
"相片": 30
}

View File

@ -0,0 +1,45 @@
const messageIds = require("./idMap")
const { translate,I18nManager,i18nScope } = require("@voerkai18n/runtime")
const formatters = require("./formatters.js")
const defaultMessages = require("./cn.js")
const activeMessages = defaultMessages
// 语言配置文件
const scopeSettings = {
"languages": [
{
"name": "cn",
"title": "cn"
},
{
"name": "en",
"title": "en"
}
],
"defaultLanguage": "cn",
"activeLanguage": "cn",
"namespaces": {}
}
// 语言作用域
const scope = new i18nScope({
...scopeSettings, // languages,defaultLanguage,activeLanguage,namespaces,formatters
id: "", // 当前作用域的id自动取当前工程的package.json的name
default: defaultMessages, // 默认语言包
messages : activeMessages, // 当前语言包
idMap:messageIds, // 消息id映射列表
formatters, // 当前作用域的格式化函数列表
loaders:{
"en" : ()=>import("./en.js")
}
})
// 翻译函数
const t = translate.bind(scope)
module.exports.t = t
module.exports.scope = scope
module.exports.i18nManager = VoerkaI18n

View File

@ -1,12 +1,12 @@
module.exports = {
{
"languages": [
{
"name": "cn",
"title": "中文"
"title": "cn"
},
{
"name": "en",
"title": "英文"
"title": "en"
}
],
"defaultLanguage": "cn",

View File

@ -0,0 +1,183 @@
{
"a": {
"en": "a",
"$file": [
"index.js"
]
},
"b": {
"en": "b",
"$file": [
"index.js"
]
},
"c": {
"en": "c",
"$file": [
"index.js"
]
},
"d": {
"en": "d",
"$file": [
"index.js"
]
},
"e": {
"en": "e",
"$file": [
"index.js"
]
},
"请输入旧密码:": {
"en": "请输入旧密码:",
"$file": [
"auth\\changepassword.js"
]
},
"请再次输入旧密码:": {
"en": "请再次输入旧密码:",
"$file": [
"auth\\changepassword.js"
]
},
"请输入新密码:": {
"en": "请输入新密码:",
"$file": [
"auth\\changepassword.js"
]
},
"请再次输入新密码:": {
"en": "请再次输入新密码:",
"$file": [
"auth\\changepassword.js"
]
},
"密码至少需要6位并且至少包含数字、字符或特殊符号中的两种": {
"en": "密码至少需要6位并且至少包含数字、字符或特殊符号中的两种",
"$file": [
"auth\\changepassword.js"
]
},
"密码强度: {strength}": {
"en": "密码强度: {strength}",
"$file": [
"auth\\changepassword.js"
]
},
"用户名或密码错误": {
"en": "用户名或密码错误",
"$file": [
"auth\\login.js"
]
},
"请输入用户名:": {
"en": "请输入用户名:",
"$file": [
"auth\\login.js",
"auth\\login.html"
]
},
"请输入密码:": {
"en": "请输入密码:",
"$file": [
"auth\\login.js"
]
},
"欢迎您: {}": {
"en": "欢迎您: {}",
"$file": [
"auth\\login.js"
]
},
"数据库类型:{}、{}、{}": {
"en": "数据库类型:{}、{}、{}",
"$file": [
"db\\index.js"
]
},
"数据库密码:{pwd}": {
"en": "数据库密码:{pwd}",
"$file": [
"db\\index.js"
]
},
"数据库地址:{url}": {
"en": "数据库地址:{url}",
"$file": [
"db\\index.js"
]
},
"编码:{encode}": {
"en": "编码:{encode}",
"$file": [
"db\\index.js"
]
},
"编码": {
"en": "编码",
"$file": [
"db\\models.js"
]
},
"名称": {
"en": "名称",
"$file": [
"db\\models.js"
]
},
"描述": {
"en": "描述",
"$file": [
"db\\models.js"
]
},
"文件名称": {
"en": "文件名称",
"$file": [
"db\\models.js"
]
},
"您有{}条未读消息": {
"en": "您有{}条未读消息",
"$file": [
"messages\\index.js"
]
},
"消息总数:{$count}": {
"en": "消息总数:{$count}",
"$file": [
"messages\\index.js"
]
},
"消息类型:{type}": {
"en": "消息类型:{type}",
"$file": [
"messages\\index.js"
]
},
"登录": {
"en": "登录",
"$file": [
"auth\\login.html"
]
},
"请输入密码:": {
"en": "请输入密码:",
"$file": [
"auth\\login.html"
]
},
"头像": {
"en": "头像",
"$file": [
"auth\\login.html"
]
},
"相片": {
"en": "相片",
"$file": [
"auth\\login.html"
]
}
}

24
packages/apps/app/package-lock.json generated Normal file
View File

@ -0,0 +1,24 @@
{
"name": "app",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"@voerkai18n/runtime": "^1.0.0"
}
},
"node_modules/@voerkai18n/runtime": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@voerkai18n/runtime/-/runtime-1.0.0.tgz",
"integrity": "sha512-P3yTmuaGb79LkWmQtLmmN9xGa3A0Lf+9O0ngB6Jr5v+0A7tzh94LGA5KnIaQAL63smc3fpQcf3vQZgnxUoAC1g=="
}
},
"dependencies": {
"@voerkai18n/runtime": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@voerkai18n/runtime/-/runtime-1.0.0.tgz",
"integrity": "sha512-P3yTmuaGb79LkWmQtLmmN9xGa3A0Lf+9O0ngB6Jr5v+0A7tzh94LGA5KnIaQAL63smc3fpQcf3vQZgnxUoAC1g=="
}
}
}

View File

@ -0,0 +1 @@
{"type":"module","dependencies":{"@voerkai18n/cli":"workspace:^1.0.6","@voerkai18n/runtime":"^1.0.0"}}

24
packages/apps/vueapp/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1,3 @@
{
"recommendations": ["johnsoncodehk.volar"]
}

View File

@ -0,0 +1,7 @@
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

1154
packages/apps/vueapp/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
{
"name": "vueapp",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@voerkai18n/cli": "workspace:^1.0.6",
"vue": "^3.2.25"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.2.0",
"vite": "^2.8.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,24 @@
<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
import HelloWorld from './components/HelloWorld.vue'
console.log(t("Hello world!"))
</script>
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Hello Vue 3 + Vite" />
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -0,0 +1,40 @@
<script setup>
import { ref } from 'vue'
defineProps({
msg: String
})
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<p>
Recommended IDE setup:
<a href="https://code.visualstudio.com/" target="_blank">VSCode</a>
+
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
</p>
<p>
<a href="https://vitejs.dev/guide/features.html" target="_blank">
Vite Documentation
</a>
|
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
</p>
<button type="button" @click="count++">count is: {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test hot module replacement.
</p>
</template>
<style scoped>
a {
color: #42b983;
}
</style>

View File

@ -0,0 +1,3 @@
export default {
"1": "Hello world!"
}

View File

@ -0,0 +1,3 @@
export default {
"1": "Hello world!"
}

View File

@ -0,0 +1,108 @@
/**
格式化器用来对翻译文本内容中的插值变量进行格式化
比如将一个数字格式化为货币格式或者将一个日期格式化为友好的日期格式
- 以下定义了一些格式化器在中文场景下会启用这些格式化器
import dayjs from "dayjs";
const formatters = {
"*":{ // 在所有语言下生效的格式化器
$types:{...}, // 只作用于特定数据类型的默认格式化器
.... // 全局格式化器
},
cn:{
// 只作用于特定数据类型的格式化器
$types:{
Date:(value)=>dayjs(value).format("YYYY年MM月DD日 HH:mm:ss"),
},
date:(value)=>dayjs(value).format("YYYY年MM月DD日")
bjTime:(value)=>"北京时间"+ value,
[格式化器名称]:(value)=>{...},
[格式化器名称]:(value)=>{...},
[格式化器名称]:(value)=>{...},
},
en:{
$types:{
Date:(value)=>dayjs(value).format("YYYY/MM/DD HH:mm:ss"), // 默认的格式化器
},
date:(value)=>dayjs(value).format("YYYY/MM/DD")
bjTime:(value)=>"BeiJing "+ value,
[格式化器名称]:(value)=>{...},
[格式化器名称]:(value)=>{...},
[格式化器名称]:(value)=>{...},
}
}
- 在翻译函数中使用格式化器的方法,示例如下
t("Now is { value | date | bjTime }",{value: new Date()})
其等效于
t(`Now is ${bjTime(date(value))",{value: new Date()})
由于value分别经过两个管道符转换上一个管道符的输出作为下一个管道符的输入,可以多次使用管道符
最终的输出结果
中文: "现在是北京时间2022年3月1日"
英文: "Now is BeiJing 2022/03/01"
*
*/
export default{
// 在所有语言下生效的格式化器
"*":{
//[格式化名称]:(value)=>{...},
//[格式化名称]:(value,arg)=>{...},
},
// 在所有语言下只作用于特定数据类型的格式化器
$types:{
},
cn:{
$types:{
// 所有类型的默认格式化器
// "*":{
// },
// Date:{
// },
// Number:{
// },
// String:{
// },
// Array:{
// },
// Object:{
// }
}
},
en:{
$types:{
// 所有类型的默认格式化器
// "*":{
// },
// Date:{
// },
// Number:{
// },
// String:{
// },
// Array:{
// },
// Object:{
// }
}
}
}

View File

@ -0,0 +1,3 @@
export default {
"Hello world!": 1
}

View File

@ -0,0 +1,46 @@
import messageIds from "./idMap.js"
import { translate,I18nManager,i18nScope } from "@voerkai18n/runtime"
import formatters from "./formatters.js"
import defaultMessages from "./cn.js"
const activeMessages = defaultMessages
// 语言配置文件
const scopeSettings = {
"languages": [
{
"name": "cn",
"title": "cn"
},
{
"name": "en",
"title": "en"
}
],
"defaultLanguage": "cn",
"activeLanguage": "cn",
"namespaces": {}
}
// 语言作用域
const scope = new i18nScope({
...scopeSettings, // languages,defaultLanguage,activeLanguage,namespaces,formatters
id: "vueapp", // 当前作用域的id自动取当前工程的package.json的name
default: defaultMessages, // 默认语言包
messages : activeMessages, // 当前语言包
idMap:messageIds, // 消息id映射列表
formatters, // 当前作用域的格式化函数列表
loaders:{
"en" : ()=>import("./en.js")
}
})
// 翻译函数
const t = translate.bind(scope)
export {
t,
i18nScope:scope,
i18nManager:VoerkaI18n,
}

View File

@ -0,0 +1,15 @@
{
"languages": [
{
"name": "cn",
"title": "cn"
},
{
"name": "en",
"title": "en"
}
],
"defaultLanguage": "cn",
"activeLanguage": "cn",
"namespaces": {}
}

View File

@ -0,0 +1,8 @@
{
"Hello world!": {
"en": "Hello world!",
"$file": [
"App.vue"
]
}
}

View File

@ -0,0 +1,8 @@
import { createApp } from 'vue'
import App from './App.vue'
import { t, i18nScope } from './languages'
createApp(App).mount('#app')

View File

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()]
})

View File

@ -14,21 +14,19 @@
* - cn.json
* - ...
* idMap.js // id映射列表
* settings.js // 配置文件
* settings.json // 配置文件
* cn.js // 中文语言包
* en.js // 英文语言包
* [lang].js // 其他语言包
* package.json // 包信息用来指定包类型以便在nodejs中能够正确加载
*
* @param {*} opts
*/
const readJson = require("readjson")
const glob = require("glob")
const createLogger = require("logsets")
const path = require("path")
const { t,importModule,findModuleType,getCurrentPackageJson} = require("./utils")
const fs = require("fs")
const { t,findModuleType,getCurrentPackageJson} = require("./utils")
const fs = require("fs-extra")
const logger = createLogger()
const artTemplate = require("art-template")
@ -36,6 +34,7 @@ function normalizeCompileOptions(opts={}) {
let options = Object.assign({
moduleType:"auto" // 指定编译后的语言文件的模块类型取值common,cjs,esm,es
}, opts)
options.moduleType = options.moduleType.trim()
if(options.moduleType==="es") options.moduleType = "esm"
if(options.moduleType==="cjs") options.moduleType = "commonjs"
if(!["auto","commonjs","cjs","esm","es"].includes(options.moduleType)) options.moduleType = "esm"
@ -45,16 +44,16 @@ function normalizeCompileOptions(opts={}) {
module.exports =async function compile(langFolder,opts={}){
const options = normalizeCompileOptions(opts);
let { moduleType } = options;
// 如果自动则会从当前项目读取如果没有指定则会是esm
if(moduleType==="auto"){
moduleType = findModuleType(langFolder)
}
const projectPackageJson = getCurrentPackageJson(langFolder)
// 加载多语言配置文件
const settingsFile = path.join(langFolder,"settings.js")
const settingsFile = path.join(langFolder,"settings.json")
try{
// 读取多语言配置文件
const langSettings = await importModule(settingsFile)
const langSettings = fs.readJSONSync(settingsFile)
let { languages,defaultLanguage,activeLanguage,namespaces } = langSettings
logger.log(t("支持的语言\t: {}"),languages.map(item=>`${item.title}(${item.name})`).join(","))
@ -69,7 +68,7 @@ module.exports =async function compile(langFolder,opts={}){
let messages = {} ,msgId =1
glob.sync(path.join(langFolder,"translates/*.json")).forEach(file=>{
try{
let msg = readJson.sync(file)
let msg = fs.readJSONSync(file)
Object.entries(msg).forEach(([msg,langs])=>{
if(msg in messages){
Object.assign(messages[msg],langs)
@ -121,7 +120,8 @@ module.exports =async function compile(langFolder,opts={}){
activeLanguage,
namespaces,
moduleType,
JSON
JSON,
settings:JSON.stringify(langSettings,null,4)
}
// 5 . 生成编译后的格式化函数文件
@ -133,11 +133,11 @@ module.exports =async function compile(langFolder,opts={}){
}else{ // 格式化器如果存在,则需要更改对应的模块类型
let formattersContent = fs.readFileSync(formattersFile,"utf8").toString()
if(moduleType == "esm"){
formattersContent = formattersContent.replaceAll(/\s*module.exports\s*\=/g,"export default ")
formattersContent = formattersContent.replaceAll(/\s*module.exports\./g,"export ")
formattersContent = formattersContent.replaceAll(/^[^\n\r\w]*module.exports\s*\=/gm,"export default ")
formattersContent = formattersContent.replaceAll(/^[^\n\r\w]*module.exports\./gm,"export ")
}else{
formattersContent = formattersContent.replaceAll(/^\s*export\s*default\s*/g,"module.exports = ")
formattersContent = formattersContent.replaceAll(/^\s*export\s*/g,"module.exports.")
formattersContent = formattersContent.replaceAll(/^[^\n\r\w]*export\s*default\s*/gm,"module.exports = ")
formattersContent = formattersContent.replaceAll(/^[^\n\r\w]*export\s*/gm,"module.exports.")
}
fs.writeFileSync(formattersFile,formattersContent)
logger.log(t(" - 更新格式化器:{}"),path.basename(formattersFile))
@ -149,30 +149,6 @@ module.exports =async function compile(langFolder,opts={}){
fs.writeFileSync(entryFile,entryContent)
logger.log(t(" - 访问入口文件: {}"),path.basename(entryFile))
// 7. 重新生成settings ,需要确保settings.js匹配模块类型
if(moduleType==="esm"){
fs.writeFileSync(settingsFile,`export default ${JSON.stringify(langSettings,null,4)}`)
}else{
fs.writeFileSync(settingsFile,`module.exports = ${JSON.stringify(langSettings,null,4)}`)
}
// 8. 生成package.json
const packageJsonFile = path.join(langFolder,"package.json")
let packageJson = {}
if(moduleType==="esm"){
packageJson = {
license:"MIT",
type:"module",
}
}else{
packageJson = {
license:"MIT",
}
}
fs.writeFileSync(packageJsonFile,JSON.stringify(packageJson,null,4))
}catch(e){
logger.log(t("加载多语言配置文件<{}>失败: {} "),settingsFile,e.message)
}

View File

@ -7,22 +7,23 @@ const createLogger = require("logsets")
const logger = createLogger()
module.exports = function(targetPath,options={}){
module.exports = function(srcPath,options={}){
let { filetypes,exclude} = options
if(!filetypes) filetypes = ["*.js","*.jsx","*.ts","*.tsx","*.vue","*.html"]
if(!Array.isArray(filetypes)) filetypes = filetypes.split(",")
const folders = filetypes.map(ftype=>{
if(ftype.startsWith(".")) ftype = "*"+ftype
if(!ftype.startsWith("*.")) ftype = "*."+ftype
return path.join(targetPath,"**",ftype)
return path.join(srcPath,"**",ftype)
})
folders.push(`!${path.join(targetPath,"languages","**")}`)
folders.push(`!${path.join(targetPath,"node_modules","**")}`)
folders.push(`!${path.join(targetPath,"**","node_modules","**")}`)
folders.push(`!${path.join(srcPath,"languages","**")}`)
folders.push(`!${path.join(srcPath,"node_modules","**")}`)
folders.push(`!${path.join(srcPath,"**","node_modules","**")}`)
folders.push("!**/babel.config.js")
folders.push("!**/gulpfile.js")
folders.push("!**/*.test.js")
folders.push("!__test__/**/*.js")
folders.push("!**/vite.config.js")
if(!Array.isArray(exclude) && exclude){
@ -30,11 +31,11 @@ module.exports = function(targetPath,options={}){
}
if(exclude){
exclude.forEach(folder=>{
folders.push(`!${path.join(targetPath,folder)}`)
folders.push(`!${path.join(srcPath,folder)}`)
})
}
if(!fs.existsSync(targetPath)){
logger.log(t("目标文件夹<{}>不存在"),targetPath)
if(!fs.existsSync(srcPath)){
logger.log(t("目标文件夹<{}>不存在"),srcPath)
return
}
if(options.debug){
@ -42,7 +43,7 @@ module.exports = function(targetPath,options={}){
logger.format(folders)
}
options.outputPath = path.join(targetPath,"languages")
options.outputPath = path.join(srcPath,"languages")
gulp.src(folders)
.pipe(extractor(options))
.pipe(gulp.dest(options.outputPath))

View File

@ -8,8 +8,7 @@
const through2 = require('through2')
const deepmerge = require("deepmerge")
const path = require('path')
const fs = require('fs')
const readJson = require("readjson")
const fs = require('fs-extra')
const createLogger = require("logsets")
const { replaceInterpolateVars,getDataTypeName } = require("@voerkai18n/runtime")
const { findModuleType,createPackageJsonFile,t } = require("./utils")
@ -27,6 +26,33 @@ const DefaultTranslateExtractor = String.raw`\bt\(\s*("|'){1}(?:((?<namespace>\w
// 从html文件标签中提取翻译文本
const DefaultHtmlAttrExtractor = String.raw`\<(?<tagName>\w+)(.*?)(?<i18nKey>{attrName}\s*\=\s*)([\"\'']{1})(?<text>.*?)(\4){1}\s*(.*?)(\>|\/\>)`
// 声明各种语言的注释匹配正则表达式
// {"js,jsx"}
const commentRegexs ={
"js,vue,jsx,ts":[
/(^[^\n\r\w\W]*\/\/.*$)|(\/\/.*$)/gm, // 单行注释
/\/\*\s*[\W\w|\r|\n|*]*\s*\*\//gm // 多行注释
],
html:[
/\<\!--[\s\r\n-]*[\w\r\n-\W]*?[\s\r\n-]*--\>/gm, // 注释
]
}
/**
* 匹配文件中的注释部分
*/
function removeComments(content,filetype="js"){
Object.entries(commentRegexs).forEach(([filetype,regexps])=>{
if(filetype.split(",").includes(filetype)){
regexps.forEach(regex=>{
content = content.replaceAll(regex,"")
})
}
})
return content
}
/**
*
* 返回filePath是否在nsPaths名称空间内
@ -61,6 +87,7 @@ function inNamespace(filePath,nsPath){
}
return "default"
}
/**
* 使用正则表达式提取翻译文本
@ -73,6 +100,10 @@ function extractTranslateTextUseRegexp(content,namespace,extractor,file,options)
let { languages,defaultLanguage } = options
// 移除代码中的注释,以便正则表达式提取翻译文本时排除注释部分
const fileExtName = file.extname.substr(1).toLowerCase() // 文件扩展名
content = removeComments(content,fileExtName)
let texts = {}
while ((result = extractor.exec(content)) !== null) {
// 这对于避免零宽度匹配的无限循环是必要的
@ -320,7 +351,7 @@ function updateLanguageFile(newTexts,toLangFile,options){
let oldTexts = {}
// 读取原始翻译文件
try{
oldTexts =JSON.parse(fs.readFileSync(toLangFile))// readJson.sync(toLangFile)
oldTexts =JSON.parse(fs.readFileSync(toLangFile))
}catch(e){
logger.log("Error while read language file <{}>: {}",toLangFile,e.message)
// 如果读取出错可能是语言文件不是有效的json文件则备份一下
@ -415,8 +446,8 @@ module.exports = function(options={}){
logger.log(" √ 保存语言文件 : {}",path.relative(outputPath,langFile))
}
}
// 生成语言配置文件 settings.js , 仅当不存在时才生成
const settingsFile = path.join(outputPath,"settings.js")
// 生成语言配置文件 settings.json , 仅当不存在时才生成
const settingsFile = path.join(outputPath,"settings.json")
if(!fs.existsSync(settingsFile)){
const settings = {
languages : options.languages,
@ -424,15 +455,12 @@ module.exports = function(options={}){
activeLanguage : options.activeLanguage,
namespaces : options.namespaces
}
fs.writeFileSync(settingsFile,`module.exports = ${JSON.stringify(settings,null,4)}`)
fs.writeFileSync(settingsFile,JSON.stringify(settings,null,4))
logger.log(" - 生成语言配置文件: {}",settingsFile)
}else{
logger.log(" - 已更新语言配置文件: {}",settingsFile)
logger.log(" - 应用语言配置文件: {}",settingsFile)
}
// 生成package.json
createPackageJsonFile(outputPath)
logger.log("下一步:")
logger.log(" - 运行<{}>编译语言包","voerkai18n compile")
logger.log(" - 在源码中导入编译后的语言包[{}]","import './languages'")

View File

@ -1,36 +1,59 @@
const { Command } = require('commander');
const createLogger = require("logsets")
const path = require("path")
const fs = require("fs");
const { importModule,t } = require('./utils');
const fs = require("fs-extra")
const deepmerge = require('deepmerge');
const logger = createLogger()
const { scope } = require('./languages');
const { getCurrentProjectRootFolder,i18nScope ,t } = require("./utils")
const program = new Command();
/**
* 根据当前输入的文件夹位置自动确定源码文件夹位置
*
* - 如果没有指定则取当前文件夹
* - 如果指定是非绝对路径则以当前文件夹作为base
* - 查找pack
* - 如果该文件夹中存在src则取src下的文件夹
* -
*
* @param {*} location
* @returns
*/
function getProjectSourceFolder(location){
if(!location) {
location = process.cwd()
}else{
if(!path.isAbsolute(location)){
location = path.join(process.cwd(),location)
}
}
let projectRoot = getCurrentProjectRootFolder(location)
// 如果当前工程存在src文件夹则自动使用该文件夹作为源文件夹
if(fs.existsSync(path.join(projectRoot,"src"))){
projectRoot = path.join(projectRoot,"src")
}
return projectRoot
}
program
.command('init')
.argument('[location]', t('工程项目所在目录'))
.description(t('初始化项目国际化配置'))
.option('-d, --debug', t('输出调试信息'))
.option('-D, --debug', t('输出调试信息'))
.option('-r, --reset', t('重新生成当前项目的语言配置'))
.option('-m, --moduleType [type]', t('生成的js模块类型,取值auto,esm,cjs'),"auto")
.option('-lngs, --languages <languages...>', t('支持的语言列表'), ['cn','en'])
.option('-default, --defaultLanguage <name>', t('默认语言'), 'cn')
.option('-active, --activeLanguage <name>', t('激活语言'), 'cn')
.option('-d, --defaultLanguage <name>', t('默认语言'), 'cn')
.option('-i, --installRuntime', t('自动安装默认语言'),true)
.option('-a, --activeLanguage <name>', t('激活语言'), 'cn')
.hook("preAction",async function(location){
const lang= process.env.LANGUAGE
if(lang){
await scope.change(lang)
}
const lang= process.env.LANGUAGE || "cn"
await i18nScope.change(lang)
})
.action((location,options) => {
if(!location) {
location = process.cwd()
}else{
location = path.join(process.cwd(),location)
}
location = getProjectSourceFolder(location)
logger.log(t("工程目录:{}"),location)
//
if(options.debug){
@ -44,45 +67,34 @@ program
program
.command('extract')
.description(t('扫描并提取所有待翻译的字符串到<languages/translates>文件夹中'))
.option('-d, --debug', t('输出调试信息'))
.option('-lngs, --languages', t('支持的语言'), 'cn,en')
.option('-default, --defaultLanguage', t('默认语言'), 'cn')
.option('-active, --activeLanguage', t('激活语言'), 'cn')
.option('-D, --debug', t('输出调试信息'))
.option('-lngs, --languages <languages...>', t('支持的语言'), ['cn','en'])
.option('-d, --defaultLanguage', t('默认语言'), 'cn')
.option('-a, --activeLanguage', t('激活语言'), 'cn')
.option('-ns, --namespaces', t('翻译名称空间'))
.option('-e, --exclude <folders>', t('排除要扫描的文件夹,多个用逗号分隔'))
.option('-u, --updateMode', t('本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并'), 'sync')
.option('-f, --filetypes', t('要扫描的文件类型'), 'js,vue,html,jsx,ts')
.option('-f, --filetypes', t('要扫描的文件类型'), 'js,vue,html,jsx,ts,mjs,cjs')
.argument('[location]', t('工程项目所在目录'),"./")
.hook("preAction",async function(location){
const lang= process.env.LANGUAGE
if(lang){
await scope.change(lang)
}
const lang= process.env.LANGUAGE || "cn"
await i18nScope.change(lang)
})
.action(async (location,options) => {
if(!location) {
location = process.cwd()
}else{
location = path.join(process.cwd(),location)
}
location = getProjectSourceFolder(location)
if(options.languages){
options.languages = options.languages.split(",").map(l=>({name:l,title:l}))
options.languages = options.languages.map(l=>({name:l,title:l}))
}
//options = Object.assign({},options)
logger.log(t("工程目录:{}"),location)
const langSettingsFile = path.join(location,"languages","settings.js")
const langSettingsFile = path.join(location,"languages","settings.json")
if(fs.existsSync(langSettingsFile)){
logger.log(t("语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本","./languages/settings.js"))
let lngOptions = await importModule(langSettingsFile)
logger.log(t("语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本","./languages/settings.json"))
let lngOptions = fs.readJSONSync(langSettingsFile)
options.languages = lngOptions.languages
options.defaultLanguage = lngOptions.defaultLanguage
options.activeLanguage = lngOptions.activeLanguage
options.namespaces = lngOptions.namespaces
}
//
// if(options.debug){
// logger.format(options,{compact:true})
// }
const extractor = require('./extract.command');
extractor(location,options)
});
@ -92,28 +104,19 @@ program
.command('compile')
.description(t('编译指定项目的语言包'))
.option('-d, --debug', t('输出调试信息'))
.option('-m, --moduleType [types]', t('输出模块类型,取值auto,esm,cjs'), 'auto')
.option('-m, --moduleType [types]', t('输出模块类型,取值auto,esm,cjs'), 'esm')
.argument('[location]', t('工程项目所在目录'),"./")
.hook("preAction",async function(location){
const lang= process.env.LANGUAGE
if(lang){
await scope.change(lang)
}
const lang= process.env.LANGUAGE || "cn"
await i18nScope.change(lang)
})
.action(async (location,options) => {
if(!location) {
location = process.cwd()
}else{
location = path.join(process.cwd(),location)
}
location = getProjectSourceFolder(location)
const langFolder = path.join(location,"languages")
if(!fs.existsSync(langFolder)){
logger.error(t("语言包文件夹<{}>不存在",langFolder))
return
}
// if(options.debug){
// logger.format(options,{compact:true})
// }
}
compile = require("./compile.command")
compile(langFolder,options)
});

View File

@ -28,7 +28,7 @@ const logger = createLogger()
}
module.exports = function(srcPath,{debug = true,languages=["cn","en"],defaultLanguage="cn",activeLanguage="cn",moduleType = "auto",reset=false}={}){
module.exports = function(srcPath,{debug = true,languages=["cn","en"],defaultLanguage="cn",activeLanguage="cn",reset=false,installRuntime=true}={}){
// 语言文件夹名称
const langPath = "languages"
// 查找当前项目的语言包类型路径
@ -38,21 +38,9 @@ module.exports = function(srcPath,{debug = true,languages=["cn","en"],defaultLan
if(debug) logger.log(t("创建语言包文件夹: {}"),lngPath)
}
moduleType = createPackageJsonFile(lngPath,moduleType)
if(moduleType==null) {
if(debug){
logger.log(t("找不到{}文件,{}只能在js项目工程中使用"),"package.json","voerkai18n")
}else{
throw new Error(t("找不到package.json文件,voerkai18n只能在js项目工程中使用"))
}
}
// 创建settings.js文件
const settingsFile = path.join(lngPath,"settings.js")
// 创建settings.json文件
const settingsFile = path.join(lngPath,"settings.json")
if(fs.existsSync(settingsFile) && !reset){
if(debug) logger.log(t("语言配置文件{}文件已存在,跳过创建。\n使用{}可以重新覆盖创建"),settingsFile,"-r")
return
@ -63,21 +51,21 @@ module.exports = function(srcPath,{debug = true,languages=["cn","en"],defaultLan
activeLanguage,
namespaces:{}
}
// 写入配置文件
if(["esm","es","module"].includes(moduleType)){
fs.writeFileSync(settingsFile,`export default ${JSON.stringify(settings,null,4)}`)
}else{
fs.writeFileSync(settingsFile,`module.exports = ${JSON.stringify(settings,null,4)}`)
}
// 自动安装运行时@voerkai18n/runtime
logger.log(t("正在安装多语言运行时:{}"),"@voerkai18n/runtime")
installVoerkai18nRuntim(srcPath)
// 写入配置文件
fs.writeFileSync(settingsFile,JSON.stringify(settings,null,4))
// 自动安装运行时@voerkai18n/runtime
if(installRuntime){
logger.log(t("正在安装多语言运行时:{}"),"@voerkai18n/runtime")
installVoerkai18nRuntim(srcPath)
}
if(debug) {
logger.log(t("生成语言配置文件:{}"),"./languages/settings.js")
logger.log(t("生成语言配置文件:{}"),"./languages/settings.json")
logger.log(t("拟支持的语言:{}"),settings.languages.map(l=>l.name).join(","))
logger.log(t("初始化成功,下一步:"))
logger.log(t(" - 编辑{}确定拟支持的语言种类等参数"),"languages/settings.js")
logger.log(t(" - 编辑{}确定拟支持的语言种类等参数"),"languages/settings.json")
logger.log(t(" - 运行<{}>扫描提取要翻译的文本"),"voerkai18n extract")
logger.log(t(" - 运行<{}>编译语言包"),"voerkai18n compile")
}

View File

@ -3,44 +3,44 @@ module.exports = {
"2": "默认语言\\t: {}",
"3": "激活语言\\t: {}",
"4": "名称空间\\t: {}",
"5": "模块类型\\t: {}",
"6": "编译结果输出至:{}",
"7": "读取语言文件{}失败:{}",
"8": " - 共合成{}条语言包文本",
"9": " - 语言包文件: {}",
"10": " - idMap文件: {}",
"11": " - 格式化器:{}",
"12": " - 更新格式化器:{}",
"13": " - 访问入口文件: {}",
"14": "加载多语言配置文件<{}>失败: {} ",
"15": "目标文件夹<{}>不存在",
"16": "扫描提取范围:",
"17": "工程项目所在目录",
"18": "初始化项目国际化配置",
"19": "输出调试信息",
"20": "重新生成当前项目的语言配置",
"21": "生成的js模块类型,取值auto,esm,cjs",
"22": "支持的语言列表",
"23": "工程目录:{}",
"24": "扫描并提取所有待翻译的字符串到<languages/translates>文件夹中",
"25": "支持的语言",
"26": "默认语言",
"27": "激活语言",
"28": "翻译名称空间",
"29": "排除要扫描的文件夹,多个用逗号分隔",
"30": "本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并",
"31": "要扫描的文件类型",
"32": "语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本",
"33": "编译指定项目的语言包",
"34": "输出模块类型,取值auto,esm,cjs",
"35": "语言包文件夹<{}>不存在",
"36": "找不到{}文件,{}只能在js项目工程中使用",
"37": "找不到package.json文件,voerkai18n只能在js项目工程中使用",
"38": "语言配置文件{}文件已存在,跳过创建。\\n使用{}可以重新覆盖创建",
"39": "生成语言配置文件:{}",
"40": "拟支持的语言:{}",
"41": "初始化成功,下一步:",
"42": " - 编辑{}确定拟支持的语言种类等参数",
"43": " - 运行<{}>扫描提取要翻译的文本",
"44": " - 运行<{}>编译语言包"
"5": " - 更新格式化器:{}",
"6": " - 访问入口文件: {}",
"7": "加载多语言配置文件<{}>失败: {} ",
"8": "目标文件夹<{}>不存在",
"9": "扫描提取范围:",
"10": "工程项目所在目录",
"11": "初始化项目国际化配置",
"12": "输出调试信息",
"13": "重新生成当前项目的语言配置",
"14": "支持的语言列表",
"15": "工程目录:{}",
"16": "扫描并提取所有待翻译的字符串到<languages/translates>文件夹中",
"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": "正在安装多语言运行时:{}",
"37": "模块类型\\t: {}",
"38": "编译结果输出至:{}",
"39": "读取语言文件{}失败:{}",
"40": " - 共合成{}条语言包文本",
"41": " - 语言包文件: {}",
"42": " - idMap文件: {}",
"43": " - 格式化器:{}",
"44": "Now is { value | date | bjTime }"
}

View File

@ -3,44 +3,44 @@ module.exports = {
"2": "Default language\\t: {}",
"3": "Active language\\t\\t: {}",
"4": "Namespaces\\t\\t: {}",
"5": "Module type\\t\\t: {}",
"6": "Compile to{}",
"7": "Error while read language of file<{}>:{}",
"8": " - Total {} messages",
"9": " - language messages: {}",
"10": " - idMap file: {}",
"11": " - Formatters:{}",
"12": " - Update formatters:{}",
"13": " - Entry of language: {}",
"14": "Failed to load multilingual configuration file <{}>: {}",
"15": "The destination folder < {} > does not exist",
"16": "Scan for",
"17": "Project directory",
"18": "Initialize project i18n configuration",
"19": "Output debug information",
"20": "Regenerate the language configuration of the current project",
"21": "Generated JS module type, with values of auto, esm, cjs",
"22": "Supported languages",
"23": "Folder of project{}",
"24": "Scan and extract all strings to be translated into the <languages/translations> folder",
"25": "Supported languages",
"26": "Default language",
"27": "Active language",
"28": "Namespaces",
"29": "Exclude folders to scan, multiple separated by commas",
"30": " strategy of messages merge,with value of sync(default),overwrite,merge",
"31": "Type of file to scan",
"32": "The language configuration file <{}> already exists. It will be used preferentially to extract messages",
"33": "Compiles the language messages for project",
"34": "Output module type, values auto, esm, cjs",
"35": "The language messages folder <{}> does not exist",
"36": "Cannot find {} file, {} can only be used in JS project",
"37": "Cannot find <package.json> file, voerkai18n can only be used in JS project",
"38": "Language configuration {} file already exists, skipping creation\\n use {} to overwrite the creation",
"39": "Generate language configuration: {}",
"40": "Languages to be supported{}",
"41": "Initialization succeeded, next step",
"42": " - Edit language parameters in {}",
"43": " - Run <{}> scan to extract the messages to be translated",
"44": " - Run <{}> compile language messages"
"5": " - Update formatters:{}",
"6": " - Entry of language: {}",
"7": "Failed to load multilingual configuration file <{}>: {}",
"8": "The destination folder < {} > does not exist",
"9": "Scan for",
"10": "Project directory",
"11": "Initialize project i18n configuration",
"12": "Output debug information",
"13": "Regenerate the language configuration of the current project",
"14": "Supported languages",
"15": "Folder of project{}",
"16": "Scan and extract all strings to be translated into the <languages/translations> folder",
"17": "Supported languages",
"18": "Default language",
"19": "Active language",
"20": "Namespaces",
"21": "Exclude folders to scan, multiple separated by commas",
"22": " strategy of messages merge,with value of sync(default),overwrite,merge",
"23": "Type of file to scan",
"24": "The language configuration file <{}> already exists. It will be used preferentially to extract messages",
"25": "Compiles the language messages for project",
"26": "Output module type, values auto, esm, cjs",
"27": "The language messages folder <{}> does not exist",
"28": "Language configuration {} file already exists, skipping creation\\n use {} to overwrite the creation",
"29": "Generate language configuration: {}",
"30": "Languages to be supported{}",
"31": "Initialization succeeded, next step",
"32": " - Edit language parameters in {}",
"33": " - Run <{}> scan to extract the messages to be translated",
"34": " - Run <{}> compile language messages",
"35": "Create <languages> folder: {}",
"36": "Installing @voerkai18n/runtime{}",
"37": "Type of module\\t\\t: {}",
"38": "Compile to{}",
"39": "Error while read language file{}: {}",
"40": " - Total {} messages",
"41": " - Language file: {}",
"42": " - idMap file: {}",
"43": " - Formatters: {}",
"44": "Now is { value | date | bjTime }"
}

View File

@ -46,7 +46,6 @@
*
*/
module.exports = {
// 在所有语言下生效的格式化器
"*":{

View File

@ -3,44 +3,44 @@ module.exports = {
"默认语言\\t: {}": 2,
"激活语言\\t: {}": 3,
"名称空间\\t: {}": 4,
"模块类型\\t: {}": 5,
"编译结果输出至:{}": 6,
"读取语言文件{}失败:{}": 7,
" - 共合成{}条语言包文本": 8,
" - 语言包文件: {}": 9,
" - idMap文件: {}": 10,
" - 格式化器:{}": 11,
" - 更新格式化器:{}": 12,
" - 访问入口文件: {}": 13,
"加载多语言配置文件<{}>失败: {} ": 14,
"目标文件夹<{}>不存在": 15,
"扫描提取范围:": 16,
"工程项目所在目录": 17,
"初始化项目国际化配置": 18,
"输出调试信息": 19,
"重新生成当前项目的语言配置": 20,
"生成的js模块类型,取值auto,esm,cjs": 21,
"支持的语言列表": 22,
"工程目录:{}": 23,
"扫描并提取所有待翻译的字符串到<languages/translates>文件夹中": 24,
"支持的语言": 25,
"默认语言": 26,
"激活语言": 27,
"翻译名称空间": 28,
"排除要扫描的文件夹,多个用逗号分隔": 29,
"本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并": 30,
"要扫描的文件类型": 31,
"语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本": 32,
"编译指定项目的语言包": 33,
"输出模块类型,取值auto,esm,cjs": 34,
"语言包文件夹<{}>不存在": 35,
"找不到{}文件,{}只能在js项目工程中使用": 36,
"找不到package.json文件,voerkai18n只能在js项目工程中使用": 37,
"语言配置文件{}文件已存在,跳过创建。\\n使用{}可以重新覆盖创建": 38,
"生成语言配置文件:{}": 39,
"拟支持的语言:{}": 40,
"初始化成功,下一步:": 41,
" - 编辑{}确定拟支持的语言种类等参数": 42,
" - 运行<{}>扫描提取要翻译的文本": 43,
" - 运行<{}>编译语言包": 44
" - 更新格式化器:{}": 5,
" - 访问入口文件: {}": 6,
"加载多语言配置文件<{}>失败: {} ": 7,
"目标文件夹<{}>不存在": 8,
"扫描提取范围:": 9,
"工程项目所在目录": 10,
"初始化项目国际化配置": 11,
"输出调试信息": 12,
"重新生成当前项目的语言配置": 13,
"支持的语言列表": 14,
"工程目录:{}": 15,
"扫描并提取所有待翻译的字符串到<languages/translates>文件夹中": 16,
"支持的语言": 17,
"默认语言": 18,
"激活语言": 19,
"翻译名称空间": 20,
"排除要扫描的文件夹,多个用逗号分隔": 21,
"本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并": 22,
"要扫描的文件类型": 23,
"语言配置文件<{}>已存在,将优先使用此配置文件中参数来提取文本": 24,
"编译指定项目的语言包": 25,
"输出模块类型,取值auto,esm,cjs": 26,
"语言包文件夹<{}>不存在": 27,
"语言配置文件{}文件已存在,跳过创建。\\n使用{}可以重新覆盖创建": 28,
"生成语言配置文件:{}": 29,
"拟支持的语言:{}": 30,
"初始化成功,下一步:": 31,
" - 编辑{}确定拟支持的语言种类等参数": 32,
" - 运行<{}>扫描提取要翻译的文本": 33,
" - 运行<{}>编译语言包": 34,
"创建语言包文件夹: {}": 35,
"正在安装多语言运行时:{}": 36,
"模块类型\\t: {}": 37,
"编译结果输出至:{}": 38,
"读取语言文件{}失败:{}": 39,
" - 共合成{}条语言包文本": 40,
" - 语言包文件: {}": 41,
" - idMap文件: {}": 42,
" - 格式化器:{}": 43,
"Now is { value | date | bjTime }": 44
}

View File

@ -1,16 +1,32 @@
const messageIds = require("./idMap")
const { translate,I18nManager,i18nScope } = require("@voerkai18n/runtime")
const scopeSettings = require("./settings.js")
const formatters = require("./formatters.js")
const defaultMessages = require("./cn.js")
const activeMessages = defaultMessages
// 语言配置文件
const scopeSettings = {
"languages": [
{
"name": "cn",
"title": "cn"
},
{
"name": "en",
"title": "en"
}
],
"defaultLanguage": "cn",
"activeLanguage": "cn",
"namespaces": {}
}
// 语言作用域
const scope = new i18nScope({
...scopeSettings, // languages,defaultLanguage,activeLanguage,namespaces,formatters
id: "@voerkai18n/cli", // 当前作用域的id自动取当前工程的package.json的name
id: "@voerkai18n/cli", // 当前作用域的id自动取当前工程的package.json的name
default: defaultMessages, // 默认语言包
messages : activeMessages, // 当前语言包
idMap:messageIds, // 消息id映射列表
@ -23,6 +39,6 @@ const scope = new i18nScope({
const t = translate.bind(scope)
module.exports.t = t
module.exports.scope = scope
module.exports.i18nScope = scope
module.exports.i18nManager = VoerkaI18n

View File

@ -1,3 +0,0 @@
{
"license": "MIT"
}

View File

@ -0,0 +1,15 @@
{
"languages": [
{
"name": "cn",
"title": "cn"
},
{
"name": "en",
"title": "en"
}
],
"defaultLanguage": "cn",
"activeLanguage": "cn",
"namespaces": {}
}

View File

@ -27,48 +27,6 @@
"extract.plugin.js"
]
},
"模块类型\\t: {}": {
"en": "Module type\\t\\t: {}",
"$file": [
"compile.command.js"
]
},
"编译结果输出至:{}": {
"en": "Compile to{}",
"$file": [
"compile.command.js"
]
},
"读取语言文件{}失败:{}": {
"en": "Error while read language of file<{}>:{}",
"$file": [
"compile.command.js"
]
},
" - 共合成{}条语言包文本": {
"en": " - Total {} messages",
"$file": [
"compile.command.js"
]
},
" - 语言包文件: {}": {
"en": " - language messages: {}",
"$file": [
"compile.command.js"
]
},
" - idMap文件: {}": {
"en": " - idMap file: {}",
"$file": [
"compile.command.js"
]
},
" - 格式化器:{}": {
"en": " - Formatters:{}",
"$file": [
"compile.command.js"
]
},
" - 更新格式化器:{}": {
"en": " - Update formatters:{}",
"$file": [
@ -123,12 +81,6 @@
"index.js"
]
},
"生成的js模块类型,取值auto,esm,cjs": {
"en": "Generated JS module type, with values of auto, esm, cjs",
"$file": [
"index.js"
]
},
"支持的语言列表": {
"en": "Supported languages",
"$file": [
@ -213,18 +165,6 @@
"index.js"
]
},
"找不到{}文件,{}只能在js项目工程中使用": {
"en": "Cannot find {} file, {} can only be used in JS project",
"$file": [
"init.command.js"
]
},
"找不到package.json文件,voerkai18n只能在js项目工程中使用": {
"en": "Cannot find <package.json> file, voerkai18n can only be used in JS project",
"$file": [
"init.command.js"
]
},
"语言配置文件{}文件已存在,跳过创建。\\n使用{}可以重新覆盖创建": {
"en": "Language configuration {} file already exists, skipping creation\\n use {} to overwrite the creation",
"$file": [
@ -266,5 +206,65 @@
"$file": [
"init.command.js"
]
},
"创建语言包文件夹: {}": {
"en": "Create <languages> folder: {}",
"$file": [
"init.command.js"
]
},
"正在安装多语言运行时:{}": {
"en": "Installing @voerkai18n/runtime{}",
"$file": [
"init.command.js"
]
},
"模块类型\\t: {}": {
"en": "Type of module\\t\\t: {}",
"$file": [
"compile.command.js"
]
},
"编译结果输出至:{}": {
"en": "Compile to{}",
"$file": [
"compile.command.js"
]
},
"读取语言文件{}失败:{}": {
"en": "Error while read language file{}: {}",
"$file": [
"compile.command.js"
]
},
" - 共合成{}条语言包文本": {
"en": " - Total {} messages",
"$file": [
"compile.command.js"
]
},
" - 语言包文件: {}": {
"en": " - Language file: {}",
"$file": [
"compile.command.js"
]
},
" - idMap文件: {}": {
"en": " - idMap file: {}",
"$file": [
"compile.command.js"
]
},
" - 格式化器:{}": {
"en": " - Formatters: {}",
"$file": [
"compile.command.js"
]
},
"Now is { value | date | bjTime }": {
"en": "Now is { value | date | bjTime }",
"$file": [
"templates\\formatters.js"
]
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@voerkai18n/cli",
"version": "1.0.6",
"version": "1.0.7",
"description": "VoerkaI18n command line interactive tools",
"main": "index.js",
"homepage": "https://gitee.com/zhangfisher/voerka-i18n",
@ -34,10 +34,10 @@
"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",
"readjson": "^2.2.2",
"shelljs": "^0.8.5",
"through2": "^4.0.2",
"vinyl": "^2.2.1"

View File

@ -1,7 +1,6 @@
{{if moduleType === "esm"}}
import messageIds from "./idMap.js"
import { translate,I18nManager,i18nScope } from "@voerkai18n/runtime"
import scopeSettings from "./settings.js"
import formatters from "./formatters.js"
import defaultMessages from "./{{defaultLanguage}}.js"
{{if defaultLanguage === activeLanguage}}const activeMessages = defaultMessages
@ -9,12 +8,14 @@ import defaultMessages from "./{{defaultLanguage}}.js"
{{else}}
const messageIds = require("./idMap")
const { translate,I18nManager,i18nScope } = require("@voerkai18n/runtime")
const scopeSettings = require("./settings.js")
const formatters = require("./formatters.js")
const defaultMessages = require("./{{defaultLanguage}}.js")
{{if defaultLanguage === activeLanguage}}const activeMessages = defaultMessages
{{else}}const activeMessages = require("./{{activeLanguage}}.js"){{/if}}
{{/if}}
// 语言配置文件
const scopeSettings = {{@ settings}}
// 语言作用域
const scope = new i18nScope({
...scopeSettings, // languages,defaultLanguage,activeLanguage,namespaces,formatters
@ -32,11 +33,11 @@ const t = translate.bind(scope)
{{if moduleType === "esm"}}
export {
t,
scope,
i18nScope:scope,
i18nManager:VoerkaI18n,
}
{{else}}
module.exports.t = t
module.exports.scope = scope
module.exports.i18nScope = scope
module.exports.i18nManager = VoerkaI18n
{{/if}}

View File

@ -42,12 +42,14 @@
最终的输出结果
中文: "现在是北京时间2022年3月1日"
英文: "Now is BeiJing 2022/03/01"
*
*/
{{if moduleType === "esm"}}export default {{else}}module.exports = {{/if}}{
{{if moduleType === "esm"}}
export default{{else}}module.exports = {{/if}}{
// 在所有语言下生效的格式化器
"*":{
//[格式化名称]:(value)=>{...},

View File

@ -1,18 +1,5 @@
const path = require("path")
const fs = require("fs")
const readJson = require("readjson")
async function importModule(url,onlyDefault=true) {
try{
return require(url)
}catch(e){
const result = await import(`file:///${url}`)
return onlyDefault ? result.default : result
}
}
const fs = require("fs-extra")
/**
* 返回当前项目根文件夹
@ -39,13 +26,13 @@ async function importModule(url,onlyDefault=true) {
/**
* 读取指定文件夹的package.json文件如果当前文件夹没有package.json文件则向上查找
* @param {*} folder
* @param {*} exclueCurrent =true 排除folder从folder的父级开始查找
* @param {*} exclueCurrent = true 排除folder从folder的父级开始查找
* @returns
*/
function getCurrentPackageJson(folder,exclueCurrent=true){
let projectFolder = getCurrentProjectRootFolder(folder,exclueCurrent)
if( projectFolder){
return readJson.sync(path.join(projectFolder, "package.json"))
if(projectFolder){
return fs.readJSONSync(path.join(projectFolder,"package.json"))
}
}
@ -168,26 +155,31 @@ function escape(str){
.replaceAll("\\\\",'\\')
}
// 翻译函数
// @voerkai18n/cli工程本身使用了voerkai18n,即@voerkai18n/cli的extract和compile依赖于其自己生成的languages运行时
// 这样产生了鸡蛋问题因此在extract与compile调试阶段如果t函数无法使用(即编译的languages无法正常使用)则需要提供t函数
// 此函数的目的是提供一种容错方式
let t
let i18nScope,t
try{
t = require("./languages").t
}catch(e){
console.warn(e.stack)
t = v=>v
// @voerkai18n/cli工程本身使用了voerkai18n,即@voerkai18n/cli的extract和compile依赖于其自己生成的languages运行时
// 而@voerkai18n/cli又用来编译多语言包这样产生了鸡生蛋问题
// extract与compile调试阶段如果t函数无法使用(即编译的languages无法正常使用)则需要提供t函数
const language = require('./languages');
t = language.t
i18nScope = language.i18nScope
}catch{
t=v=>v
i18nScope={change:()=>{} }
}
module.exports = {
importModule,
findModuleType,
createPackageJsonFile,
isPlainObject,
getCurrentPackageJson,
getCurrentProjectRootFolder,
escape,
i18nScope,
t
}

View File

@ -1,3 +1,5 @@
[![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/formatters

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -621,6 +621,7 @@ function translate(message) {
* 切换语言
*/
async change(value){
value=value.trim()
if(this.languages.findIndex(lang=>lang.name === value)!==-1){
// 通知所有作用域刷新到对应的语言包
await this._refreshScopes(value)

View File

@ -1,6 +1,6 @@
{
"name": "@voerkai18n/runtime",
"version": "1.0.0",
"version": "1.0.3",
"description": "Voerkai18n Runtime",
"main": "./dist/index.cjs",
"module": "dist/index.esm.js",

27
packages/vue/index.js Normal file
View File

@ -0,0 +1,27 @@
/**
import { createApp } from 'vue'
import Root from './App.vue'
import i18nPlugin from '@voerkai18n/vue'
import { t, i18nScope } from './languages'
const app = createApp(Root)
app.use(i18nPlugin,{ t,i18nScope })
app.mount('#app')
*/
export default {
install: (app, opts={}) => {
let options = Object.assign({
t:message=>message,
}, opts)
// 全局翻译函数
app.config.globalProperties.t = function(){
return options.t(...arguments)
}
}
}

4
packages/vue/readme.md Normal file
View File

@ -0,0 +1,4 @@
[![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/vue

506
pnpm-lock.yaml generated
View File

@ -34,6 +34,27 @@ importers:
shelljs: 0.8.5
vinyl: 2.2.1
packages/apps/app:
specifiers:
'@voerkai18n/cli': workspace:^1.0.6
'@voerkai18n/runtime': ^1.0.0
dependencies:
'@voerkai18n/cli': link:../../cli
'@voerkai18n/runtime': link:../../runtime
packages/apps/vueapp:
specifiers:
'@vitejs/plugin-vue': ^2.2.0
'@voerkai18n/cli': workspace:^1.0.6
vite: ^2.8.0
vue: ^3.2.25
dependencies:
'@voerkai18n/cli': link:../../cli
vue: 3.2.31
devDependencies:
'@vitejs/plugin-vue': 2.2.4_vite@2.8.6+vue@3.2.31
vite: 2.8.6
packages/babel:
specifiers: {}
@ -46,10 +67,10 @@ importers:
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
readjson: ^2.2.2
shelljs: ^0.8.5
through2: ^4.0.2
vinyl: ^2.2.1
@ -61,10 +82,10 @@ importers:
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
readjson: 2.2.2
shelljs: 0.8.5
through2: 4.0.2
vinyl: 2.2.1
@ -1253,6 +1274,14 @@ packages:
esutils: 2.0.3
dev: true
/@babel/runtime-corejs3/7.17.2:
resolution: {integrity: sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npm.taobao.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz}
engines: {node: '>=6.9.0'}
dependencies:
core-js-pure: 3.21.1
regenerator-runtime: 0.13.9
dev: false
/@babel/runtime/7.17.2:
resolution: {integrity: sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==}
engines: {node: '>=6.9.0'}
@ -1686,6 +1715,100 @@ packages:
'@types/yargs-parser': 20.2.1
dev: true
/@vitejs/plugin-vue/2.2.4_vite@2.8.6+vue@3.2.31:
resolution: {integrity: sha512-ev9AOlp0ljCaDkFZF3JwC/pD2N4Hh+r5srl5JHM6BKg5+99jiiK0rE/XaRs3pVm1wzyKkjUy/StBSoXX5fFzcw==}
engines: {node: '>=12.0.0'}
peerDependencies:
vite: ^2.5.10
vue: ^3.2.25
dependencies:
vite: 2.8.6
vue: 3.2.31
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.3
'@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.3
'@vue/compiler-core': 3.2.31
'@vue/compiler-dom': 3.2.31
'@vue/compiler-ssr': 3.2.31
'@vue/reactivity-transform': 3.2.31
'@vue/shared': 3.2.31
estree-walker: 2.0.2
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/reactivity-transform/3.2.31:
resolution: {integrity: sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA==}
dependencies:
'@babel/parser': 7.17.3
'@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==}
dependencies:
'@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==}
peerDependencies:
vue: 3.2.31
dependencies:
'@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
/abab/2.0.5:
resolution: {integrity: sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==}
dev: true
@ -1779,6 +1902,10 @@ packages:
resolution: {integrity: sha1-qCJQ3bABXponyoLoLqYDu/pF768=}
engines: {node: '>=0.10.0'}
/ansicolor/1.1.100:
resolution: {integrity: sha512-Jl0pxRfa9WaQVUX57AB8/V2my6FJxrOR1Pp2qqFbig20QB4HzUoQ48THTKAgHlUCJeQm/s2WoOPcoIDhyCL/kw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npm.taobao.org/ansicolor/-/ansicolor-1.1.100.tgz}
dev: false
/anymatch/2.0.0:
resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==}
dependencies:
@ -2333,7 +2460,7 @@ packages:
dev: true
/color-name/1.1.3:
resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=}
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
/color-name/1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
@ -2413,6 +2540,16 @@ packages:
semver: 7.0.0
dev: true
/core-js-pure/3.21.1:
resolution: {integrity: sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npm.taobao.org/core-js-pure/-/core-js-pure-3.21.1.tgz}
requiresBuild: true
dev: false
/core-js/3.21.1:
resolution: {integrity: sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==}
requiresBuild: true
dev: false
/core-util-is/1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
@ -2447,6 +2584,10 @@ packages:
cssom: 0.3.8
dev: true
/csstype/2.6.20:
resolution: {integrity: sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==}
dev: false
/d/1.0.1:
resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
dependencies:
@ -2491,7 +2632,7 @@ packages:
dev: true
/decode-uri-component/0.2.0:
resolution: {integrity: sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=}
resolution: {integrity: sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==}
engines: {node: '>=0.10'}
/dedent/0.7.0:
@ -2630,12 +2771,220 @@ packages:
es6-iterator: 2.0.3
es6-symbol: 3.1.3
/esbuild-android-64/0.14.27:
resolution: {integrity: sha512-LuEd4uPuj/16Y8j6kqy3Z2E9vNY9logfq8Tq+oTE2PZVuNs3M1kj5Qd4O95ee66yDGb3isaOCV7sOLDwtMfGaQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-android-arm64/0.14.27:
resolution: {integrity: sha512-E8Ktwwa6vX8q7QeJmg8yepBYXaee50OdQS3BFtEHKrzbV45H4foMOeEE7uqdjGQZFBap5VAqo7pvjlyA92wznQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-64/0.14.27:
resolution: {integrity: sha512-czw/kXl/1ZdenPWfw9jDc5iuIYxqUxgQ/Q+hRd4/3udyGGVI31r29LCViN2bAJgGvQkqyLGVcG03PJPEXQ5i2g==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-arm64/0.14.27:
resolution: {integrity: sha512-BEsv2U2U4o672oV8+xpXNxN9bgqRCtddQC6WBh4YhXKDcSZcdNh7+6nS+DM2vu7qWIWNA4JbRG24LUUYXysimQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-64/0.14.27:
resolution: {integrity: sha512-7FeiFPGBo+ga+kOkDxtPmdPZdayrSzsV9pmfHxcyLKxu+3oTcajeZlOO1y9HW+t5aFZPiv7czOHM4KNd0tNwCA==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-arm64/0.14.27:
resolution: {integrity: sha512-8CK3++foRZJluOWXpllG5zwAVlxtv36NpHfsbWS7TYlD8S+QruXltKlXToc/5ZNzBK++l6rvRKELu/puCLc7jA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-32/0.14.27:
resolution: {integrity: sha512-qhNYIcT+EsYSBClZ5QhLzFzV5iVsP1YsITqblSaztr3+ZJUI+GoK8aXHyzKd7/CKKuK93cxEMJPpfi1dfsOfdw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-64/0.14.27:
resolution: {integrity: sha512-ESjck9+EsHoTaKWlFKJpPZRN26uiav5gkI16RuI8WBxUdLrrAlYuYSndxxKgEn1csd968BX/8yQZATYf/9+/qg==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm/0.14.27:
resolution: {integrity: sha512-JnnmgUBdqLQO9hoNZQqNHFWlNpSX82vzB3rYuCJMhtkuaWQEmQz6Lec1UIxJdC38ifEghNTBsF9bbe8dFilnCw==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm64/0.14.27:
resolution: {integrity: sha512-no6Mi17eV2tHlJnqBHRLekpZ2/VYx+NfGxKcBE/2xOMYwctsanCaXxw4zapvNrGE9X38vefVXLz6YCF8b1EHiQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-mips64le/0.14.27:
resolution: {integrity: sha512-NolWP2uOvIJpbwpsDbwfeExZOY1bZNlWE/kVfkzLMsSgqeVcl5YMen/cedRe9mKnpfLli+i0uSp7N+fkKNU27A==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-ppc64le/0.14.27:
resolution: {integrity: sha512-/7dTjDvXMdRKmsSxKXeWyonuGgblnYDn0MI1xDC7J1VQXny8k1qgNp6VmrlsawwnsymSUUiThhkJsI+rx0taNA==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-riscv64/0.14.27:
resolution: {integrity: sha512-D+aFiUzOJG13RhrSmZgrcFaF4UUHpqj7XSKrIiCXIj1dkIkFqdrmqMSOtSs78dOtObWiOrFCDDzB24UyeEiNGg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-s390x/0.14.27:
resolution: {integrity: sha512-CD/D4tj0U4UQjELkdNlZhQ8nDHU5rBn6NGp47Hiz0Y7/akAY5i0oGadhEIg0WCY/HYVXFb3CsSPPwaKcTOW3bg==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-netbsd-64/0.14.27:
resolution: {integrity: sha512-h3mAld69SrO1VoaMpYl3a5FNdGRE/Nqc+E8VtHOag4tyBwhCQXxtvDDOAKOUQexBGca0IuR6UayQ4ntSX5ij1Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-openbsd-64/0.14.27:
resolution: {integrity: sha512-xwSje6qIZaDHXWoPpIgvL+7fC6WeubHHv18tusLYMwL+Z6bEa4Pbfs5IWDtQdHkArtfxEkIZz77944z8MgDxGw==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-sunos-64/0.14.27:
resolution: {integrity: sha512-/nBVpWIDjYiyMhuqIqbXXsxBc58cBVH9uztAOIfWShStxq9BNBik92oPQPJ57nzWXRNKQUEFWr4Q98utDWz7jg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-32/0.14.27:
resolution: {integrity: sha512-Q9/zEjhZJ4trtWhFWIZvS/7RUzzi8rvkoaS9oiizkHTTKd8UxFwn/Mm2OywsAfYymgUYm8+y2b+BKTNEFxUekw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-64/0.14.27:
resolution: {integrity: sha512-b3y3vTSl5aEhWHK66ngtiS/c6byLf6y/ZBvODH1YkBM+MGtVL6jN38FdHUsZasCz9gFwYs/lJMVY9u7GL6wfYg==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-arm64/0.14.27:
resolution: {integrity: sha512-I/reTxr6TFMcR5qbIkwRGvldMIaiBu2+MP0LlD7sOlNXrfqIl9uNjsuxFPGEG4IRomjfQ5q8WT+xlF/ySVkqKg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild/0.14.27:
resolution: {integrity: sha512-MZQt5SywZS3hA9fXnMhR22dv0oPGh6QtjJRIYbgL1AeqAoQZE+Qn5ppGYQAoHv/vq827flj4tIJ79Mrdiwk46Q==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
esbuild-android-64: 0.14.27
esbuild-android-arm64: 0.14.27
esbuild-darwin-64: 0.14.27
esbuild-darwin-arm64: 0.14.27
esbuild-freebsd-64: 0.14.27
esbuild-freebsd-arm64: 0.14.27
esbuild-linux-32: 0.14.27
esbuild-linux-64: 0.14.27
esbuild-linux-arm: 0.14.27
esbuild-linux-arm64: 0.14.27
esbuild-linux-mips64le: 0.14.27
esbuild-linux-ppc64le: 0.14.27
esbuild-linux-riscv64: 0.14.27
esbuild-linux-s390x: 0.14.27
esbuild-netbsd-64: 0.14.27
esbuild-openbsd-64: 0.14.27
esbuild-sunos-64: 0.14.27
esbuild-windows-32: 0.14.27
esbuild-windows-64: 0.14.27
esbuild-windows-arm64: 0.14.27
dev: true
/escalade/3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
/escape-string-regexp/1.0.5:
resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=}
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
/escape-string-regexp/2.0.0:
@ -2690,7 +3039,6 @@ packages:
/estree-walker/2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true
/esutils/2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
@ -2750,7 +3098,7 @@ packages:
type: 2.6.0
/extend-shallow/2.0.1:
resolution: {integrity: sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=}
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
dependencies:
is-extendable: 0.1.1
@ -2908,7 +3256,6 @@ packages:
graceful-fs: 4.2.9
jsonfile: 6.1.0
universalify: 2.0.0
dev: true
/fs-mkdirp-stream/1.0.0:
resolution: {integrity: sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=}
@ -3101,7 +3448,7 @@ packages:
glogg: 1.0.2
/has-flag/3.0.0:
resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=}
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
/has-flag/4.0.0:
@ -3325,7 +3672,7 @@ packages:
kind-of: 6.0.3
/is-extendable/0.1.1:
resolution: {integrity: sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=}
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
engines: {node: '>=0.10.0'}
/is-extendable/1.0.1:
@ -3335,7 +3682,7 @@ packages:
is-plain-object: 2.0.4
/is-extglob/2.1.1:
resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=}
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
/is-fullwidth-code-point/1.0.0:
@ -3446,10 +3793,10 @@ packages:
engines: {node: '>=0.10.0'}
/isarray/1.0.0:
resolution: {integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=}
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
/isexe/2.0.0:
resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=}
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
/isobject/2.1.0:
resolution: {integrity: sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=}
@ -3458,7 +3805,7 @@ packages:
isarray: 1.0.0
/isobject/3.0.1:
resolution: {integrity: sha1-TkMekrEalzFjaqH5yNHMvP2reN8=}
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
engines: {node: '>=0.10.0'}
/istanbul-lib-coverage/3.2.0:
@ -3982,10 +4329,6 @@ packages:
- utf-8-validate
dev: true
/jju/1.4.0:
resolution: {integrity: sha1-o6vicYryQaKykE+EpiWXDzia4yo=}
dev: false
/js-tokens/3.0.2:
resolution: {integrity: sha1-mGbfOVECEw449/mWvOtlRDIJwls=}
dev: false
@ -4073,13 +4416,12 @@ packages:
universalify: 2.0.0
optionalDependencies:
graceful-fs: 4.2.9
dev: true
/just-debounce/1.1.0:
resolution: {integrity: sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==}
/kind-of/3.2.2:
resolution: {integrity: sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=}
resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
engines: {node: '>=0.10.0'}
dependencies:
is-buffer: 1.1.6
@ -4185,9 +4527,9 @@ packages:
/logsets/1.0.8:
resolution: {integrity: sha512-9XuCtIjGvAWbi+JgF2+NI5Bb55uvzwgCFvlo/pafXdZjVC0DDri2k+Jzv7hWg0audTrw4FTnIBiSo3yOlEpmHQ==}
dependencies:
'@babel/runtime-corejs3': registry.npmmirror.com/@babel/runtime-corejs3/7.17.2
ansicolor: registry.npmmirror.com/ansicolor/1.1.100
core-js: registry.npmmirror.com/core-js/3.21.1
'@babel/runtime-corejs3': 7.17.2
ansicolor: 1.1.100
core-js: 3.21.1
deepmerge: 4.2.2
dev: false
@ -4206,7 +4548,6 @@ packages:
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
dependencies:
sourcemap-codec: 1.4.8
dev: true
/make-dir/2.1.0:
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
@ -4323,7 +4664,7 @@ packages:
is-extendable: 1.0.1
/ms/2.0.0:
resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=}
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
/ms/2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
@ -4337,6 +4678,11 @@ packages:
requiresBuild: true
optional: true
/nanoid/3.3.1:
resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
/nanomatch/1.2.13:
resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
engines: {node: '>=0.10.0'}
@ -4469,7 +4815,7 @@ packages:
make-iterator: 1.0.1
/once/1.4.0:
resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
@ -4652,6 +4998,14 @@ packages:
resolution: {integrity: sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=}
engines: {node: '>=0.10.0'}
/postcss/8.4.12:
resolution: {integrity: sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.1
picocolors: 1.0.0
source-map-js: 1.0.2
/prelude-ls/1.1.2:
resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=}
engines: {node: '>= 0.8.0'}
@ -4763,14 +5117,6 @@ packages:
dev: false
optional: true
/readjson/2.2.2:
resolution: {integrity: sha512-PdeC9tsmLWBiL8vMhJvocq+OezQ3HhsH2HrN7YkhfYcTjQSa/iraB15A7Qvt7Xpr0Yd2rDNt6GbFwVQDg3HcAw==}
engines: {node: '>=10'}
dependencies:
jju: 1.4.0
try-catch: 3.0.0
dev: false
/rechoir/0.6.2:
resolution: {integrity: sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=}
engines: {node: '>= 0.10'}
@ -4790,7 +5136,6 @@ packages:
/regenerator-runtime/0.13.9:
resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
dev: true
/regenerator-transform/0.14.5:
resolution: {integrity: sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==}
@ -4829,7 +5174,7 @@ packages:
dev: true
/relateurl/0.2.7:
resolution: {integrity: sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=}
resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==}
engines: {node: '>= 0.10'}
dev: false
@ -4904,7 +5249,7 @@ packages:
value-or-function: 3.0.0
/resolve-url/0.2.1:
resolution: {integrity: sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=}
resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==}
deprecated: https://github.com/lydell/resolve-url#deprecated
/resolve.exports/1.1.0:
@ -5095,6 +5440,10 @@ packages:
source-map-resolve: 0.5.3
use: 3.1.1
/source-map-js/1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
/source-map-resolve/0.5.3:
resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==}
deprecated: See https://github.com/lydell/source-map-resolve#deprecated
@ -5131,7 +5480,6 @@ packages:
/sourcemap-codec/1.4.8:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
dev: true
/sparkles/1.0.1:
resolution: {integrity: sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==}
@ -5413,11 +5761,6 @@ packages:
punycode: 2.1.1
dev: true
/try-catch/3.0.0:
resolution: {integrity: sha512-3uAqUnoemzca1ENvZ72EVimR+E8lqBbzwZ9v4CEbLjkaV3Q+FtdmPUt7jRtoSoTiYjyIMxEkf6YgUpe/voJ1ng==}
engines: {node: '>=6'}
dev: false
/type-check/0.3.2:
resolution: {integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=}
engines: {node: '>= 0.8.0'}
@ -5527,7 +5870,6 @@ packages:
/universalify/2.0.0:
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
engines: {node: '>= 10.0.0'}
dev: true
/unset-value/1.0.0:
resolution: {integrity: sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=}
@ -5545,7 +5887,7 @@ packages:
dev: false
/urix/0.1.0:
resolution: {integrity: sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=}
resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==}
deprecated: Please see https://github.com/lydell/urix#deprecated
/use/3.1.1:
@ -5553,7 +5895,7 @@ packages:
engines: {node: '>=0.10.0'}
/util-deprecate/1.0.2:
resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=}
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
/v8-to-istanbul/8.1.1:
resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==}
@ -5625,6 +5967,40 @@ packages:
remove-trailing-separator: 1.1.0
replace-ext: 1.0.1
/vite/2.8.6:
resolution: {integrity: sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug==}
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.27
postcss: 8.4.12
resolve: 1.22.0
rollup: 2.69.0
optionalDependencies:
fsevents: 2.3.2
dev: true
/vue/3.2.31:
resolution: {integrity: sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw==}
dependencies:
'@vue/compiler-dom': 3.2.31
'@vue/compiler-sfc': 3.2.31
'@vue/runtime-dom': 3.2.31
'@vue/server-renderer': 3.2.31_vue@3.2.31
'@vue/shared': 3.2.31
dev: false
/w3c-hr-time/1.0.2:
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
dependencies:
@ -5710,7 +6086,7 @@ packages:
dev: true
/wrappy/1.0.2:
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
/write-file-atomic/3.0.3:
resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
@ -5798,39 +6174,3 @@ packages:
which-module: 1.0.0
y18n: 3.2.2
yargs-parser: 5.0.1
registry.npmmirror.com/@babel/runtime-corejs3/7.17.2:
resolution: {integrity: sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz}
name: '@babel/runtime-corejs3'
version: 7.17.2
engines: {node: '>=6.9.0'}
dependencies:
core-js-pure: registry.npmmirror.com/core-js-pure/3.21.1
regenerator-runtime: registry.npmmirror.com/regenerator-runtime/0.13.9
dev: false
registry.npmmirror.com/ansicolor/1.1.100:
resolution: {integrity: sha512-Jl0pxRfa9WaQVUX57AB8/V2my6FJxrOR1Pp2qqFbig20QB4HzUoQ48THTKAgHlUCJeQm/s2WoOPcoIDhyCL/kw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansicolor/-/ansicolor-1.1.100.tgz}
name: ansicolor
version: 1.1.100
dev: false
registry.npmmirror.com/core-js-pure/3.21.1:
resolution: {integrity: sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/core-js-pure/-/core-js-pure-3.21.1.tgz}
name: core-js-pure
version: 3.21.1
requiresBuild: true
dev: false
registry.npmmirror.com/core-js/3.21.1:
resolution: {integrity: sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/core-js/-/core-js-3.21.1.tgz}
name: core-js
version: 3.21.1
requiresBuild: true
dev: false
registry.npmmirror.com/regenerator-runtime/0.13.9:
resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz}
name: regenerator-runtime
version: 0.13.9
dev: false

183
readme.md
View File

@ -78,12 +78,10 @@
```shell
myapp
|--package.json
|--index.js
|--index.js
```
## 第一步:使用翻译函数
在源码文件中直接使用`t`翻译函数对要翻译文本信息进行封装,简单而粗暴。
在本项目的所有支持的源码文件中均可以使用`t`函数对要翻译的文本进行包装,简单而粗暴。
```javascript
// index.js
@ -93,35 +91,69 @@ console.log(t("中华人民共和国成立于{}",1949))
`t`翻译函数是从`myapp/languages/index.js`文件导出的翻译函数,但是现在`myapp/languages`还不存在,后续会使用工具自动生成。`voerkai18n`后续会使用正则表达式对提取要翻译的文本。
## 第二步:提取要翻译的内容
## 第一步:初始化工程
在工程目录中运行`voerkai18n init`命令进行初始化。
```javascript
> voerkai18n init
```
上述命令会在当前工程目录下创建`languages/settings.json`文件。如果您的源代码在`src`子文件夹中,则会创建在`src/languages/settings.json`
`settings.json`内容如下:
```json
{
"languages": [
{
"name": "cn",
"title": "cn"
},
{
"name": "en",
"title": "en"
}
],
"defaultLanguage": "cn",
"activeLanguage": "cn",
"namespaces": {}
}
```
上述命令代表了:
- 本项目拟支持`中文``英文`两种语言。
- 默认语言是`中文`(即在源代码中直接使用中文)
- 激活语言是`中文`
**注意:**
- `voerkai18n init`是可选的,`voerkai18n extract`也可以实现相同的功能。
- 一般情况下,您可以手工修改`settings.json`,如定义名称空间。
## 第二步:提取文本
接下来我们使用`voerkai18n extract`命令来自动扫描工程源码文件中的需要的翻译的文本信息。
```shell
myapp>voerkai18n extract -d -lngs cn,en,de,jp -default cn -active cn
myapp>voerkai18n extract
```
以上命令代表:
- 扫描当前文件夹下所有源码文件,默认是`js``jsx``html``vue`文件类型,并排除`node_modules`
- 计划支持`cn``en``de``jp`四种语言
- 默认语言是中文。(指在源码文件中我们直接使用中文即可)
- 激活语言是中文(即默认切换到中文)
- `-d`代表显示扫描调试信息
执行`voerkai18n extract`命令后,就会在`myapp/languages`通过生成`translates/default.json``settings.js`等相关文件。
执行`voerkai18n extract`命令后,就会在`myapp/languages`通过生成`translates/default.json``settings.json`等相关文件。
- **translates/default.json** 该文件就是需要进行翻译的文本信息。
- **settings.js** 语言环境的基本配置信息,可以进行修改。
- **settings.json** 语言环境的基本配置信息,可以进行修改。
最后文件结构如下:
```shell
myapp
|-- languages
|-- settings.js // 语言配置文件
|-- package.json
|-- settings.json // 语言配置文件
|-- translates // 此文件夹是所有需要翻译的内容
|-- default.json // 默认名称空间内容
|-- package.json
@ -129,6 +161,20 @@ myapp
```
**如果略过第一步中的`voerkai18n init`,也可以使用以下命令来为创建和更新`settinbgs.json`**
```javascript
myapp>voerkai18n extract -D -lngs cn en de jp -d cn -a cn
```
以上命令代表:
- 扫描当前文件夹下所有源码文件,默认是`js``jsx``html``vue`文件类型。
- 计划支持`cn``en``de``jp`四种语言
- 默认语言是中文。(指在源码文件中我们直接使用中文即可)
- 激活语言是中文(即默认切换到中文)
- `-D`代表显示扫描调试信息
## 第三步:翻译文本
接下来就可以分别对`language/translates`文件夹下的所有`JSON`文件进行翻译了。每个`JSON`文件大概如下:
@ -160,7 +206,7 @@ myapp
因此,反复执行`voerkai18n extract`命令是安全的,不会导致进行了一半的翻译内容丢失,可以放心执行。
## 第步:编译语言包
## 第步:编译语言包
当我们完成`myapp/languages/translates`下的所有`JSON语言文件`的翻译后(如果配置了名称空间后,每一个名称空间会对应生成一个文件,详见后续`名称空间`介绍),接下来需要对翻译后的文件进行编译。
@ -168,12 +214,11 @@ myapp
myapp> voerkai18n compile
```
`compile`命令根据`myapp/languages/translates/*.json``myapp/languages/settings.js`文件编译生成以下文件:
`compile`命令根据`myapp/languages/translates/*.json``myapp/languages/settings.json`文件编译生成以下文件:
```javascript
|-- languages
|-- package.json
|-- settings.js // 语言配置文件
|-- settings.json // 语言配置文件
|-- idMap.js // 文本信息id映射表
|-- index.js // 包含该应用作用域下的翻译函数等
|-- cn.js // 语言包
@ -187,7 +232,7 @@ myapp> voerkai18n compile
```
## 第步:导入翻译函数
## 第步:导入翻译函数
第一步中我们在源文件中直接使用了`t`翻译函数包装要翻译的文本信息,该`t`翻译函数就是在编译环节自动生成并声明在`myapp/languages/index.js`中的。
@ -197,28 +242,28 @@ import { t } from "./languages"
因此,我们需要在需要进行翻译时导入该函数即可。但是如果源码文件很多,重次重复导入`t`函数也是比较麻烦的,所以我们也提供了一个`babel插件`来自动导入`t`函数。
## 第步:切换语言
## 第步:切换语言
当需要切换语言时,可以通过调用scope方法来切换语言。
当需要切换语言时,可以通过调用`change`方法来切换语言。
```javascript
import { scope } from "./languages"
import { i18nScope } from "./languages"
// 切换到英文
await scope.change("en")
await i18nScope.change("en")
// VoerkaI18n是一个全局单例可以直接访问
VoerkaI18n.change("en")
```
`scope.change`与`VoerkaI18n.change`两者是等价的。
`i18nScope.change`与`VoerkaI18n.change`两者是等价的。
一般可能也需要在语言切换后进行界面更新渲染,可以订阅事件来响应语言切换。
```javascript
import { scope } from "./languages"
import { i18nScope } from "./languages"
// 切换到英文
scope.on((newLanguage)=>{
i18nScope.on((newLanguage)=>{
...
})
//
@ -262,7 +307,6 @@ t("中华人民共和国成立于{birthday | year}年",{birthday:new Date()})
- `voerkai18n`使用正则表达式来提取要翻译的内容,因此`t()`可以使用在任意地方。
-
## 插值变量
@ -705,11 +749,11 @@ t("当前状态:{status | dict(0,'初始化',1,'正在连接'2,'已连接',3,
因此,引入`名称空间`就是目的就是为了解决此问题。
配置名称空间,需要配置`languages/settings.js`文件。
配置名称空间,需要配置`languages/settings.json`文件。
```javascript
// 工程目录d:/code/myapp
// languages/settings.js
// languages/settings.json
module.exports = {
namespaces:{
//"名称":"相对路径"
@ -882,10 +926,10 @@ module.expors = {
可以通过全局单例或当前作用域实例切换语言。
```javascript
import { scope } from "./languages"
import { i18nScope } from "./languages"
// 切换到英文
await scope.change("en")
await i18nScope.change("en")
// VoerkaI18n是一个全局单例可以直接访问
VoerkaI18n.change("en")
```
@ -893,10 +937,10 @@ VoerkaI18n.change("en")
侦听语言切换事件:
```javascript
import { scope } from "./languages"
import { i18nScope } from "./languages"
// 切换到英文
scope.on((newLanguage)=>{
i18nScope.on((newLanguage)=>{
...
})
//
@ -937,9 +981,9 @@ const scope = new i18nScope({
然后在`babel.config.js`中使用,详见上节`自动导入翻译函数`介绍。
## Vue扩展
## VUE扩展
## React扩展
@ -985,12 +1029,11 @@ const scope = new i18nScope({
Arguments:
location 工程项目所在目录
Options:
-d, --debug 输出调试信息
-D, --debug 输出调试信息
-r, --reset 重新生成当前项目的语言配置
-m, --moduleType [type] 生成的js模块类型,取值auto,esm,cjs (default: "auto")
-lngs, --languages <languages...> 支持的语言列表 (default: ["cn","en"])
-default, --defaultLanguage 默认语言
-active, --activeLanguage 激活语言
-d, --defaultLanguage 默认语言
-a, --activeLanguage 激活语言
-h, --help display help for command
```
@ -1000,7 +1043,7 @@ Options:
```javascript
//- `lngs`参数用来指定拟支持的语言名称列表
> voerkai18n init . -lngs cn en jp de -default cn
> voerkai18n init . -lngs cn en jp de -d cn
```
运行`voerkai18n init`命令后,会在当前工程中创建相应配置文件。
@ -1008,13 +1051,12 @@ Options:
```javascript
myapp
|-- languages
|-- settings.js // 语言配置文件
|-- package.json
|-- settings.json // 语言配置文件
|-- package.json
|-- index.js
```
`settings.js`文件很简单,主要是用来配置要支持的语言等基本信息。
`settings.json`文件很简单,主要是用来配置要支持的语言等基本信息。
```javascript
module.exports = {
@ -1040,16 +1082,16 @@ module.exports = {
**说明:**
- 您也可以手动自行创建`languages/settings.js`、`languages/package.json`文件。这样就不需运行`voerkai18n init`命令了。
- 您也可以手动自行创建`languages/settings.json`文件。这样就不需运行`voerkai18n init`命令了。
- 如果你的源码放在`src`文件夹,则需要在`src`文件夹下执行`init`命令
- 如果你的源码放在`src`文件夹,则`init`命令会自动在在`src`文件夹下创建`languages`文件夹
- `voerkai18n init`是可选的,直接使用`extract`时也会自动创建相应的文件。
- `-m`参数用来指定生成的`settings.js`的模块类型:
- `-m`参数用来指定生成的`settings.json`的模块类型:
- 当`-m=auto`时,会自动读取前工程`package.json`中的`type`字段
- 当`-m=esm`时,会生成`ESM`模块类型的`settings.js`。
- 当`-m=cjs`时,会生成`commonjs`模块类型的`settings.js`。
- 当`-m=esm`时,会生成`ESM`模块类型的`settings.json`。
- 当`-m=cjs`时,会生成`commonjs`模块类型的`settings.json`。
- `location`参数是可选的,如果没有指定则采用当前目录。
@ -1067,10 +1109,10 @@ Arguments:
location 工程项目所在目录 (default: "./")
Options:
-d, --debug 输出调试信息
-D, --debug 输出调试信息
-lngs, --languages 支持的语言
-default, --defaultLanguage 默认语言
-active, --activeLanguage 激活语言
-d, --defaultLanguage 默认语言
-a, --activeLanguage 激活语言
-ns, --namespaces 翻译名称空间
-e, --exclude <folders> 排除要扫描的文件夹,多个用逗号分隔
-u, --updateMode 本次提取内容与已存在内容的数据合并策略,默认取值sync=同步,overwrite=覆盖,merge=合并
@ -1081,7 +1123,7 @@ Options:
**说明:**
- 启用`-d`参数时会输出提取过程,显示从哪些文件提取了几条信息。
- 如果已手动创建或通过`init`命令创建了`languages/settings.js`文件,则可以不指定`-ns``-lngs``-default``-active`参数。`extract`会优先使用`languages/settings.js`文件中的参数来进行提取。
- 如果已手动创建或通过`init`命令创建了`languages/settings.json`文件,则可以不指定`-ns``-lngs``-d``-a`参数。`extract`会优先使用`languages/settings.json`文件中的参数来进行提取。
- `-u`参数用来指定如何将提取的文本与现存的文件进行合并。因为在国际化流程中,我们经常面临源代码变更时需要更新翻译的问题。支持三种合并策略。
- **sync**:同步(默认值),两者自动合并,并且会删除在源码文件中不存在的文本。如果某个翻译已经翻译了一半也会保留。此值适用于大部情况,推荐。
- **overwrite**:覆盖现存的翻译内容。这会导致已经进行了一半的翻译数据丢失,**慎用**。
@ -1109,8 +1151,8 @@ Arguments:
location 工程项目所在目录 (default: "./")
Options:
-d, --debug 输出调试信息
-m, --moduleType [types] 输出模块类型,取值auto,esm,cjs (default: "auto")
-D, --debug 输出调试信息
-m, --moduleType [types] 输出模块类型,取值auto,esm,cjs (default: "esm")
-h, --help display help for command
```
@ -1119,7 +1161,6 @@ Options:
```javascript
myapp
|--- langauges
|-- package.json
|-- index.js // 当前作用域的源码
|-- idMap.js // 翻译文本与id的映射文件
|-- formatters.js // 自定义格式化器
@ -1142,33 +1183,33 @@ myapp
每个工程会创建一个`i18nScope`实例。
```javascript
import { scope } from "./languages"
import { i18nScope } from "./languages"
// 订阅语言切换事件
scope.on((newLanguage)=>{...})
i18nScope.on((newLanguage)=>{...})
// 取消语言切换事件订阅
scope.off(callback)
i18nScope.off(callback)
// 当前作用域配置
scope.settings
i18nScope.settings
// 当前语言
scope.activeLanguage // 如cn
i18nScope.activeLanguage // 如cn
// 默认语言
scope.defaultLanguage
i18nScope.defaultLanguage
// 返回当前支持的语言列表,可以用来显示
scope.languages // [{name:"cn",title:"中文"},{name:"en",title:"英文"},...]
i18nScope.languages // [{name:"cn",title:"中文"},{name:"en",title:"英文"},...]
// 返回当前作用域的格式化器
scope.formatters
i18nScope.formatters
// 当前作用id
scop.id
i18nScope.id
// 切换语言,异步函数
await scope.change(newLanguage)
await i18nScope.change(newLanguage)
// 当前语言包
scope.messages // {1:"...",2:"...","3":"..."}
i18nScope.messages // {1:"...",2:"...","3":"..."}
// 引用全局VoerkaI18n实例
scope.global
i18nScope.global
// 注册当前作用域格式化器
scope.registerFormatter(name,formatter,{language:"*"})
i18nScope.registerFormatter(name,formatter,{language:"*"})
```
## VoerkaI18n

View File

@ -97,9 +97,9 @@ 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.js"))).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.js"));
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);
@ -110,9 +110,9 @@ test("初始化工程(cjs)",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.js"))).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.js"));
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);