init
This commit is contained in:
commit
1e4f95ad01
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/.vscode
|
||||||
|
/node_modules
|
20
demodata/a/a1.js
Normal file
20
demodata/a/a1.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
t("a1:aaaaa")
|
||||||
|
|
||||||
|
t('no aaaaa')
|
||||||
|
t("no aaaaa")
|
||||||
|
t('no aaaaa')
|
||||||
|
|
||||||
|
t('a1:bbbbb',a,b,c)
|
||||||
|
|
||||||
|
t("cccc Arrow Function",()=>{},c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("dddd中国",c)
|
||||||
|
t("eeeeee", )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("x:from a")
|
20
demodata/a/a2.js
Normal file
20
demodata/a/a2.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
t("a2:aaaaa")
|
||||||
|
|
||||||
|
t('no erer')
|
||||||
|
t("no aaareraa")
|
||||||
|
t('no fdfd')
|
||||||
|
|
||||||
|
t('fdgfdgfdg',a,b,c)
|
||||||
|
|
||||||
|
t("cccc Arrow Function",()=>{},c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("ddddd中国",c)
|
||||||
|
t("eeeeee", )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("x:from a")
|
16
demodata/b/b1.js
Normal file
16
demodata/b/b1.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
t("aaaaa")
|
||||||
|
|
||||||
|
|
||||||
|
t('bbbbb',a,b,c)
|
||||||
|
|
||||||
|
t("cccc",()=>{},c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("ddddd中国",()=>{},c)
|
||||||
|
t("eeeeee")
|
||||||
|
|
||||||
|
t("ddddd中国",()=>{},c)
|
||||||
|
t("x:from b")
|
9
demodata/c/c1.js
Normal file
9
demodata/c/c1.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
t("ccccc")
|
||||||
|
|
||||||
|
t('cccccdc')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("x:from c",ddd)
|
20
demodata/c/c2.js
Normal file
20
demodata/c/c2.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
t("a2:aaaaa")
|
||||||
|
|
||||||
|
t('no erer')
|
||||||
|
t("no aaareraa")
|
||||||
|
t('no fdfd')
|
||||||
|
|
||||||
|
t('fdgfdgfdg',a,b,c)
|
||||||
|
|
||||||
|
t("cccc Arrow Function",()=>{},c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("ddddd中国",c)
|
||||||
|
t("eeeeee", )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("x:from a")
|
14
demodata/index.js
Normal file
14
demodata/index.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
t("aaaaa")
|
||||||
|
|
||||||
|
t('aaaaa1') t("aaaaa2") t('aaaaa 3')
|
||||||
|
|
||||||
|
t('bbbbb',a,b,c)
|
||||||
|
|
||||||
|
t("cccc",()=>{},c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t("ddddd中国",()=>{},c)
|
||||||
|
t("eeeeee", )
|
3
demodata/languages/ddd.js
Normal file
3
demodata/languages/ddd.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
"确定":"OK" // a/b/b1.js
|
||||||
|
}
|
17
package.json
Normal file
17
package.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "voerka-i18n",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"extract": ""
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"through2": "^4.0.2"
|
||||||
|
}
|
||||||
|
}
|
2138
pnpm-lock.yaml
generated
Normal file
2138
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
109
src/extract.plugin.js
Normal file
109
src/extract.plugin.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
* 从源文件中提取要翻译的文本
|
||||||
|
*/
|
||||||
|
|
||||||
|
const through2 = require('through2')
|
||||||
|
const deepmerge = require("deepmerge")
|
||||||
|
|
||||||
|
// 捕获翻译函数的表达式
|
||||||
|
const DefaultTranslateMatcher = /\bt\(\s*("|'){1}(?:((?<namespace>\w+):))?(?<text>.*?)(((\1\s*\)){1})|((\1){1}\s*(,(\w|\d|(?:\{.*\})|(?:\[.*\])|([\"\'\(].*[\"\'\)]))*)*\s*\)))/gm
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 找出要翻译的文本列表 {namespace:[text,text],...}
|
||||||
|
* {namespace:{text:[],...}
|
||||||
|
* @param {*} content
|
||||||
|
* @param {*} matcher
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function getTranslateTexts(content,matcher,namespace,file){
|
||||||
|
if(!matcher) return
|
||||||
|
let texts = {default:{}}
|
||||||
|
while ((result = matcher.exec(content)) !== null) {
|
||||||
|
// 这对于避免零宽度匹配的无限循环是必要的
|
||||||
|
if (result.index === matcher.lastIndex) {
|
||||||
|
matcher.lastIndex++;
|
||||||
|
}
|
||||||
|
const text = result.groups.text
|
||||||
|
if(text){
|
||||||
|
const ns = result.groups.namespace || namespace
|
||||||
|
if(!(ns in texts)){
|
||||||
|
texts[ns] = {}
|
||||||
|
}
|
||||||
|
texts[ns][text] = [file.relative]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return texts
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将texts合并到results中
|
||||||
|
function mergeTranslateTexts(results,texts){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取指定文件的名称空间
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} file
|
||||||
|
* @param {*} namespaces 名称空间配置 {<name>:[path,...,path],<name>:path,<name>:(file)=>{}}
|
||||||
|
*/
|
||||||
|
function getFileNamespace(file,options){
|
||||||
|
const {output, namespaces } = options
|
||||||
|
const refPath = file.relative.toLowerCase()
|
||||||
|
for(let [name,paths] of Object.entries(options.namespaces)){
|
||||||
|
if(typeof paths === "string"){
|
||||||
|
paths = [paths]
|
||||||
|
}
|
||||||
|
for(let path of paths){
|
||||||
|
if(refPath.startsWith(path.toLowerCase())){
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = function(options={}){
|
||||||
|
options = Object.assign({
|
||||||
|
debug : true, // 输出调试信息
|
||||||
|
format : "js", // 目标文件格式,取值JSON,JS
|
||||||
|
languages : ["en","zh"], // 目标语言列表
|
||||||
|
defaultLanguage: "zh", // 默认语言
|
||||||
|
matcher : DefaultTranslateMatcher, // 匹配翻译函数并提取内容的正则表达式
|
||||||
|
namespaces : {}, // 命名空间, {[name]: [path,...,path]}
|
||||||
|
output : null // 输出目录,如果没有指定,则转让
|
||||||
|
},options)
|
||||||
|
let {debug,output:outputPath,languages} = options
|
||||||
|
// 输出语言文件 {cn:{default:<文件>,namespace:<文件>},en:{default:{}}}
|
||||||
|
let outputFiles = languages.map(language=>{})
|
||||||
|
// 保存提交提取的文本 = {}
|
||||||
|
let results = {}
|
||||||
|
// file == vinyl实例
|
||||||
|
return through2.obj(function(file, encoding, callback){
|
||||||
|
if(!outputPath){
|
||||||
|
outputPath = path.join(file.base,"languages")
|
||||||
|
}
|
||||||
|
// 跳过空文件
|
||||||
|
if(file.isNull()){
|
||||||
|
return callback()
|
||||||
|
}
|
||||||
|
// 跳过流文件
|
||||||
|
if(file.isStream()){
|
||||||
|
return callback()
|
||||||
|
}
|
||||||
|
// 获取该文件的
|
||||||
|
const namespace = getFileNamespace(file,options)
|
||||||
|
if(debug) console.log(namespace," : ",file.path)
|
||||||
|
|
||||||
|
// 提出出翻译文件
|
||||||
|
const texts = getTranslateTexts(file.contents.toString(),options.matcher,namespace,file)
|
||||||
|
results = deepmerge(results,texts)
|
||||||
|
|
||||||
|
callback()
|
||||||
|
},function(callback){
|
||||||
|
console.log("输出路径:",outputPath)
|
||||||
|
console.log(JSON.stringify(results,null,2))
|
||||||
|
});
|
||||||
|
}
|
18
src/extract.test.js
Normal file
18
src/extract.test.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const extract = require('./extract.plugin');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
|
||||||
|
const soucePath = path.join(__dirname,'../demodata')
|
||||||
|
|
||||||
|
gulp.src([
|
||||||
|
soucePath+ '/**',
|
||||||
|
"!"+ soucePath+ '/languages/**'
|
||||||
|
]).pipe(extract({
|
||||||
|
// output: path.join(soucePath , 'languages'),
|
||||||
|
namespaces:{
|
||||||
|
"a":"a",
|
||||||
|
"b":"b",
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.pipe(gulp.dest(path.join(__dirname,'../demodata/languages')));
|
0
src/index.js
Normal file
0
src/index.js
Normal file
Loading…
x
Reference in New Issue
Block a user