update
This commit is contained in:
parent
5b18f5a0e5
commit
feb72c01a2
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,7 @@
|
|||||||
/.vscode
|
/.vscode
|
||||||
/node_modules
|
/node_modules
|
||||||
/demo/apps/app/languages
|
node_modules
|
||||||
|
/packages/demo/apps/app/languages
|
||||||
|
/packages/demo/apps/*/languages
|
||||||
|
/packages/demo/*/node_modules
|
||||||
|
/coverage
|
@ -1,27 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
"1": "a1:aaaaa",
|
|
||||||
"2": "no aaaaa",
|
|
||||||
"3": "bbbbb",
|
|
||||||
"4": "eeeeee",
|
|
||||||
"5": "x:from a",
|
|
||||||
"6": "中华人民共和国",
|
|
||||||
"7": "a2:aaaaa",
|
|
||||||
"8": "no erer",
|
|
||||||
"9": "no aaareraa",
|
|
||||||
"10": "no fdfd",
|
|
||||||
"11": "fdgfdgfdg",
|
|
||||||
"12": "aaaaa",
|
|
||||||
"13": "aaaaa1",
|
|
||||||
"14": "aaaaa2",
|
|
||||||
"15": "aaaaa 3",
|
|
||||||
"16": "ccccc",
|
|
||||||
"17": "cccccdc",
|
|
||||||
"18": "ddddd中国",
|
|
||||||
"19": "html-a",
|
|
||||||
"20": "html-b",
|
|
||||||
"21": "html-c",
|
|
||||||
"22": "from a",
|
|
||||||
"23": "from b",
|
|
||||||
"24": "from c1",
|
|
||||||
"25": "from c2"
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
"1": "德文:aaaaa",
|
|
||||||
"2": "no aaaaa",
|
|
||||||
"3": "bbbbb",
|
|
||||||
"4": "eeeeee",
|
|
||||||
"5": "x:from a",
|
|
||||||
"6": "中华人民共和国",
|
|
||||||
"7": "a2:aaaaa",
|
|
||||||
"8": "no erer",
|
|
||||||
"9": "no aaareraa",
|
|
||||||
"10": "no fdfd",
|
|
||||||
"11": "fdgfdgfdg",
|
|
||||||
"12": "aaaaa",
|
|
||||||
"13": "aaaaa1",
|
|
||||||
"14": "aaaaa2",
|
|
||||||
"15": "aaaaa 3",
|
|
||||||
"16": "ccccc",
|
|
||||||
"17": "cccccdc",
|
|
||||||
"18": "ddddd中国",
|
|
||||||
"19": "html-a",
|
|
||||||
"20": "html-b",
|
|
||||||
"21": "html-c",
|
|
||||||
"22": "from a",
|
|
||||||
"23": "from b",
|
|
||||||
"24": "from c1",
|
|
||||||
"25": "from c2"
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
"1": "a1:aaaaa",
|
|
||||||
"2": "no aaaaa",
|
|
||||||
"3": "bbbbb",
|
|
||||||
"4": "eeeeee",
|
|
||||||
"5": "x:from a",
|
|
||||||
"6": "中华人民共和国",
|
|
||||||
"7": "a2:aaaaa",
|
|
||||||
"8": "no erer",
|
|
||||||
"9": "no aaareraa",
|
|
||||||
"10": "no fdfd",
|
|
||||||
"11": "fdgfdgfdg",
|
|
||||||
"12": "aaaaa",
|
|
||||||
"13": "aaaaa1",
|
|
||||||
"14": "aaaaa2",
|
|
||||||
"15": "aaaaa 3",
|
|
||||||
"16": "ccccc",
|
|
||||||
"17": "cccccdc",
|
|
||||||
"18": "ddddd中国",
|
|
||||||
"19": "html-a",
|
|
||||||
"20": "html-b",
|
|
||||||
"21": "html-c",
|
|
||||||
"22": "from a",
|
|
||||||
"23": "from b",
|
|
||||||
"24": "from c1",
|
|
||||||
"25": "from c2"
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
export default {
|
|
||||||
"a1:aaaaa": 1,
|
|
||||||
"no aaaaa": 2,
|
|
||||||
"bbbbb": 3,
|
|
||||||
"eeeeee": 4,
|
|
||||||
"x:from a": 5,
|
|
||||||
"中华人民共和国": 6,
|
|
||||||
"a2:aaaaa": 7,
|
|
||||||
"no erer": 8,
|
|
||||||
"no aaareraa": 9,
|
|
||||||
"no fdfd": 10,
|
|
||||||
"fdgfdgfdg": 11,
|
|
||||||
"aaaaa": 12,
|
|
||||||
"aaaaa1": 13,
|
|
||||||
"aaaaa2": 14,
|
|
||||||
"aaaaa 3": 15,
|
|
||||||
"ccccc": 16,
|
|
||||||
"cccccdc": 17,
|
|
||||||
"ddddd中国": 18,
|
|
||||||
"html-a": 19,
|
|
||||||
"html-b": 20,
|
|
||||||
"html-c": 21,
|
|
||||||
"from a": 22,
|
|
||||||
"from b": 23,
|
|
||||||
"from c1": 24,
|
|
||||||
"from c2": 25
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
|
|
||||||
const messageIds = require("./idMap")
|
|
||||||
const { translate,i18n } = require("voerka-i18n")
|
|
||||||
const defaultMessages = require("./cn.js")
|
|
||||||
const i18nSettings = require("./settings.js")
|
|
||||||
const formatters = require("../formatters")
|
|
||||||
|
|
||||||
|
|
||||||
// 自动创建全局VoerkaI18n实例
|
|
||||||
if(!globalThis.VoerkaI18n){
|
|
||||||
globalThis.VoerkaI18n = new i18n(i18nSettings)
|
|
||||||
}
|
|
||||||
|
|
||||||
let scope = {
|
|
||||||
defaultLanguage: "cn", // 默认语言名称
|
|
||||||
default: defaultMessages, // 默认语言包
|
|
||||||
messages : defaultMessages, // 当前语言包
|
|
||||||
idMap:messageIds, // 消息id映射列表
|
|
||||||
formatters, // 当前作用域的格式化函数列表
|
|
||||||
loaders:{}, // 异步加载语言文件的函数列表
|
|
||||||
global:{} // 引用全局VoerkaI18n配置
|
|
||||||
}
|
|
||||||
|
|
||||||
let supportedlanguages = {}
|
|
||||||
|
|
||||||
messages["cn"]= defaultMessages
|
|
||||||
|
|
||||||
scope.loaders["en"] = ()=>import("./en.js")
|
|
||||||
|
|
||||||
scope.loaders["de"] = ()=>import("./de.js")
|
|
||||||
|
|
||||||
scope.loaders["jp"] = ()=>import("./jp.js")
|
|
||||||
|
|
||||||
|
|
||||||
const t = ()=> translate.bind(scope)(...arguments)
|
|
||||||
|
|
||||||
// 注册当前作用域到全局VoerkaI18n实例
|
|
||||||
VoerkaI18n.register(scope)
|
|
||||||
|
|
||||||
|
|
||||||
module.exports.scope = scope
|
|
||||||
module.exports.t = t
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
"1": "a1:aaaaa",
|
|
||||||
"2": "no aaaaa",
|
|
||||||
"3": "bbbbb",
|
|
||||||
"4": "eeeeee",
|
|
||||||
"5": "x:from a",
|
|
||||||
"6": "中华人民共和国",
|
|
||||||
"7": "a2:aaaaa",
|
|
||||||
"8": "no erer",
|
|
||||||
"9": "no aaareraa",
|
|
||||||
"10": "no fdfd",
|
|
||||||
"11": "fdgfdgfdg",
|
|
||||||
"12": "aaaaa",
|
|
||||||
"13": "aaaaa1",
|
|
||||||
"14": "aaaaa2",
|
|
||||||
"15": "aaaaa 3",
|
|
||||||
"16": "ccccc",
|
|
||||||
"17": "cccccdc",
|
|
||||||
"18": "ddddd中国",
|
|
||||||
"19": "html-a",
|
|
||||||
"20": "html-b",
|
|
||||||
"21": "html-c",
|
|
||||||
"22": "from a",
|
|
||||||
"23": "from b",
|
|
||||||
"24": "from c1",
|
|
||||||
"25": "from c2"
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "module"
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
export default {
|
|
||||||
"languages": [
|
|
||||||
{
|
|
||||||
"name": "en",
|
|
||||||
"title": "英文"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cn",
|
|
||||||
"title": "中文",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "de",
|
|
||||||
"title": "德语"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "jp",
|
|
||||||
"title": "日本語"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"defaultLanguage": "cn",
|
|
||||||
"activeLanguage": "cn",
|
|
||||||
"namespaces": {
|
|
||||||
"a": [
|
|
||||||
"a"
|
|
||||||
],
|
|
||||||
"b": [
|
|
||||||
"b"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
{
|
|
||||||
"a1:aaaaa": {
|
|
||||||
"en": "a1:aaaaa",
|
|
||||||
"de": "德文:aaaaa",
|
|
||||||
"jp": "a1:aaaaa",
|
|
||||||
"$file": [
|
|
||||||
"a\\a1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"no aaaaa": {
|
|
||||||
"en": "no aaaaa",
|
|
||||||
"de": "no aaaaa",
|
|
||||||
"jp": "no aaaaa",
|
|
||||||
"$file": [
|
|
||||||
"a\\a1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"bbbbb": {
|
|
||||||
"en": "bbbbb",
|
|
||||||
"de": "bbbbb",
|
|
||||||
"jp": "bbbbb",
|
|
||||||
"$file": [
|
|
||||||
"a\\a1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"eeeeee": {
|
|
||||||
"en": "eeeeee",
|
|
||||||
"de": "eeeeee",
|
|
||||||
"jp": "eeeeee",
|
|
||||||
"$file": [
|
|
||||||
"a\\a1.js",
|
|
||||||
"a\\a2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"x:from a": {
|
|
||||||
"en": "x:from a",
|
|
||||||
"de": "x:from a",
|
|
||||||
"jp": "x:from a",
|
|
||||||
"$file": [
|
|
||||||
"a\\a1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"中华人民共和国": {
|
|
||||||
"en": "中华人民共和国",
|
|
||||||
"de": "中华人民共和国",
|
|
||||||
"jp": "中华人民共和国",
|
|
||||||
"$file": [
|
|
||||||
"a\\a1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"a2:aaaaa": {
|
|
||||||
"en": "a2:aaaaa",
|
|
||||||
"de": "a2:aaaaa",
|
|
||||||
"jp": "a2:aaaaa",
|
|
||||||
"$file": [
|
|
||||||
"a\\a2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"no erer": {
|
|
||||||
"en": "no erer",
|
|
||||||
"de": "no erer",
|
|
||||||
"jp": "no erer",
|
|
||||||
"$file": [
|
|
||||||
"a\\a2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"no aaareraa": {
|
|
||||||
"en": "no aaareraa",
|
|
||||||
"de": "no aaareraa",
|
|
||||||
"jp": "no aaareraa",
|
|
||||||
"$file": [
|
|
||||||
"a\\a2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"no fdfd": {
|
|
||||||
"en": "no fdfd",
|
|
||||||
"de": "no fdfd",
|
|
||||||
"jp": "no fdfd",
|
|
||||||
"$file": [
|
|
||||||
"a\\a2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"fdgfdgfdg": {
|
|
||||||
"en": "fdgfdgfdg",
|
|
||||||
"de": "fdgfdgfdg",
|
|
||||||
"jp": "fdgfdgfdg",
|
|
||||||
"$file": [
|
|
||||||
"a\\a2.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"aaaaa": {
|
|
||||||
"en": "aaaaa",
|
|
||||||
"de": "aaaaa",
|
|
||||||
"jp": "aaaaa",
|
|
||||||
"$file": [
|
|
||||||
"b\\b1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"bbbbb": {
|
|
||||||
"en": "bbbbb",
|
|
||||||
"de": "bbbbb",
|
|
||||||
"jp": "bbbbb",
|
|
||||||
"$file": [
|
|
||||||
"b\\b1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"eeeeee": {
|
|
||||||
"en": "eeeeee",
|
|
||||||
"de": "eeeeee",
|
|
||||||
"jp": "eeeeee",
|
|
||||||
"$file": [
|
|
||||||
"b\\b1.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,139 +0,0 @@
|
|||||||
{
|
|
||||||
"aaaaa": {
|
|
||||||
"en": "aaaaa",
|
|
||||||
"de": "aaaaa",
|
|
||||||
"jp": "aaaaa",
|
|
||||||
"$file": [
|
|
||||||
"index.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"aaaaa1": {
|
|
||||||
"en": "aaaaa1",
|
|
||||||
"de": "aaaaa1",
|
|
||||||
"jp": "aaaaa1",
|
|
||||||
"$file": [
|
|
||||||
"index.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"aaaaa2": {
|
|
||||||
"en": "aaaaa2",
|
|
||||||
"de": "aaaaa2",
|
|
||||||
"jp": "aaaaa2",
|
|
||||||
"$file": [
|
|
||||||
"index.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"aaaaa 3": {
|
|
||||||
"en": "aaaaa 3",
|
|
||||||
"de": "aaaaa 3",
|
|
||||||
"jp": "aaaaa 3",
|
|
||||||
"$file": [
|
|
||||||
"index.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"bbbbb": {
|
|
||||||
"en": "bbbbb",
|
|
||||||
"de": "bbbbb",
|
|
||||||
"jp": "bbbbb",
|
|
||||||
"$file": [
|
|
||||||
"index.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"eeeeee": {
|
|
||||||
"en": "eeeeee",
|
|
||||||
"de": "eeeeee",
|
|
||||||
"jp": "eeeeee",
|
|
||||||
"$file": [
|
|
||||||
"index.js",
|
|
||||||
"c\\c2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ccccc": {
|
|
||||||
"en": "ccccc",
|
|
||||||
"de": "ccccc",
|
|
||||||
"jp": "ccccc",
|
|
||||||
"$file": [
|
|
||||||
"c\\c1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"cccccdc": {
|
|
||||||
"en": "cccccdc",
|
|
||||||
"de": "cccccdc",
|
|
||||||
"jp": "cccccdc",
|
|
||||||
"$file": [
|
|
||||||
"c\\c1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"a2:aaaaa": {
|
|
||||||
"en": "a2:aaaaa",
|
|
||||||
"de": "a2:aaaaa",
|
|
||||||
"jp": "a2:aaaaa",
|
|
||||||
"$file": [
|
|
||||||
"c\\c2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"no erer": {
|
|
||||||
"en": "no erer",
|
|
||||||
"de": "no erer",
|
|
||||||
"jp": "no erer",
|
|
||||||
"$file": [
|
|
||||||
"c\\c2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"no aaareraa": {
|
|
||||||
"en": "no aaareraa",
|
|
||||||
"de": "no aaareraa",
|
|
||||||
"jp": "no aaareraa",
|
|
||||||
"$file": [
|
|
||||||
"c\\c2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"no fdfd": {
|
|
||||||
"en": "no fdfd",
|
|
||||||
"de": "no fdfd",
|
|
||||||
"jp": "no fdfd",
|
|
||||||
"$file": [
|
|
||||||
"c\\c2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"fdgfdgfdg": {
|
|
||||||
"en": "fdgfdgfdg",
|
|
||||||
"de": "fdgfdgfdg",
|
|
||||||
"jp": "fdgfdgfdg",
|
|
||||||
"$file": [
|
|
||||||
"c\\c2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ddddd中国": {
|
|
||||||
"en": "ddddd中国",
|
|
||||||
"de": "ddddd中国",
|
|
||||||
"jp": "ddddd中国",
|
|
||||||
"$file": [
|
|
||||||
"c\\c2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"html-a": {
|
|
||||||
"en": "html-a",
|
|
||||||
"de": "html-a",
|
|
||||||
"jp": "html-a",
|
|
||||||
"$file": [
|
|
||||||
"c\\h1.html"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"html-b": {
|
|
||||||
"en": "html-b",
|
|
||||||
"de": "html-b",
|
|
||||||
"jp": "html-b",
|
|
||||||
"$file": [
|
|
||||||
"c\\h1.html"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"html-c": {
|
|
||||||
"en": "html-c",
|
|
||||||
"de": "html-c",
|
|
||||||
"jp": "html-c",
|
|
||||||
"$file": [
|
|
||||||
"c\\h1.html"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"from a": {
|
|
||||||
"en": "from a",
|
|
||||||
"de": "from a",
|
|
||||||
"jp": "from a",
|
|
||||||
"$file": [
|
|
||||||
"a\\a2.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"from b": {
|
|
||||||
"en": "from b",
|
|
||||||
"de": "from b",
|
|
||||||
"jp": "from b",
|
|
||||||
"$file": [
|
|
||||||
"b\\b1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"from c1": {
|
|
||||||
"en": "from c1",
|
|
||||||
"de": "from c1",
|
|
||||||
"jp": "from c1",
|
|
||||||
"$file": [
|
|
||||||
"c\\c1.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"from c2": {
|
|
||||||
"en": "from c2",
|
|
||||||
"de": "from c2",
|
|
||||||
"jp": "from c2",
|
|
||||||
"$file": [
|
|
||||||
"c\\c2.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
export default {
|
|
||||||
"a":1,
|
|
||||||
"b":2,
|
|
||||||
"c{}{}":3,
|
|
||||||
"d{a}{b}":4,
|
|
||||||
"e":5
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
"a":1,
|
|
||||||
"b":2,
|
|
||||||
"c{}{}":3,
|
|
||||||
"d{a}{b}":4,
|
|
||||||
"e":5
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
const compile = require('../src/compile');
|
|
||||||
const path = require("path")
|
|
||||||
|
|
||||||
|
|
||||||
compile(path.resolve(__dirname,"./apps/app/languages"))
|
|
27
package.json
27
package.json
@ -5,25 +5,28 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"extract": "",
|
"test:babelplugin": "jest babel",
|
||||||
"babeldemo": "babel ./demodata/a/a1.js --plugins=./src/babel-plugin-voerkai18n.js"
|
"test:extract": "jest extract",
|
||||||
|
"test:translate": "jest translate",
|
||||||
|
"demo:extract": "node ./packages/demo/extract.demo.js",
|
||||||
|
"demo:compile": "node ./packages/demo/compile.demo.js",
|
||||||
|
"demo:babel": "babel ./demodata/a/a1.js --plugins=./src/babel-plugin-voerkai18n.js"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"devDependencies": {
|
||||||
"art-template": "^4.13.2",
|
"@babel/core": "^7.17.5",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.17.0",
|
||||||
|
"@babel/preset-env": "^7.16.11",
|
||||||
|
"@rollup/plugin-babel": "^5.3.1",
|
||||||
|
"@rollup/plugin-commonjs": "^21.0.2",
|
||||||
"dayjs": "^1.10.8",
|
"dayjs": "^1.10.8",
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"glob": "^7.2.0",
|
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"logsets": "^1.0.6",
|
|
||||||
"readjson": "^2.2.2",
|
|
||||||
"through2": "^4.0.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/cli": "^7.17.6",
|
|
||||||
"@babel/core": "^7.17.5",
|
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
|
"rollup": "^2.69.0",
|
||||||
|
"rollup-plugin-clear": "^2.0.7",
|
||||||
|
"rollup-plugin-uglify": "^6.0.4",
|
||||||
"vinyl": "^2.2.1"
|
"vinyl": "^2.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// import {t } from "./languages"
|
const { t,languages,scope } = reuire("./languages")
|
||||||
// import { nanoid } from "./nanoid"
|
|
||||||
//const {t } = reuire("./languages")
|
|
||||||
|
|
||||||
function output(){
|
function output(){
|
||||||
t("aaaaa")
|
t("aaaaa")
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
const babel = require("@babel/core");
|
const babel = require("@babel/core");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const i18nPlugin = require("../src/babel-plugin-voerkai18n");
|
const i18nPlugin = require("@voerkai18n/tools/babel-plugin-voerkai18n");
|
||||||
|
|
||||||
|
|
||||||
const code = fs.readFileSync(path.join(__dirname, "./apps/app/index.js"), "utf-8");
|
const code = fs.readFileSync(path.join(__dirname, "./apps/app/index.js"), "utf-8");
|
7
packages/demo/compile.demo.js
Normal file
7
packages/demo/compile.demo.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const compile = require('@voerkai18n/tools/compile');
|
||||||
|
const path = require("path")
|
||||||
|
|
||||||
|
|
||||||
|
compile(path.resolve(__dirname,"./apps/app/languages")).then(()=>{})
|
@ -1,5 +1,5 @@
|
|||||||
const gulp = require('gulp');
|
const gulp = require('gulp');
|
||||||
const extract = require('../src/extract.plugin');
|
const extract = require('@voerkai18n/tools/extract.plugin');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +13,15 @@ gulp.src([
|
|||||||
]).pipe(extract({
|
]).pipe(extract({
|
||||||
debug:true,
|
debug:true,
|
||||||
// output: path.join(soucePath , 'languages'),
|
// output: path.join(soucePath , 'languages'),
|
||||||
languages: [{name:'en',title:"英文"},{name:'cn',title:"中文",default:true},{name:'de',title:"德语"},{name:'jp',title:"日語"}],
|
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:{
|
// extractor:{
|
||||||
// default:[new RegExp()], // 默认匹配器,当文件类型没有对应的提取器时使用
|
// default:[new RegExp()], // 默认匹配器,当文件类型没有对应的提取器时使用
|
||||||
// "*" : [new RegExp()], // 所有类型均会执行的提取器
|
// "*" : [new RegExp()], // 所有类型均会执行的提取器
|
20
packages/demo/package.json
Normal file
20
packages/demo/package.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"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/tools": "workspace:^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"vinyl": "^2.2.1"
|
||||||
|
}
|
||||||
|
}
|
@ -7,5 +7,10 @@
|
|||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC"
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"vinyl": "^2.2.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
16
packages/react/package.json
Normal file
16
packages/react/package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "@voerkai18n/react",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"vinyl": "^2.2.1"
|
||||||
|
}
|
||||||
|
}
|
60
packages/runtime/formatters.js
Normal file
60
packages/runtime/formatters.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* 内置的格式化器
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典格式化器
|
||||||
|
* 根据输入data的值,返回后续参数匹配的结果
|
||||||
|
* dict(data,<value1>,<result1>,<value2>,<result1>,<value3>,<result1>,...)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* dict(1,1,"one",2,"two",3,"three",4,"four") == "one"
|
||||||
|
* dict(2,1,"one",2,"two",3,"three",4,"four") == "two"
|
||||||
|
* dict(3,1,"one",2,"two",3,"three",4,"four") == "three"
|
||||||
|
* dict(4,1,"one",2,"two",3,"three",4,"four") == "four"
|
||||||
|
* // 无匹配时返回原始值
|
||||||
|
* dict(5,1,"one",2,"two",3,"three",4,"four") == 5
|
||||||
|
* // 无匹配时并且后续参数个数是奇数,则返回最后一个参数
|
||||||
|
* dict(5,1,"one",2,"two",3,"three",4,"four","more") == "more"
|
||||||
|
*
|
||||||
|
* 在翻译中使用
|
||||||
|
* I have { value | dict(1,"one",2,"two",3,"three",4,"four")} apples
|
||||||
|
*
|
||||||
|
* @param {*} value
|
||||||
|
* @param {...any} args
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function dict(value,...args){
|
||||||
|
for(let i=0;i<args.length;i+=2){
|
||||||
|
if(args[i]===value){
|
||||||
|
return args[i+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(args.length >0 && (args.length % 2!==0)) return args[args.length-1]
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
"*":{
|
||||||
|
$types:{
|
||||||
|
Date:(value)=>value.toLocaleString()
|
||||||
|
},
|
||||||
|
time:(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()}秒`
|
||||||
|
},
|
||||||
|
time:(value)=>`${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`,
|
||||||
|
date: (value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日`,
|
||||||
|
currency:(value)=>`${value}元`,
|
||||||
|
},
|
||||||
|
en:{
|
||||||
|
currency:(value)=>`$${value}`,
|
||||||
|
}
|
||||||
|
}
|
@ -49,7 +49,7 @@ function hasInterpolation(str){
|
|||||||
目前对参数采用简单的split(",")来解析,因为无法正确解析aaa(1,1,"dd,,dd")形式的参数
|
目前对参数采用简单的split(",")来解析,因为无法正确解析aaa(1,1,"dd,,dd")形式的参数
|
||||||
在此场景下基本够用了,如果需要支持更复杂的参数解析,可以后续考虑使用正则表达式来解析
|
在此场景下基本够用了,如果需要支持更复杂的参数解析,可以后续考虑使用正则表达式来解析
|
||||||
|
|
||||||
@returns [<formatterName>,[<formatterName>,[<arg>,<arg>,...]]]
|
@returns [[<formatterName>,[<arg>,<arg>,...]]]
|
||||||
*/
|
*/
|
||||||
function parseFormatters(formatters){
|
function parseFormatters(formatters){
|
||||||
if(!formatters) return []
|
if(!formatters) return []
|
||||||
@ -89,29 +89,51 @@ function parseFormatters(formatters){
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取字符串中的插值变量
|
* 提取字符串中的插值变量
|
||||||
|
* // [
|
||||||
|
// {
|
||||||
|
name:<变量名称>,formatters:[{name:<格式化器名称>,args:[<参数>,<参数>,....]]}],<匹配字符串>],
|
||||||
|
// ....
|
||||||
|
//
|
||||||
* @param {*} str
|
* @param {*} str
|
||||||
* @param {*} isFull =true 保留所有插值变量 =false 进行去重
|
* @param {*} isFull =true 保留所有插值变量 =false 进行去重
|
||||||
* @returns {Array} [[变量名称,[],match],[变量名称,[formatter,formatter,...],match],...]
|
* @returns {Array}
|
||||||
|
* [
|
||||||
|
* {
|
||||||
|
* name:"<变量名称>",
|
||||||
|
* formatters:[
|
||||||
|
* {name:"<格式化器名称>",args:[<参数>,<参数>,....]},
|
||||||
|
* {name:"<格式化器名称>",args:[<参数>,<参数>,....]},
|
||||||
|
* ],
|
||||||
|
* match:"<匹配字符串>"
|
||||||
|
* },
|
||||||
|
* ...
|
||||||
|
* ]
|
||||||
*/
|
*/
|
||||||
function getInterpolatedVars(str){
|
function getInterpolatedVars(str){
|
||||||
let results = [], match
|
let vars = []
|
||||||
while ((match = varWithPipeRegexp.exec(str)) !== null) {
|
forEachInterpolatedVars(str,(varName,formatters,match)=>{
|
||||||
if (match.index === varWithPipeRegexp.lastIndex) {
|
let varItem = {
|
||||||
varWithPipeRegexp.lastIndex++;
|
name:varName,
|
||||||
}
|
formatters:formatters.map(([formatter,args])=>{
|
||||||
const varname = match.groups.varname || ""
|
return {
|
||||||
// 解析格式化器和参数 = [<formatterName>,[<formatterName>,[<arg>,<arg>,...]]]
|
name:formatter,
|
||||||
const formatters = parseFormatters(match.groups.formatters)
|
args:args
|
||||||
const varInfo = [varname,formatters,match]
|
}
|
||||||
results.push(varInfo)
|
}),
|
||||||
}
|
match:match
|
||||||
return results
|
}
|
||||||
|
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 {*} str
|
||||||
* @param {*} callback
|
* @param {Function(<变量名称>,[formatters],match[0])} callback
|
||||||
* @returns
|
* @returns 返回替换后的字符串
|
||||||
*/
|
*/
|
||||||
function forEachInterpolatedVars(str,callback,options={}){
|
function forEachInterpolatedVars(str,callback,options={}){
|
||||||
let result=str, match
|
let result=str, match
|
||||||
@ -126,9 +148,9 @@ function forEachInterpolatedVars(str,callback,options={}){
|
|||||||
if(typeof(callback)==="function"){
|
if(typeof(callback)==="function"){
|
||||||
try{
|
try{
|
||||||
if(opts.replaceAll){
|
if(opts.replaceAll){
|
||||||
result=result.replaceAll(match[0],callback(varname,formatters))
|
result=result.replaceAll(match[0],callback(varname,formatters,match[0]))
|
||||||
}else{
|
}else{
|
||||||
result=result.replace(match[0],callback(varname,formatters))
|
result=result.replace(match[0],callback(varname,formatters,match[0]))
|
||||||
}
|
}
|
||||||
}catch{// callback函数可能会抛出异常,如果抛出异常,则中断匹配过程
|
}catch{// callback函数可能会抛出异常,如果抛出异常,则中断匹配过程
|
||||||
break
|
break
|
||||||
@ -443,12 +465,11 @@ function translate(message) {
|
|||||||
}else if(arguments.length >= 2){
|
}else if(arguments.length >= 2){
|
||||||
vars = [...arguments].splice(1).map((arg,index)=>{
|
vars = [...arguments].splice(1).map((arg,index)=>{
|
||||||
try{
|
try{
|
||||||
return typeof(arg)==="function" ? arg() : arg
|
arg = typeof(arg)==="function" ? arg() : arg
|
||||||
}catch(e){
|
// 位置参数中以第一个数值变量为复数变量
|
||||||
return arg
|
if(isNumber(arg)) pluraValue = parseInt(arg)
|
||||||
}
|
}catch(e){ }
|
||||||
// 位置参数中以第一个数值变量为复数变量
|
return arg
|
||||||
if(isNumber(arg)) pluraValue = parseInt(arg)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -475,7 +496,7 @@ function translate(message) {
|
|||||||
// 如果是数组说明要启用复数机制,需要根据插值变量中的某个变量来判断复数形式
|
// 如果是数组说明要启用复数机制,需要根据插值变量中的某个变量来判断复数形式
|
||||||
if(Array.isArray(content) && content.length>0){
|
if(Array.isArray(content) && content.length>0){
|
||||||
// 如果存在复数命名变量,只取第一个复数变量
|
// 如果存在复数命名变量,只取第一个复数变量
|
||||||
if(pluraValue){ // 启用的是位置插值,pluraIndex=第一个数字变量的位置
|
if(pluraValue!==null){ // 启用的是位置插值,pluraIndex=第一个数字变量的位置
|
||||||
content = getPluraMessage(content,pluraValue)
|
content = getPluraMessage(content,pluraValue)
|
||||||
}else if(pluralVar.length>0){
|
}else if(pluralVar.length>0){
|
||||||
content = getPluraMessage(content,parseInt(vars(pluralVar[0])))
|
content = getPluraMessage(content,parseInt(vars(pluralVar[0])))
|
||||||
@ -509,7 +530,7 @@ function translate(message) {
|
|||||||
* VoerkaI18n.off("change",(language)=>{})
|
* VoerkaI18n.off("change",(language)=>{})
|
||||||
*
|
*
|
||||||
* */
|
* */
|
||||||
class I18n{
|
class I18nManager{
|
||||||
static instance = null; // 单例引用
|
static instance = null; // 单例引用
|
||||||
callbacks = [] // 当切换语言时的回调事件
|
callbacks = [] // 当切换语言时的回调事件
|
||||||
constructor(settings={}){
|
constructor(settings={}){
|
||||||
@ -650,7 +671,7 @@ function translate(message) {
|
|||||||
module.exports ={
|
module.exports ={
|
||||||
getInterpolatedVars,
|
getInterpolatedVars,
|
||||||
replaceInterpolatedVars,
|
replaceInterpolatedVars,
|
||||||
I18n,
|
I18nManager,
|
||||||
translate,
|
translate,
|
||||||
languages,
|
languages,
|
||||||
defaultLanguageSettings
|
defaultLanguageSettings
|
@ -1,11 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "@voerkai18n/runtime",
|
"name": "@voerkai18n/runtime",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "Voerkai18n Runtime",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC"
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"deepmerge": "^4.2.2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
33
packages/runtime/rollup.config.js
Normal file
33
packages/runtime/rollup.config.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
import clear from 'rollup-plugin-clear'
|
||||||
|
import { uglify } from "rollup-plugin-uglify";
|
||||||
|
import { babel } from '@rollup/plugin-babel';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
input: './index.js',
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
file: 'dist/index.mjs',
|
||||||
|
format:"es"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
file: 'dist/index.cjs',
|
||||||
|
exports:"default",
|
||||||
|
format:"cjs"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
//resolve(),
|
||||||
|
commonjs(),
|
||||||
|
babel({
|
||||||
|
babelHelpers:"runtime",
|
||||||
|
exclude: 'node_modules/**'
|
||||||
|
}),
|
||||||
|
clear({targets:["dist"]}),
|
||||||
|
uglify()
|
||||||
|
],
|
||||||
|
external:["@babel/runtime"]
|
||||||
|
}
|
||||||
|
]
|
@ -31,32 +31,11 @@ function isPlainObject(obj){
|
|||||||
function isNumber(value){
|
function isNumber(value){
|
||||||
return !isNaN(parseInt(value))
|
return !isNaN(parseInt(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支持导入cjs和esm模块
|
|
||||||
* @param {*} url
|
|
||||||
*/
|
|
||||||
async function importModule(url){
|
|
||||||
try{
|
|
||||||
return require(url)
|
|
||||||
}catch(e){
|
|
||||||
// 当加载出错时,尝试加载esm模块
|
|
||||||
if(e.code === "MODULE_NOT_FOUND"){
|
|
||||||
return await import(url)
|
|
||||||
}else{
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getDataTypeName,
|
getDataTypeName,
|
||||||
isNumber,
|
isNumber,
|
||||||
isPlainObject,
|
isPlainObject
|
||||||
importModule
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { isPlainObject } = require("./utils");
|
const { isPlainObject } = require("../runtime/utils");
|
||||||
|
|
||||||
const DefaultI18nPluginOptions = {
|
const DefaultI18nPluginOptions = {
|
||||||
translateFunctionName:"t", // 默认的翻译函数名称
|
translateFunctionName:"t", // 默认的翻译函数名称
|
@ -27,7 +27,7 @@ const readJson = require("readjson")
|
|||||||
const glob = require("glob")
|
const glob = require("glob")
|
||||||
const createLogger = require("logsets")
|
const createLogger = require("logsets")
|
||||||
const path = require("path")
|
const path = require("path")
|
||||||
const { getMessageId } = require("./utils")
|
const { importModule } = require("./utils")
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
const logger = createLogger()
|
const logger = createLogger()
|
||||||
const artTemplate = require("art-template")
|
const artTemplate = require("art-template")
|
||||||
@ -40,19 +40,30 @@ function normalizeCompileOptions(opts={}) {
|
|||||||
}, opts)
|
}, opts)
|
||||||
if(options.moduleType==="es") options.moduleType = "esm"
|
if(options.moduleType==="es") options.moduleType = "esm"
|
||||||
if(options.moduleType==="cjs") options.moduleType = "commonjs"
|
if(options.moduleType==="cjs") options.moduleType = "commonjs"
|
||||||
if(["commonjs","cjs","esm","es"].includes(options.moduleType)) options.moduleType = "esm"
|
if(!["commonjs","cjs","esm","es"].includes(options.moduleType)) options.moduleType = "esm"
|
||||||
return opts;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function compile(langFolder,opts={}){
|
module.exports =async function compile(langFolder,opts={}){
|
||||||
const options = normalizeCompileOptions(opts);
|
const options = normalizeCompileOptions(opts);
|
||||||
const { output,moduleType } = options;
|
const { output,moduleType } = options;
|
||||||
|
|
||||||
//1. 加载多语言配置文件
|
// 加载多语言配置文件
|
||||||
import(`file:///${path.join(langFolder,"settings.js")}`).then(module=>{
|
const settingsFile = path.join(langFolder,"settings.js")
|
||||||
|
try{
|
||||||
|
// 读取多语言配置文件
|
||||||
|
const module =await importModule(`file:///${settingsFile}`)
|
||||||
const langSettings = module.default;
|
const langSettings = module.default;
|
||||||
let { languages,defaultLanguage,activeLanguage,namespaces } = langSettings
|
let { languages,defaultLanguage,activeLanguage,namespaces } = langSettings
|
||||||
|
|
||||||
|
logger.log("支持的语言\t: {}",languages.map(item=>`${item.title}(${item.name})`))
|
||||||
|
logger.log("默认语言\t: {}",defaultLanguage)
|
||||||
|
logger.log("激活语言\t: {}",activeLanguage)
|
||||||
|
logger.log("名称空间\t: {}",Object.keys(namespaces).join(","))
|
||||||
|
logger.log("模块类型\t: {}",moduleType)
|
||||||
|
logger.log("")
|
||||||
|
logger.log("编译结果输出至:{}",langFolder)
|
||||||
|
|
||||||
// 1. 合并生成最终的语言文件
|
// 1. 合并生成最终的语言文件
|
||||||
let messages = {} ,msgId =1
|
let messages = {} ,msgId =1
|
||||||
glob.sync(path.join(langFolder,"translates/*.json")).forEach(file=>{
|
glob.sync(path.join(langFolder,"translates/*.json")).forEach(file=>{
|
||||||
@ -69,6 +80,8 @@ module.exports = function compile(langFolder,opts={}){
|
|||||||
logger.log("读取语言文件{}失败:{}",file,e.message)
|
logger.log("读取语言文件{}失败:{}",file,e.message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
logger.log(" - 合成语言包文本,共{}条",Object.keys(messages).length)
|
||||||
|
|
||||||
// 2. 为每一个文本内容生成一个唯一的id
|
// 2. 为每一个文本内容生成一个唯一的id
|
||||||
let messageIds = {}
|
let messageIds = {}
|
||||||
Object.entries(messages).forEach(([msg,langs])=>{
|
Object.entries(messages).forEach(([msg,langs])=>{
|
||||||
@ -88,6 +101,7 @@ module.exports = function compile(langFolder,opts={}){
|
|||||||
}else{
|
}else{
|
||||||
fs.writeFileSync(langFile,`module.exports = ${JSON.stringify(langMessages,null,4)}`)
|
fs.writeFileSync(langFile,`module.exports = ${JSON.stringify(langMessages,null,4)}`)
|
||||||
}
|
}
|
||||||
|
logger.log(" - 语言包文件: {}",path.basename(langFile))
|
||||||
})
|
})
|
||||||
|
|
||||||
// 4. 生成id映射文件
|
// 4. 生成id映射文件
|
||||||
@ -97,29 +111,56 @@ module.exports = function compile(langFolder,opts={}){
|
|||||||
}else{
|
}else{
|
||||||
fs.writeFileSync(idMapFile,`module.exports = ${JSON.stringify(messageIds,null,4)}`)
|
fs.writeFileSync(idMapFile,`module.exports = ${JSON.stringify(messageIds,null,4)}`)
|
||||||
}
|
}
|
||||||
|
logger.log(" - idMap文件: {}",path.basename(idMapFile))
|
||||||
|
|
||||||
// 5. 生成编译后的访问入口文件
|
// 5. 生成编译后的访问入口文件
|
||||||
const entryFile = path.join(langFolder,"index.js")
|
const entryFile = path.join(langFolder,"index.js")
|
||||||
const entryContent = artTemplate(path.join(__dirname,"templates","entry.js"), {languages,defaultLanguage,activeLanguage,namespaces,moduleType } )
|
const entryContent = artTemplate(path.join(__dirname,"templates","entry.js"), {languages,defaultLanguage,activeLanguage,namespaces,moduleType,JSON } )
|
||||||
fs.writeFileSync(entryFile,entryContent)
|
fs.writeFileSync(entryFile,entryContent)
|
||||||
|
logger.log(" - 访问入口文件: {}",path.basename(entryFile))
|
||||||
|
|
||||||
|
|
||||||
// 6 . 生成编译后的格式化函数文件
|
// 6 . 生成编译后的格式化函数文件
|
||||||
const formattersFile = path.join(langFolder,"formatters.js")
|
const formattersFile = path.join(langFolder,"formatters.js")
|
||||||
if(!fs.existsSync(formattersFile)){
|
if(!fs.existsSync(formattersFile)){
|
||||||
const formattersContent = artTemplate(path.join(__dirname,"templates","formatters.js"), {languages,defaultLanguage,activeLanguage,namespaces,moduleType } )
|
const formattersContent = artTemplate(path.join(__dirname,"templates","formatters.js"), {languages,defaultLanguage,activeLanguage,namespaces,moduleType } )
|
||||||
fs.writeFileSync(formattersFile,formattersContent)
|
fs.writeFileSync(formattersFile,formattersContent)
|
||||||
}
|
logger.log(" - 格式化器:{}",path.basename(formattersFile))
|
||||||
// 7. 生成package.json
|
}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 ")
|
||||||
|
}else{
|
||||||
|
formattersContent = formattersContent.replaceAll(/\s*export\s*default\s*/g,"module.exports = ")
|
||||||
|
formattersContent = formattersContent.replaceAll(/\s*export\s*/g,"module.exports.")
|
||||||
|
}
|
||||||
|
fs.writeFileSync(formattersFile,formattersContent)
|
||||||
|
logger.log(" - 更新格式化器:{}",path.basename(formattersFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")
|
const packageJsonFile = path.join(langFolder,"package.json")
|
||||||
let packageJson = {}
|
let packageJson = {}
|
||||||
if(moduleType==="esm"){
|
if(moduleType==="esm"){
|
||||||
packageJson = {
|
packageJson = {
|
||||||
|
version:"1.0.0",
|
||||||
type:"module",
|
type:"module",
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
packageJson = {
|
packageJson = {
|
||||||
|
version:"1.0.0",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fs.writeFileSync(packageJsonFile,JSON.stringify(packageJson,null,4))
|
fs.writeFileSync(packageJsonFile,JSON.stringify(packageJson,null,4))
|
||||||
})
|
}catch(e){
|
||||||
|
logger.log("加载多语言配置文件<{}>失败: {} ",settingsFile,e.message)
|
||||||
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ const path = require('path')
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const readJson = require("readjson")
|
const readJson = require("readjson")
|
||||||
const createLogger = require("logsets")
|
const createLogger = require("logsets")
|
||||||
const { replaceInterpolateVars,getDataTypeName } = require("./utils")
|
const { replaceInterpolateVars,getDataTypeName } = require("../runtime/utils")
|
||||||
const logger = createLogger()
|
const logger = createLogger()
|
||||||
|
|
||||||
// 捕获翻译文本的默认正则表达式
|
// 捕获翻译文本的默认正则表达式
|
||||||
@ -177,18 +177,23 @@ function getTranslateTexts(content,file,options){
|
|||||||
},texts)
|
},texts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultExtractLanguages = [
|
||||||
|
{name:'en',title:"英文"},
|
||||||
|
{name:'cn',title:"中文",default:true},
|
||||||
|
{name:'de',title:"德语"},
|
||||||
|
{name:'fr',title:"法语"},
|
||||||
|
{name:'es',title:"西班牙语"},
|
||||||
|
{name:'it',title:"意大利语"},
|
||||||
|
{name:'jp',title:"日語"}
|
||||||
|
]
|
||||||
|
|
||||||
function normalizeLanguageOptions(options){
|
function normalizeLanguageOptions(options){
|
||||||
options = Object.assign({
|
options = Object.assign({
|
||||||
debug : true, // 输出调试信息,控制台输出相关的信息
|
debug : true, // 输出调试信息,控制台输出相关的信息
|
||||||
languages : [ // 支持的语言列表
|
languages :defaultExtractLanguages, // 默认要支持的语言
|
||||||
{name:"en",title:"英文"},
|
|
||||||
{name:"cn",title:"中文",active:true,default:true} // 通过default指定默认语言
|
|
||||||
],
|
|
||||||
defaultLanguage: "cn", // 默认语言:指的是在源代码中的原始文本语言
|
defaultLanguage: "cn", // 默认语言:指的是在源代码中的原始文本语言
|
||||||
activeLanguage : "cn", // 当前激活语言:指的是当前启用的语言,比如在源码中使用中文,在默认激活的是英文
|
activeLanguage : "cn", // 当前激活语言:指的是当前启用的语言,比如在源码中使用中文,在默认激活的是英文
|
||||||
extractor : { // 匹配翻译函数并提取内容的正则表达式
|
extractor : { // 匹配翻译函数并提取内容的正则表达式
|
||||||
//default : DefaultTranslateExtractor,
|
|
||||||
"*" : DefaultTranslateExtractor,
|
"*" : DefaultTranslateExtractor,
|
||||||
"html,vue,jsx" : DefaultHtmlAttrExtractor
|
"html,vue,jsx" : DefaultHtmlAttrExtractor
|
||||||
},
|
},
|
||||||
@ -359,14 +364,8 @@ module.exports = function(options={}){
|
|||||||
if(!outputPath){
|
if(!outputPath){
|
||||||
outputPath = path.join(file.base,"languages")
|
outputPath = path.join(file.base,"languages")
|
||||||
}
|
}
|
||||||
// 跳过空文件
|
if(file.isNull()) return callback()
|
||||||
if(file.isNull()){
|
if(file.isStream()) return callback()
|
||||||
return callback()
|
|
||||||
}
|
|
||||||
// 跳过流文件
|
|
||||||
if(file.isStream()){
|
|
||||||
return callback()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取翻译文本
|
// 提取翻译文本
|
||||||
try{
|
try{
|
||||||
@ -375,10 +374,10 @@ module.exports = function(options={}){
|
|||||||
fileCount++
|
fileCount++
|
||||||
if(debug){
|
if(debug){
|
||||||
const textCount = Object.values(texts).reduce((sum,item)=>sum+Object.keys(item).length,0)
|
const textCount = Object.values(texts).reduce((sum,item)=>sum+Object.keys(item).length,0)
|
||||||
logger.log("Extract <{}>, found [{}] namespaces and {} texts.",file.relative,Object.keys(texts).join(),textCount)
|
logger.log("Extract <{}>, found [{}] namespaces and {} messages.",file.relative,Object.keys(texts).join(),textCount)
|
||||||
}
|
}
|
||||||
}catch(err){
|
}catch(err){
|
||||||
logger.log("Error while extract text from <{}> : {}",file.relative,err.message)
|
logger.log("Error while extract messages from <{}> : {}",file.relative,err.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
callback()
|
callback()
|
||||||
@ -388,6 +387,7 @@ module.exports = function(options={}){
|
|||||||
logger.log(" - Total of files\t: {}",fileCount)
|
logger.log(" - Total of files\t: {}",fileCount)
|
||||||
logger.log(" - Output location\t: {}",outputPath)
|
logger.log(" - Output location\t: {}",outputPath)
|
||||||
const translatesPath = path.join(outputPath,"translates")
|
const translatesPath = path.join(outputPath,"translates")
|
||||||
|
if(!fs.existsSync(outputPath)) fs.mkdirSync(outputPath)
|
||||||
if(!fs.existsSync(translatesPath)) fs.mkdirSync(translatesPath)
|
if(!fs.existsSync(translatesPath)) fs.mkdirSync(translatesPath)
|
||||||
// 每个名称空间对应一个文件
|
// 每个名称空间对应一个文件
|
||||||
for(let [namespace,texts] of Object.entries(results)){
|
for(let [namespace,texts] of Object.entries(results)){
|
||||||
@ -402,16 +402,20 @@ module.exports = function(options={}){
|
|||||||
logger.log(" Save language file : {}",path.relative(outputPath,langFile))
|
logger.log(" Save language file : {}",path.relative(outputPath,langFile))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 将元数据生成到 i18n.meta.json
|
// 生成语言配置文件 settings.js , 仅当不存在时才生成
|
||||||
const metaFile = path.join(outputPath,"settings.js")
|
const settingsFile = path.join(outputPath,"settings.js")
|
||||||
const meta = {
|
if(!fs.existsSync(settingsFile)){
|
||||||
languages : options.languages,
|
const settings = {
|
||||||
defaultLanguage: options.defaultLanguage,
|
languages : options.languages,
|
||||||
activeLanguage : options.activeLanguage,
|
defaultLanguage: options.defaultLanguage,
|
||||||
namespaces : options.namespaces
|
activeLanguage : options.activeLanguage,
|
||||||
}
|
namespaces : options.namespaces
|
||||||
fs.writeFileSync(metaFile,`export default ${JSON.stringify(meta,null,4)}`)
|
}
|
||||||
logger.log(" - Generate language metadata : {}",metaFile)
|
fs.writeFileSync(settingsFile,`module.exports = ${JSON.stringify(settings,null,4)}`)
|
||||||
|
logger.log(" - Generate settings of language : {}",settingsFile)
|
||||||
|
}else{
|
||||||
|
logger.log(" - Settings of language already exists : {}",settingsFile)
|
||||||
|
}
|
||||||
callback()
|
callback()
|
||||||
});
|
});
|
||||||
}
|
}
|
23
packages/tools/index.js
Normal file
23
packages/tools/index.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
const { Command } = require('commander');
|
||||||
|
const program = new Command();
|
||||||
|
|
||||||
|
|
||||||
|
program
|
||||||
|
.option('-d, --debug', '输出调试信息')
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('extract <source> [destination]')
|
||||||
|
.description('扫描指定的项目目录,提取文件中的国际化字符串')
|
||||||
|
.option('-d, --debug', '输出调试信息')
|
||||||
|
.option('-l, --languages', '支持的语言', 'cn,en,de,fr,es,it,jp')
|
||||||
|
.option('-d, --default', '默认语言', 'cn')
|
||||||
|
.option('-a, --active', '激活语言', 'cn')
|
||||||
|
.action((source, destination) => {
|
||||||
|
console.log('clone command called');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
program.parse(process.argv);
|
||||||
|
|
||||||
|
const options = program.opts();
|
26
packages/tools/package.json
Normal file
26
packages/tools/package.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "@voerkai18n/tools",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "VoerkaI18n Tools",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/cli": "^7.17.6",
|
||||||
|
"@babel/core": "^7.17.5",
|
||||||
|
"art-template": "^4.13.2",
|
||||||
|
"commander": "^9.0.0",
|
||||||
|
"glob": "^7.2.0",
|
||||||
|
"logsets": "^1.0.6",
|
||||||
|
"readjson": "^2.2.2",
|
||||||
|
"through2": "^4.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"vinyl": "^2.2.1"
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,18 @@
|
|||||||
{{if moduleTye === "esm"}}
|
{{if moduleType === "esm"}}
|
||||||
import messageIds from "./idMap.js"
|
import messageIds from "./idMap.js"
|
||||||
import { translate,i18n } from "voerka-i18n"
|
import { translate,I18nManager } from "@voerkai18n/runtime"
|
||||||
import defaultMessages from "./{{defaultLanguage}}.js"
|
import defaultMessages from "./{{defaultLanguage}}.js"
|
||||||
import scopeSettings from "./settings.js"
|
import scopeSettings from "./settings.js"
|
||||||
import formatters from "../formatters"
|
|
||||||
{{else}}
|
{{else}}
|
||||||
const messageIds = require("./idMap")
|
const messageIds = require("./idMap")
|
||||||
const { translate,i18n } = require("voerka-i18n")
|
const { translate,i18n } = require("@voerkai18n/runtime")
|
||||||
const defaultMessages = require("./{{defaultLanguage}}.js")
|
const defaultMessages = require("./{{defaultLanguage}}.js")
|
||||||
const scopeSettings = require("./settings.js")
|
const scopeSettings = require("./settings.js")
|
||||||
const formatters = require("../formatters")
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
// 自动创建全局VoerkaI18n实例
|
// 自动创建全局VoerkaI18n实例
|
||||||
if(!globalThis.VoerkaI18n){
|
if(!globalThis.VoerkaI18n){
|
||||||
globalThis.VoerkaI18n = new i18n(scopeSettings)
|
globalThis.VoerkaI18n = new I18nManager(scopeSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
let scope = {
|
let scope = {
|
||||||
@ -22,7 +20,7 @@ let scope = {
|
|||||||
default: defaultMessages, // 默认语言包
|
default: defaultMessages, // 默认语言包
|
||||||
messages : defaultMessages, // 当前语言包
|
messages : defaultMessages, // 当前语言包
|
||||||
idMap:messageIds, // 消息id映射列表
|
idMap:messageIds, // 消息id映射列表
|
||||||
formatters, // 当前作用域的格式化函数列表
|
formatters:{}, // 当前作用域的格式化函数列表
|
||||||
loaders:{}, // 异步加载语言文件的函数列表
|
loaders:{}, // 异步加载语言文件的函数列表
|
||||||
global:{} // 引用全局VoerkaI18n配置,注册后自动引用
|
global:{} // 引用全局VoerkaI18n配置,注册后自动引用
|
||||||
}
|
}
|
||||||
@ -35,14 +33,16 @@ scope.loaders["{{$value.name}}"] = ()=>import("./{{$value.name}}.js")
|
|||||||
{{/if}}{{/each}}
|
{{/if}}{{/each}}
|
||||||
|
|
||||||
const t = ()=> translate.bind(scope)(...arguments)
|
const t = ()=> translate.bind(scope)(...arguments)
|
||||||
|
const languages = {{@ JSON.stringify(languages,null,4) }}
|
||||||
// 注册当前作用域到全局VoerkaI18n实例
|
// 注册当前作用域到全局VoerkaI18n实例
|
||||||
VoerkaI18n.register(scope)
|
VoerkaI18n.register(scope)
|
||||||
|
|
||||||
{{if moduleTye === "esm"}}
|
{{if moduleType === "esm"}}
|
||||||
|
export languages
|
||||||
export scope
|
export scope
|
||||||
export t
|
export t
|
||||||
{{else}}
|
{{else}}
|
||||||
|
module.exports.languages = languages
|
||||||
module.exports.scope = scope
|
module.exports.scope = scope
|
||||||
module.exports.t = t
|
module.exports.t = t
|
||||||
{{/if}}
|
{{/if}}
|
@ -76,7 +76,7 @@ const formatters = {
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
}
|
}
|
||||||
|
|
||||||
{{if moduleTye === "esm"}}
|
{{if moduleType === "esm"}}
|
||||||
export default formatters
|
export default formatters
|
||||||
{{else}}
|
{{else}}
|
||||||
module.exports = formatters
|
module.exports = formatters
|
15
packages/tools/utils.js
Normal file
15
packages/tools/utils.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
|
||||||
|
async function importModule(url){
|
||||||
|
try{
|
||||||
|
return require(url)
|
||||||
|
}catch{
|
||||||
|
return await import(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
importModule
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@voerkai18n/scripts",
|
"name": "@voerkai18n/vue",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
@ -7,5 +7,10 @@
|
|||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC"
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"vinyl": "^2.2.1"
|
||||||
|
}
|
||||||
}
|
}
|
1916
pnpm-lock.yaml
generated
1916
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
27
readme.md
27
readme.md
@ -151,7 +151,7 @@ t("第{}章",100) // == Chapter 100
|
|||||||
## 插值变量格式化
|
## 插值变量格式化
|
||||||
|
|
||||||
voerka-i18n支持对插值变量进行格式化
|
voerka-i18n支持对插值变量进行格式化
|
||||||
|
{{value | filter}} 过滤器语法类似管道操作符,它的上一个输出作为下一个输入。
|
||||||
```javascript
|
```javascript
|
||||||
|
|
||||||
new VoerkaI18n({
|
new VoerkaI18n({
|
||||||
@ -195,6 +195,31 @@ new VoerkaI18n({
|
|||||||
|
|
||||||
t("今天是{date}",{date:new Date()})
|
t("今天是{date}",{date:new Date()})
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 字典
|
||||||
|
|
||||||
|
当翻译内容是一个{}时,启用字典插值模式。
|
||||||
|
```javascript
|
||||||
|
// 源文件
|
||||||
|
// 假设网络状态取值:0=初始化,1=正在连接,2=已连接,3=正在断开.4=已断开,>4=未知
|
||||||
|
|
||||||
|
t("当前状态:{status}",{status})
|
||||||
|
|
||||||
|
// translates/default.json
|
||||||
|
|
||||||
|
{
|
||||||
|
"当前状态:{status}":{
|
||||||
|
cn:{0:"初始化",1:"正在连接",2:"已连接",3:"正在断开",4:"已断开",unknow:"未知"},
|
||||||
|
en:{
|
||||||
|
to:"Status:{}",
|
||||||
|
vars:{"Init","Connecting","Connected","Disconnecting","Disconnected","unknow"}
|
||||||
|
},
|
||||||
|
en:"Status : {status | dict({0:"Init",1:"Connecting",2:"Connected",3:"Disconnecting",4:"Disconnected",5:"unknow"})}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* 内置的格式化器
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
"*":{
|
|
||||||
$types:{
|
|
||||||
Date:(value)=>value.toLocaleString()
|
|
||||||
},
|
|
||||||
time:(value)=> value.toLocaleTimeString(),
|
|
||||||
date: (value)=> value.toLocaleDateString(),
|
|
||||||
},
|
|
||||||
cn:{
|
|
||||||
$types:{
|
|
||||||
Date:(value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日 ${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`
|
|
||||||
},
|
|
||||||
time:(value)=>`${value.getHours()}点${value.getMinutes()}分${value.getSeconds()}秒`,
|
|
||||||
date: (value)=> `${value.getFullYear()}年${value.getMonth()+1}月${value.getDate()}日`,
|
|
||||||
currency:(value)=>`${value}元`,
|
|
||||||
},
|
|
||||||
en:{
|
|
||||||
currency:(value)=>`$${value}`,
|
|
||||||
}
|
|
||||||
}
|
|
13
test/app.test.js
Normal file
13
test/app.test.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 测试demp app的语言运行环境
|
||||||
|
*/
|
||||||
|
const compile = require('../packages/tools/compile');
|
||||||
|
const path = require("path")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
test("导入多语言包",async ()=>{
|
||||||
|
await compile(path.resolve(__dirname,'../packages/demo/apps/app/languages'),{moduleType:"commonjs"})
|
||||||
|
const { t,scope,languages } = require(path.join(__dirname,'../packages/demo/apps/app/languages/index.js'));
|
||||||
|
expect(t).toBeFunction()
|
||||||
|
})
|
@ -1,7 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* 测试babel-plugin-voerkai18n插件
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* babel-plugin-voerkai18n插件可以根据idMap.js文件将源文件中的t函数翻译内容转化为对应的id
|
||||||
|
* 并且可以自动导入t函数
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
const babel = require("@babel/core");
|
const babel = require("@babel/core");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const i18nPlugin = require("../src/babel-plugin-voerkai18n");
|
const i18nPlugin = require("../packages/tools/babel-plugin-voerkai18n");
|
||||||
|
|
||||||
const code = `
|
const code = `
|
||||||
function test(a,b){
|
function test(a,b){
|
||||||
@ -32,7 +41,8 @@ test("翻译函数转换",done=>{
|
|||||||
// 可以指定相对路径,也可以指定绝对路径
|
// 可以指定相对路径,也可以指定绝对路径
|
||||||
autoImport:"#/languages",
|
autoImport:"#/languages",
|
||||||
moduleType:"esm",
|
moduleType:"esm",
|
||||||
// 此参数仅仅用于单元测试时使用,正常情况下,会读取location文件夹下的idMap", idMap:{
|
// 此参数仅仅用于单元测试时使用,正常情况下,会读取location文件夹下的idMap",
|
||||||
|
idMap:{
|
||||||
"a":1,
|
"a":1,
|
||||||
"b":2,
|
"b":2,
|
||||||
"c{}{}":3,
|
"c{}{}":3,
|
||||||
@ -53,7 +63,7 @@ test("读取esm格式的idMap后进行翻译函数转换",done=>{
|
|||||||
[
|
[
|
||||||
i18nPlugin,
|
i18nPlugin,
|
||||||
{
|
{
|
||||||
location:path.join(__dirname, "../demo/apps/lib1/languages"),
|
location:path.join(__dirname, "../packages/demo/apps/lib1/languages"),
|
||||||
autoImport:"#/languages",
|
autoImport:"#/languages",
|
||||||
moduleType:"esm",
|
moduleType:"esm",
|
||||||
}
|
}
|
||||||
@ -70,7 +80,7 @@ test("读取commonjs格式的idMap后进行翻译函数转换",done=>{
|
|||||||
[
|
[
|
||||||
i18nPlugin,
|
i18nPlugin,
|
||||||
{
|
{
|
||||||
location:path.join(__dirname, "../demo/apps/lib2/languages"),
|
location:path.join(__dirname, "../packages/demo/apps/lib2/languages"),
|
||||||
autoImport:"#/languages",
|
autoImport:"#/languages",
|
||||||
moduleType:"esm",
|
moduleType:"esm",
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
const extract = require("../src/extract.plugin");
|
const extract = require("../packages/tools/extract.plugin");
|
||||||
const gulp = require('gulp');
|
const gulp = require('gulp');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const Vinyl = require('vinyl');
|
const Vinyl = require('vinyl');
|
||||||
const { getTranslateTexts, normalizeLanguageOptions } = require("../src/extract.plugin");
|
const { getTranslateTexts, normalizeLanguageOptions } = require("../packages/tools/extract.plugin");
|
||||||
|
|
||||||
|
|
||||||
const languages = [{name:'en',title:"英文"},{name:'cn',title:"中文",default:true},{name:'de',title:"德语"},{name:'jp',title:"日本語"}]
|
const languages = [{name:'en',title:"英文"},{name:'cn',title:"中文",default:true},{name:'de',title:"德语"},{name:'jp',title:"日本語"}]
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
const dayjs = require('dayjs');
|
const dayjs = require('dayjs');
|
||||||
const { getInterpolatedVars, replaceInterpolatedVars , translate} = require('../src/index.js')
|
const { getInterpolatedVars, replaceInterpolatedVars , translate} = require('../packages/runtime/index.js')
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
cn:{
|
cn:{
|
||||||
1:"你好",
|
1:"你好",
|
||||||
2:"现在是{}",
|
2:"现在是{}",
|
||||||
3:"我出生于{year}年,今年{age}岁",
|
3:"我出生于{year}年,今年{age}岁",
|
||||||
|
4:"我有{}个朋友",
|
||||||
},
|
},
|
||||||
en :{
|
en :{
|
||||||
1:"hello",
|
1:"hello",
|
||||||
2:"Now is {}",
|
2:"Now is {}",
|
||||||
3:"I was born in {year}, now is {age} years old",
|
3:"I was born in {year}, now is {age} years old",
|
||||||
|
4:["I have no friends","I have one friends","I have two friends","I have {} friends"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const idMap = {
|
const idMap = {
|
||||||
"你好":1,
|
"你好":1,
|
||||||
"现在是{}":2,
|
"现在是{}":2,
|
||||||
"我出生于{year}年,今年{age}岁":3
|
"我出生于{year}年,今年{age}岁":3,
|
||||||
|
"我有{}个朋友":4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -99,24 +102,48 @@ beforeEach(() => {
|
|||||||
|
|
||||||
|
|
||||||
test("获取翻译内容中的插值变量",done=>{
|
test("获取翻译内容中的插值变量",done=>{
|
||||||
const results = getInterpolatedVars("中华人民共和国成立于{date | year | time }年,首都是{city}市");
|
const results = getInterpolatedVars("中华人民共和国成立于{date | year(1,2) | time('a','b') | rel }年,首都是{city}市");
|
||||||
expect(results.map(r=>r[0]).join(",")).toBe("date,city");
|
expect(results.length).toEqual(2);
|
||||||
expect(results[0][0]).toEqual("date");
|
//
|
||||||
expect(results[0][1]).toEqual(["year","time"]);
|
expect(results[0].name).toEqual("date");
|
||||||
expect(results[1][0]).toEqual("city");
|
expect(results[0].formatters.length).toEqual(3);
|
||||||
expect(results[1][1]).toEqual([]);
|
// year(1,2)
|
||||||
|
expect(results[0].formatters[0].name).toEqual("year");
|
||||||
|
expect(results[0].formatters[0].args).toEqual([1,2]);
|
||||||
|
// time('a','b')
|
||||||
|
expect(results[0].formatters[1].name).toEqual("time");
|
||||||
|
expect(results[0].formatters[1].args).toEqual(["a","b"]);
|
||||||
|
// rel
|
||||||
|
expect(results[0].formatters[2].name).toEqual("rel");
|
||||||
|
expect(results[0].formatters[2].args).toEqual([]);
|
||||||
|
|
||||||
|
|
||||||
|
expect(results[1].name).toEqual("city");
|
||||||
|
expect(results[1].formatters.length).toEqual(0);
|
||||||
|
|
||||||
|
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("获取翻译内容中定义了重复的插值变量",done=>{
|
test("获取翻译内容中定义了重复的插值变量",done=>{
|
||||||
const results = getInterpolatedVars("{a}{a}{a|x}{a|x}{a|x|y}{a|x|y}");
|
const results = getInterpolatedVars("{a}{a}{a|x}{a|x}{a|x|y}{a|x|y}");
|
||||||
expect(results.length).toEqual(3);
|
expect(results.length).toEqual(3);
|
||||||
expect(results[0][0]).toEqual("a");
|
expect(results[0].name).toEqual("a");
|
||||||
expect(results[0][1]).toEqual([]);
|
expect(results[0].formatters.length).toEqual(0);
|
||||||
expect(results[1][0]).toEqual("a");
|
|
||||||
expect(results[1][1]).toEqual(["x"]);
|
expect(results[1].name).toEqual("a");
|
||||||
expect(results[2][0]).toEqual("a");
|
expect(results[1].formatters.length).toEqual(1);
|
||||||
expect(results[2][1]).toEqual(["x","y"]);
|
expect(results[1].formatters[0].name).toEqual("x");
|
||||||
|
expect(results[1].formatters[0].args).toEqual([]);
|
||||||
|
|
||||||
|
|
||||||
|
expect(results[2].name).toEqual("a");
|
||||||
|
expect(results[2].formatters.length).toEqual(2);
|
||||||
|
expect(results[2].formatters[0].name).toEqual("x");
|
||||||
|
expect(results[2].formatters[0].args).toEqual([]);
|
||||||
|
expect(results[2].formatters[1].name).toEqual("y");
|
||||||
|
expect(results[2].formatters[1].args).toEqual([]);
|
||||||
|
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -223,3 +250,14 @@ test("切换到未知语言",done=>{
|
|||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test("翻译复数支持",done=>{
|
||||||
|
changeLanguage("en")
|
||||||
|
expect(t("我有{}个朋友",0)).toBe("I have no friends");
|
||||||
|
expect(t("我有{}个朋友",1)).toBe("I have one friends");
|
||||||
|
expect(t("我有{}个朋友",2)).toBe("I have two friends");
|
||||||
|
expect(t("我有{}个朋友",3)).toBe("I have 3 friends");
|
||||||
|
expect(t("我有{}个朋友",4)).toBe("I have 4 friends");
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user