From 22123a8e3650d378d80d53f065935f9e7adaad75 Mon Sep 17 00:00:00 2001 From: wxzhang Date: Fri, 27 Jan 2023 19:39:40 +0800 Subject: [PATCH] add voerkai18n-loader for webpack --- packages/cli/init.command.js | 9 ++ packages/cli/templates/init-entry.js | 20 +++- packages/cli/templates/init-entry.ts | 20 +++- packages/runtime/scope.js | 13 +++ packages/utils/index.js | 129 +++++++++++++++++++++++- packages/vite/index.d.ts | 2 +- packages/vite/index.js | 124 ++++------------------- packages/vite/utils.js | 117 --------------------- packages/vue/index.d.ts | 1 - packages/webpack/data/app.js | 6 ++ packages/webpack/debug-loader.js | 67 ++++++++++++ packages/webpack/loader.js | 39 +++++++ packages/webpack/package.json | 19 ++++ packages/webpack/src/languages/idMap.js | 4 + pnpm-lock.yaml | 31 +++++- 15 files changed, 360 insertions(+), 241 deletions(-) delete mode 100644 packages/vite/utils.js create mode 100644 packages/webpack/data/app.js create mode 100644 packages/webpack/debug-loader.js create mode 100644 packages/webpack/loader.js create mode 100644 packages/webpack/package.json create mode 100644 packages/webpack/src/languages/idMap.js diff --git a/packages/cli/init.command.js b/packages/cli/init.command.js index f9d98d6..4bf7261 100644 --- a/packages/cli/init.command.js +++ b/packages/cli/init.command.js @@ -94,6 +94,15 @@ module.exports = function(srcPath,{moduleType='cjs',isTypeScript,debug = true,la tasks.error(e.message) } + try{ + tasks.add("生成IdMap文件") + const entryContent = isTypeScript ? "export default {}" : (moduleType=='cjs' ? "module.exports={}" :"export default {}") + fs.writeFileSync(path.join(lngPath,`idMap.${isTypeScript ? 'ts' : 'js'}`),entryContent) + tasks.complete() + }catch(e){ + tasks.error(e.message) + } + try{ tasks.add(t("安装运行时依赖@voerkai18n/runtime")) installPackage('@voerkai18n/runtime') diff --git a/packages/cli/templates/init-entry.js b/packages/cli/templates/init-entry.js index e0dcaaa..e09d273 100644 --- a/packages/cli/templates/init-entry.js +++ b/packages/cli/templates/init-entry.js @@ -16,11 +16,21 @@ const { translate,i18nScope } = require("@voerkai18n/runtime") const scope = new VoerkaI18nScope({ id : "{{scopeId}}", // 当前作用域的id,自动取当前工程的package.json的name debug : false, // 是否在控制台输出高度信息 - default : {}, // 默认语言包 - messages : {}, // 当前语言包 - idMap : {}, // 消息id映射列表 - formatters, // 扩展自定义格式化器 - loaders : {} // 语言包加载器 + default : {}, // 默认语言包 + messages : {}, // 当前语言包 + idMap : {}, // 消息id映射列表 + formatters : {}, // 扩展自定义格式化器 + loaders : {}, // 语言包加载器 + languages: [ + { + name: "zh", + title: "中文" + }, + { + name: "en", + title: "英文" + } + ] }) // 翻译函数 const scopedTtranslate = translate.bind(scope) diff --git a/packages/cli/templates/init-entry.ts b/packages/cli/templates/init-entry.ts index df91257..9c3b3ac 100644 --- a/packages/cli/templates/init-entry.ts +++ b/packages/cli/templates/init-entry.ts @@ -12,11 +12,21 @@ const { translate,VoerkaI18nScope } = runtime const scope = new VoerkaI18nScope({ id : "{{scopeId}}", // 当前作用域的id,自动取当前工程的package.json的name debug : false, // 是否在控制台输出高度信息 - default : {}, // 默认语言包 - messages : {}, // 当前语言包 - idMap : {}, // 消息id映射列表 - formatters : {}, // 扩展自定义格式化器 - loaders : {} // 语言包加载器 + default : {}, // 默认语言包 + messages : {}, // 当前语言包 + idMap : {}, // 消息id映射列表 + formatters : {}, // 扩展自定义格式化器 + loaders : {}, // 语言包加载器 + languages: [ + { + name: "zh", + title: "中文" + }, + { + name: "en", + title: "英文" + } + ] }) // 翻译函数 const scopedTtranslate = translate.bind(scope) diff --git a/packages/runtime/scope.js b/packages/runtime/scope.js index 6d69c54..04bdb52 100644 --- a/packages/runtime/scope.js +++ b/packages/runtime/scope.js @@ -60,6 +60,19 @@ module.exports = class VoerkaI18nScope { * - 将en配置为默认回退语言 */ _initiLanguages(){ + if(!isPlainObject(this._languages)){ + console.warn("[VoerkaI18n] 无效的语言配置") + this._languages = [ + { + name: "zh", + title: "中文" + }, + { + name: "en", + title: "英文" + } + ] + } Object.entries(this._languages).forEach(([name,language])=>{ if(!language.fallback) language.fallback = "en" }) diff --git a/packages/utils/index.js b/packages/utils/index.js index 4210d63..a7c43a2 100644 --- a/packages/utils/index.js +++ b/packages/utils/index.js @@ -476,6 +476,123 @@ function installPackage(packageName){ } +/** + * 读取当前工程下languages/idMap.(js|ts)文件 + * + * @param {*} location 项目根文件夹或者当前项目下的任意一个文件夹 + * @returns + */ +function readIdMapFile(location="./"){ + let searchIdMapFiles = [] + if(!path.isAbsolute(location)){ + location = path.join(process.cwd(),location) + } + searchIdMapFiles.push(path.join(location,"src","languages/idMap.js")) + searchIdMapFiles.push(path.join(location,"languages/idMap.js")) + searchIdMapFiles.push(path.join(location,"idMap.js")) + + searchIdMapFiles.push(path.join(location,"src","languages/idMap.ts")) + searchIdMapFiles.push(path.join(location,"languages/idMap.ts")) + searchIdMapFiles.push(path.join(location,"idMap.ts")) + + let projectRoot = getProjectRootFolder(location) + searchIdMapFiles.push(path.join(projectRoot,"src","languages/idMap.js")) + searchIdMapFiles.push(path.join(projectRoot,"languages/idMap.js")) + searchIdMapFiles.push(path.join(projectRoot,"idMap.js")) + + searchIdMapFiles.push(path.join(projectRoot,"src","languages/idMap.ts")) + searchIdMapFiles.push(path.join(projectRoot,"languages/idMap.ts")) + searchIdMapFiles.push(path.join(projectRoot,"idMap.ts")) + + let idMapFile + for( idMapFile of searchIdMapFiles){ + // 如果不存在idMap文件,则尝试从location/languages/中导入 + if(fs.existsSync(idMapFile)){ + try{ + // 由于idMap.js可能是esm或cjs,并且babel插件不支持异步 + // 当require(idMap.js)失败时,对esm模块尝试采用直接读取的方式 + return require(idMapFile) + }catch(e){ + // 出错原因可能是因为无效require esm模块,由于idMap.js文件格式相对简单,因此尝试直接读取解析 + try{ + let idMapContent = fs.readFileSync(idMapFile).toString() + idMapContent = idMapContent.trim().replace(/^\s*export\s*default\s/g,"") + return JSON.parse(idMapContent) + }catch{ } + } + } + } + throw new Error(`${idMapFile}文件不存在,无法对翻译文本进行转换。`) + return {} +} + + +//const TranslateRegex = /\bt\(\s*("|'){1}(?:((?\w+)::))?(?[^\1]*?)(?=(\1\s*\))|(\1\s*\,))/gm +// 匹配t('xxxx')的正则表达式 +const TranslateRegex =/(?<=\bt\(\s*("|'){1})(?[^\1]*?)(?=(\1\s*\))|(\1\s*\,))/gm + +/** + * 将code中的t("xxxx")使用idMap进行映射为t("1"),t("2")的形式 + * + * @param {*} code + * @param {*} idmap + */ +function replaceTranslateText(code, idmap) { + return code.replaceAll(TranslateRegex, (message) => { + if(message in idmap) { + return idmap[message] + }else{ + let result + // 为什么要decodeURIComponent/unescape? 一些vite插件会将中文编码转义导致无法进行替换,所以要解码一下 + try{ + result = decodeURIComponent(message.replaceAll("\\u","%u")) + return result in idmap ? idmap[result] : message + }catch{ + return message + } + } + }) + // decodeURI 或 decodeURIComponent 对特殊字符进行转义序列编码和解码。 +} + +// 匹配 import {t } from 的正则表达式 +const importTRegex = /^[^\w\r\n\s]*import\s*\{(.*)\bt\b(.*)\}\s*from/gm + + +/** + * 判定代码中是否导入了Translate函数 + * @param {*} code + * @returns + */ +function hasImportTranslateFunction(code){ + return importTRegex.test(code) +} + + +function importTranslateFunction(code,sourceFile,langPath){ + let importSource = path.relative(path.dirname(sourceFile),langPath) + if(!importSource.startsWith(".")){ + importSource = "./" + importSource + } + importSource= importSource.replaceAll("\\","/") + const extName = path.extname(sourceFile) + // Vue文件 + if(extName==".vue"){ + // 优先在中导入 + const setupScriptRegex = /(^\s*\)/gmi + if(setupScriptRegex.test(code)){ + code = code.replace(setupScriptRegex,`$1\nimport { t } from '${importSource}';`) + }else{// 如果没有中导入 + code = code.replace(/(^\s*\)/gmi,`$1\nimport { t } from '${importSource}';`) + } + }else if(['.jsx','.js','.ts','.tsx'].includes(extName)){ + // 普通js/ts文件直接添加到最前面 + code = code = `import { t } from '${importSource}';\n${code}` + } + return code +} + + module.exports = { fileMatcher, // 文件名称匹配器 getProjectRootFolder, // 查找获取项目根目录 @@ -492,8 +609,12 @@ module.exports = { deepMerge, // 深度合并对象 getDataTypeName, // 获取指定变量类型名称 isGitRepo, // 判断当前工程是否是git工程 - fileIsExists, - isTypeScriptProject, - getPackageTool, - installPackage + fileIsExists, // 检查文件是否存在 + isTypeScriptProject, // 当前是否是TypeScript工程 + getPackageTool, // 获取当前工程使用的包工具,如pnpm,yarn,npm + installPackage, // 安装指定的包 + readIdMapFile, // 读取当前工程下的idMap文件 + replaceTranslateText, + hasImportTranslateFunction, + importTranslateFunction // 在代码中导入t函数 } \ No newline at end of file diff --git a/packages/vite/index.d.ts b/packages/vite/index.d.ts index c11f868..37e42bb 100644 --- a/packages/vite/index.d.ts +++ b/packages/vite/index.d.ts @@ -1,7 +1,7 @@ import type { PluginOption } from "vite" export interface Voerkai18nPluginOptions{ location?: string // 指定当前工程目录 - autoImport?: boolean // 是否自动导入t函数 + autoImport?: boolean | string[] // 是否自动导入t函数,或者[".js"]代表只对js文件进行自动导入,允许只对约定的扩展名进行自动导入 debug?:boolean // 是否输出调试信息,当=true时,在控制台输出转换匹配的文件清单 patterns?:(string | RegExp)[] } diff --git a/packages/vite/index.js b/packages/vite/index.js index 10afaee..56ff18b 100644 --- a/packages/vite/index.js +++ b/packages/vite/index.js @@ -1,89 +1,16 @@ const path = require("path") const fs = require("fs") -const { fileMatcher,getProjectRootFolder,getProjectLanguageFolder } = require("@voerkai18n/utils") - -//const TranslateRegex = /\bt\(\s*("|'){1}(?:((?\w+)::))?(?[^\1]*?)(?=(\1\s*\))|(\1\s*\,))/gm - -const TranslateRegex =/(?<=\bt\(\s*("|'){1})(?[^\1]*?)(?=(\1\s*\))|(\1\s*\,))/gm - -// 匹配正则表达式 -const importTRegex = /^[^\w\r\n\s]*import\s*\{(.*)\bt\b(.*)\}\s*from/gm +const { + fileMatcher, + getProjectRootFolder, + getProjectLanguageFolder, + readIdMapFile, + hasImportTranslateFunction, + replaceTranslateText, + importTranslateFunction +} = require("@voerkai18n/utils") -/** - * 读取idMap.js文件 - * - * - * - * @param {*} options - * @returns - */ - function readIdMapFile(options){ - let { location } = options - let searchIdMapFiles = [] - if(!path.isAbsolute(location)){ - location = path.join(process.cwd(),location) - } - searchIdMapFiles.push(path.join(location,"src","languages/idMap.js")) - searchIdMapFiles.push(path.join(location,"languages/idMap.js")) - searchIdMapFiles.push(path.join(location,"idMap.js")) - - searchIdMapFiles.push(path.join(location,"src","languages/idMap.ts")) - searchIdMapFiles.push(path.join(location,"languages/idMap.ts")) - searchIdMapFiles.push(path.join(location,"idMap.ts")) - - let projectRoot = getProjectRootFolder(location) - searchIdMapFiles.push(path.join(projectRoot,"src","languages/idMap.js")) - searchIdMapFiles.push(path.join(projectRoot,"languages/idMap.js")) - searchIdMapFiles.push(path.join(projectRoot,"idMap.js")) - - searchIdMapFiles.push(path.join(projectRoot,"src","languages/idMap.ts")) - searchIdMapFiles.push(path.join(projectRoot,"languages/idMap.ts")) - searchIdMapFiles.push(path.join(projectRoot,"idMap.ts")) - - let idMapFile - for( idMapFile of searchIdMapFiles){ - // 如果不存在idMap文件,则尝试从location/languages/中导入 - if(fs.existsSync(idMapFile)){ - try{ - // 由于idMap.js可能是esm或cjs,并且babel插件不支持异步 - // 当require(idMap.js)失败时,对esm模块尝试采用直接读取的方式 - return require(idMapFile) - }catch(e){ - // 出错原因可能是因为无效require esm模块,由于idMap.js文件格式相对简单,因此尝试直接读取解析 - try{ - let idMapContent = fs.readFileSync(idMapFile).toString() - idMapContent = idMapContent.trim().replace(/^\s*export\s*default\s/g,"") - return JSON.parse(idMapContent) - }catch{ } - } - } - } - // 所有尝试完成后触发错误 - throw new Error(`${idMapFile}文件不存在,无法对翻译文本进行转换。\n原因可能是babel-plugin-voerkai18n插件的location参数未指向有效的语言包所在的目录。`) - -} - - -function replaceCode(code, idmap) { - return code.replaceAll(TranslateRegex, (message) => { - if(message in idmap) { - return idmap[message] - }else{ - const msg = unescape(message.replaceAll("\\u","%u")) - return msg in idmap ? idmap[msg] : message - } - }) -} - -/** - * 判定代码中是否导入了Translate函数 - * @param {*} code - * @returns - */ -function hasImportTranslateFunction(code){ - return importTRegex.test(code) -} /** options = { @@ -95,7 +22,7 @@ function hasImportTranslateFunction(code){ module.exports = function VoerkaI18nPlugin(opts={}) { let options = Object.assign({ location: "./", // 指定当前工程目录 - autoImport: false, // 是否自动导入t函数 + autoImport: false, // 是否自动导入t函数 debug:false, // 是否输出调试信息,当=true时,在控制台输出转换匹配的文件清单 patterns:[ "!\.(svg|css|json|scss|less|sass)$", @@ -126,7 +53,7 @@ module.exports = function VoerkaI18nPlugin(opts={}) { }) let idMap try{ - idMap = readIdMapFile(options) + idMap = readIdMapFile(options.location) }catch(e){ console.warn("读取idMap.js文件失败,@voerkai18n/vite未启用") return @@ -138,40 +65,23 @@ module.exports = function VoerkaI18nPlugin(opts={}) { let [isMatched,pattern] = debug ? matcher.test(id) : [matcher.test(id),null] if(isMatched){ if(debug){ - console.log(`File=${path.relative(projectRoot,id)}, pattern=[${pattern}], import from "${path.relative(path.dirname(id),languageFolder)}"`) + console.log(`[VoerkaI18n] File=${path.relative(projectRoot,id)}, pattern=[${pattern}], import from "${path.relative(path.dirname(id),languageFolder)}"`) } try{ // 判断是否使用了t函数 if(TranslateRegex.test(src)){ - let code = replaceCode(src,idMap) + let code = replaceTranslateText(src,idMap) // 如果没有导入t函数,则尝试自动导入 - if(autoImport && !hasImportTranslateFunction(code)){ - let importSource = path.relative(path.dirname(id),languageFolder) - if(!importSource.startsWith(".")){ - importSource = "./" + importSource - } - importSource=importSource.replace("\\","/") - const extName = path.extname(id) - // 转换Vue文件 - if(extName==".vue"){ - // 优先在中导入 - const setupScriptRegex = /(^\s*\)/gmi - if(setupScriptRegex.test(code)){ - code = code.replace(setupScriptRegex,`$1\nimport { t } from '${importSource}';`) - }else{// 如果没有中导入 - code = code.replace(/(^\s*\)/gmi,`$1\nimport { t } from '${importSource}';`) - } - }else if(['.js','.ts'].includes(extName)){// 普通js/ts文件需要添加到最前面 - code = code = `import { t } from '${importSource}';\n${code}` - } - } + if(autoImport && !hasImportTranslateFunction(code)){ + code = importTranslateFunction(code,id,languageFolder) + } return { code, map: null } } }catch(e){ - console.warn(`vite-plugin-voerkai18n转换<${id}>文件出错:${e.message}`) + console.warn(`[voerkai18n]转换<${id}>文件出错:${e.message}`) } } return { diff --git a/packages/vite/utils.js b/packages/vite/utils.js deleted file mode 100644 index cce274a..0000000 --- a/packages/vite/utils.js +++ /dev/null @@ -1,117 +0,0 @@ -const path = require("path") -const fs = require("fs") -/** - * - * 匹配指定路径或文件名称 - * - * const matcher = fileMatcher([ - * "", // 匹配正则表达式字符串 - * "!", // 以!开头代表否定匹配 - * /正则表达式/ - * ],{ - * basePath:"<指定一个基准目录,所有不是以此开头的均视为不匹配>", - * defaultPatterns:["<默认排除的模式>","<默认排除的模式>","<默认排除的模式>"], - * debug:false,是否输出调试信息,当=true时,.test()方法返回[,pattern] * - * }) - * - * - * - * - * @param {*} patterns - * @param {*} basePath 如果指定basePath,则所有不是以basePath开头的文件都排除 - * @param {*} defaultPatterns 默认的匹配模式 - * @param {*} debug 是否输出调试信息 - */ - - function fileMatcher(patterns,{basePath,defaultPatterns=[],debug=true}={}) { - if(basePath) { - basePath = path.normalize(basePath) - } - //[[pattern,exclude],[pattern,false],[pattern,true]] - let finalPatterns = [] - let inputPatterns = Array.isArray(patterns) ? patterns : (patterns ? [patterns] : []) - - // 默认排除模式 - if(defaultPatterns.length===0){ - finalPatterns.push([/.*\/node_modules\/.*/,true]) - finalPatterns.push([/.*\/languages\/.*/,true]) // 默认排除语言文件 - finalPatterns.push([/\.babelrc/,true]) - finalPatterns.push([/babel\.config\.js/,true]) - finalPatterns.push([/package\.json$/,true]) - finalPatterns.push([/vite\.config\.js$/,true]) - finalPatterns.push([/^plugin-vue:.*/,true]) - } - - inputPatterns.forEach(pattern=>{ - if(typeof pattern === "string"){ - pattern.replaceAll("**",".*") - pattern.replaceAll("?","[^\/]?") - pattern.replaceAll(/(? { - let isMatched = false - let file = filename - // 如果指定basePath,则文件名称必须是以basePath开头 - if(basePath){ - if(path.isAbsolute(file)){ - if(!path.normalize(file).startsWith(basePath)){ - return debug ? [false,`!^${basePath}`] : false - }else{ - isMatched = true - } - } - } - if(finalPatterns.length===0){ - return debug ? [true,"*"] : true - }else{ - for(const pattern of finalPatterns){ - pattern[0].lastIndex = 0 - if(pattern[1]===true){ - if(pattern[0].test(file)) return debug ? [false,pattern[0].toString()] : false - }else{ - if(pattern[0].test(file)) return debug ? [true,pattern[0].toString()] : true - } - } - } - return debug ? [isMatched,"*"] : isMatched - } - } -} - - -function getProjectRootFolder(folder,exclueCurrent=false){ - if(!path.isAbsolute(folder)){ - folder = path.join(process.cwd(),folder) - } - try{ - const pkgFile =exclueCurrent ? - path.join(folder, "..", "package.json") - : path.join(folder, "package.json") - if(fs.existsSync(pkgFile)){ - return path.dirname(pkgFile) - } - const parent = path.dirname(folder) - if(parent===folder) return null - return getProjectRootFolder(parent,false) - }catch(e){ - return process.cwd() - } -} - -module.exports = { - fileMatcher, - getProjectRootFolder -} \ No newline at end of file diff --git a/packages/vue/index.d.ts b/packages/vue/index.d.ts index f6ac214..a8340db 100644 --- a/packages/vue/index.d.ts +++ b/packages/vue/index.d.ts @@ -1,4 +1,3 @@ -export {} import type { VoerkaI18nSupportedLanguages, VoerkaI18nTranslate } from "@Voerkai18n/runtime" import type { InjectionKey,Plugin } from "vue" diff --git a/packages/webpack/data/app.js b/packages/webpack/data/app.js new file mode 100644 index 0000000..b1aa5dd --- /dev/null +++ b/packages/webpack/data/app.js @@ -0,0 +1,6 @@ +t("中国") +t("中华人民共和国") +t('中国') +t('中华人民共和国') +t("中国",1) +t("中华人民共和国","fdf") \ No newline at end of file diff --git a/packages/webpack/debug-loader.js b/packages/webpack/debug-loader.js new file mode 100644 index 0000000..e6c2324 --- /dev/null +++ b/packages/webpack/debug-loader.js @@ -0,0 +1,67 @@ +const { runLoaders } = require("loader-runner") +const path = require("path") +const fs = require("fs") + +runLoaders({ + resource: path.join(__dirname, "data","app.js"), + // String: Absolute path to the resource (optionally including query string) + + // loaders: [path.join(__dirname, "loader.js?x=1")], + loaders:[ + { + loader:path.join(__dirname, "loader.js"), + options:{ + a:1 + } + } + ], + // String[]: Absolute paths to the loaders (optionally including query string) + // {loader, options}[]: Absolute paths to the loaders with options object + + context: { minimize: true }, + // Additional loader context which is used as base context + + // processResource: (loaderContext, resourcePath, callback) => { + // console.log("loaderContext=",resourcePath) + // callback() + // }, + // Optional: A function to process the resource + // Must have signature function(context, path, function(err, buffer)) + // By default readResource is used and the resource is added a fileDependency + + readResource: fs.readFile.bind(fs) + // Optional: A function to read the resource + // Only used when 'processResource' is not provided + // Must have signature function(path, function(err, buffer)) + // By default fs.readFile is used +}, function(err, result) { + if(err){ + console.error("替换失败!!!") + console.error(err.stack) + }else{ + console.log("********** 成功 **********") + console.log(result.result) + } + + // err: Error? + + // result.result: Buffer | String + // The result + // only available when no error occured + + // result.resourceBuffer: Buffer + // The raw resource as Buffer (useful for SourceMaps) + // only available when no error occured + + // result.cacheable: Bool + // Is the result cacheable or do it require reexecution? + + // result.fileDependencies: String[] + // An array of paths (existing files) on which the result depends on + + // result.missingDependencies: String[] + // An array of paths (not existing files) on which the result depends on + + // result.contextDependencies: String[] + // An array of paths (directories) on which the result depends on +}) \ No newline at end of file diff --git a/packages/webpack/loader.js b/packages/webpack/loader.js new file mode 100644 index 0000000..8ed7c60 --- /dev/null +++ b/packages/webpack/loader.js @@ -0,0 +1,39 @@ +const path = require('path'); +const fs = require('fs'); + +const { + getProjectRootFolder, + getProjectLanguageFolder, + readIdMapFile, + replaceTranslateText, + hasImportTranslateFunction, + importTranslateFunction +} = require('@voerkai18n/utils') + + +function voerkaI18nLoader(content, map, meta) { + const { autoImport,debug } =Object.assign({ + autoImport: false, // 是否自动导入t函数 + debug:false // 输出一些调试信息 + },this.query || {}) + try{ + const projectPath = getProjectRootFolder(this.resourcePath) + const lngPath = getProjectLanguageFolder(projectPath) + if(debug){ + console.log("[voerkai18n-loader]",`source=${this.resourcePath}`) + } + // 是否自动导入t函数 + if(autoImport && !hasImportTranslateFunction(content) ){ + content = importTranslateFunction(content, this.resourcePath , lngPath) + } + const idMap = readIdMapFile(projectPath) + return replaceTranslateText(content,idMap) + }catch(e){ + if(debug){ + console.error("[voerkai18n-loader]",this.resourcePath,e.stack) + } + } + return content +} + +module.exports = voerkaI18nLoader; diff --git a/packages/webpack/package.json b/packages/webpack/package.json new file mode 100644 index 0000000..e2be47e --- /dev/null +++ b/packages/webpack/package.json @@ -0,0 +1,19 @@ +{ + "name": "voerkai18n-loader", + "version": "1.0.0", + "description": "voerkai18n loader for webpack", + "main": "loader.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "loader-runner": "^4.3.0", + "loader-utils": "^3.2.1" + }, + "dependencies": { + "@voerkai18n/utils": "workspace:^1.0.21" + } +} diff --git a/packages/webpack/src/languages/idMap.js b/packages/webpack/src/languages/idMap.js new file mode 100644 index 0000000..f44bad4 --- /dev/null +++ b/packages/webpack/src/languages/idMap.js @@ -0,0 +1,4 @@ +module.exports = { + 中国:1, + 中华人民共和国:2 +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 91d72cd..0dae21f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -247,7 +247,7 @@ importers: rollup-plugin-terser: ^7.0.2 dependencies: '@babel/runtime': 7.20.7 - '@babel/runtime-corejs3': 7.20.7 + '@babel/runtime-corejs3': 7.20.13 core-js: 3.27.1 devDependencies: '@babel/cli': 7.18.10_@babel+core@7.18.10 @@ -288,6 +288,17 @@ importers: '@voerkai18n/runtime': link:../runtime vue: 3.2.45 + packages/webpack: + specifiers: + '@voerkai18n/utils': workspace:^1.0.21 + loader-runner: ^4.3.0 + loader-utils: ^3.2.1 + dependencies: + '@voerkai18n/utils': link:../utils + devDependencies: + loader-runner: 4.3.0 + loader-utils: 3.2.1 + packages: /@ampproject/remapping/2.2.0: @@ -1504,6 +1515,14 @@ packages: core-js-pure: 3.24.1 regenerator-runtime: 0.13.9 + /@babel/runtime-corejs3/7.20.13: + resolution: {integrity: sha512-p39/6rmY9uvlzRiLZBIB3G9/EBr66LBMcYm7fIDeSBNdRjF2AGD3rFZucUyAgGHC2N+7DdLvVi33uTjSE44FIw==} + engines: {node: '>=6.9.0'} + dependencies: + core-js-pure: 3.27.1 + regenerator-runtime: 0.13.11 + dev: false + /@babel/runtime-corejs3/7.20.7: resolution: {integrity: sha512-jr9lCZ4RbRQmCR28Q8U8Fu49zvFqLxTY9AMOUz+iyMohMoAgpEcVxY+wJNay99oXOpOcCTODkk70NDN2aaJEeg==} engines: {node: '>=6.9.0'} @@ -8160,6 +8179,11 @@ packages: pinkie-promise: 2.0.1 strip-bom: 2.0.0 + /loader-runner/4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + dev: true + /loader-utils/1.4.0: resolution: {integrity: sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==} engines: {node: '>=4.0.0'} @@ -8169,6 +8193,11 @@ packages: json5: 1.0.1 dev: true + /loader-utils/3.2.1: + resolution: {integrity: sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==} + engines: {node: '>= 12.13.0'} + dev: true + /locate-path/5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'}