diff --git a/packages/runtime/index.js b/packages/runtime/index.js index 7e67742..b81f32d 100644 --- a/packages/runtime/index.js +++ b/packages/runtime/index.js @@ -477,6 +477,7 @@ function translate(message) { let vars=[] // 插值变量列表 let pluralVars= [] // 复数变量 let pluraValue = null // 复数值 + if(!typeof(message)==="string") return message try{ // 1. 预处理变量: 复数变量保存至pluralVars中 , 变量如果是Function则调用 if(arguments.length === 2 && isPlainObject(arguments[1])){ @@ -503,19 +504,25 @@ function translate(message) { }) } - + // 由于在编译语言时会使用JSON.stringify进行保存,而JSON.stringify会将\t\n\r转换为\\t\\n\\r的形式 + // 这会导致在翻译时,如果消息中有\t\n\r则会出现翻译错误 + // 所以需要将message再次使用JSON.stringify进行转换才可以匹配 + content = JSON.stringify(content) + content = content.substr(1,content.length-2) + // 2. 取得翻译文本模板字符串 if(activeLanguage === scope.defaultLanguage){ // 2.1 从默认语言中取得翻译文本模板字符串 // 如果当前语言就是默认语言,不需要查询加载,只需要做插值变换即可 // 当源文件运用了babel插件后会将原始文本内容转换为msgId // 如果是msgId则从scope.default中读取,scope.default=默认语言包={:} - if(isMessageId(content)){ + if(isMessageId(text)){ content = scope.default[content] || message } }else{ // 2.2 从当前语言包中取得翻译文本模板字符串 // 如果没有启用babel插件将源文本转换为msgId,需要先将文本内容转换为msgId + // JSON.stringify在进行转换时会将\t\n\r转换为\\t\\n\\r,这样在进行匹配时就出错 let msgId = isMessageId(content) ? content : scope.idMap[content] content = scope.messages[msgId] || content } diff --git a/packages/tools/extract.plugin.js b/packages/tools/extract.plugin.js index 4286caf..447b092 100644 --- a/packages/tools/extract.plugin.js +++ b/packages/tools/extract.plugin.js @@ -17,8 +17,12 @@ const logger = createLogger() const { t } = require("./languages") -// 捕获翻译文本的默认正则表达式 -const DefaultTranslateExtractor = String.raw`\b{funcName}\(\s*("|'){1}(?:((?\w+)::))?(?.*?)(((\1\s*\)){1})|((\1){1}\s*(,(\w|\d|(?:\{.*\})|(?:\[.*\])|([\"\'\(].*[\"\'\)]))*)*\s*\)))` +// 捕获翻译文本正则表达式一:缺点:当t(xxx,...复杂的表达式时不能正确匹配....) +// const DefaultTranslateExtractor = String.raw`\b{funcName}\(\s*("|'){1}(?:((?\w+)::))?(?.*?)(((\1\s*\)){1})|((\1){1}\s*(,(\w|\d|(?:\{.*\})|(?:\[.*\])|([\"\'\(].*[\"\'\)]))*)*\s*\)))` + +// 捕获翻译文本正则表达式二: 能够支持复杂的表达式,但是当提供不完整的t函数定义时,也会进行匹配提取 ,比如t +const DefaultTranslateExtractor = String.raw`\bt\(\s*("|'){1}(?:((?\w+)::))?(?.*?)(?=(\1\s*\))|(\1\s*\,))` + // 从html文件标签中提取翻译文本 const DefaultHtmlAttrExtractor = String.raw`\<(?\w+)(.*?)(?{attrName}\s*\=\s*)([\"\'']{1})(?.*?)(\4){1}\s*(.*?)(\>|\/\>)` @@ -84,7 +88,7 @@ function extractTranslateTextUseRegexp(content,namespace,extractor,file,options) texts[ns][text] ={} languages.forEach(language=>{ if(language.name !== defaultLanguage){ - texts[ns][text][language.name] = text //"" + texts[ns][text][language.name] = text } }) texts[ns][text]["$file"]=[file.relative] @@ -353,7 +357,7 @@ module.exports = function(options={}){ options = normalizeLanguageOptions(options) let {debug,outputPath, updateMode,languages} = options - logger.log(t("支持的语言\t: {}"),options.languages.map(item=>`${item.title}(${item.name})`).join(",")) + logger.log(t("支持的语言\t: {}",options.languages.map(item=>`${item.title}(${item.name})`).join(","))) logger.log("默认语言\t: {}",options.defaultLanguage) logger.log("激活语言\t: {}",options.activeLanguage) logger.log("名称空间\t: {}",Object.keys(options.namespaces).join(",")) diff --git a/packages/tools/index.js b/packages/tools/index.js index 2cb5c9c..9efecb4 100644 --- a/packages/tools/index.js +++ b/packages/tools/index.js @@ -106,4 +106,5 @@ program program.parseAsync(process.argv); -const options = program.opts(); \ No newline at end of file +const options = program.opts(); + \ No newline at end of file diff --git a/packages/tools/languages/cn.js b/packages/tools/languages/cn.js index 3fb3b4f..388e839 100644 --- a/packages/tools/languages/cn.js +++ b/packages/tools/languages/cn.js @@ -1,4 +1,4 @@ module.exports = { - "1": "工程项目所在目录", - "2": "支持的语言\\t: {}" + "1": "支持的语言\t: {}", + "2": "工程项目所在目录" } \ No newline at end of file diff --git a/packages/tools/languages/en.js b/packages/tools/languages/en.js index 5e5d2fa..49c31c9 100644 --- a/packages/tools/languages/en.js +++ b/packages/tools/languages/en.js @@ -1,4 +1,4 @@ module.exports = { - "1": "Project directory", - "2": "Supported Languages\\t: {}" + "1": "Supported Languages\t: {}", + "2": "Project Directory" } \ No newline at end of file diff --git a/packages/tools/languages/formatters.js b/packages/tools/languages/formatters.js index 70631cb..8985775 100644 --- a/packages/tools/languages/formatters.js +++ b/packages/tools/languages/formatters.js @@ -100,6 +100,6 @@ const formatters = { } -module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.exports.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s = formatters +module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.module.exports.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s = formatters diff --git a/packages/tools/languages/idMap.js b/packages/tools/languages/idMap.js index a665e68..21ba2f7 100644 --- a/packages/tools/languages/idMap.js +++ b/packages/tools/languages/idMap.js @@ -1,4 +1,4 @@ module.exports = { - "工程项目所在目录": 1, - "支持的语言\\t: {}": 2 + "支持的语言\t: {}": 1, + "工程项目所在目录": 2 } \ No newline at end of file diff --git a/packages/tools/languages/translates/default.json b/packages/tools/languages/translates/default.json index 67ec3a9..eaf3cab 100644 --- a/packages/tools/languages/translates/default.json +++ b/packages/tools/languages/translates/default.json @@ -1,38 +1,15 @@ { - "工程项目所在目录": { - "en": "Project directory", - "$file": [ - "index.js" - ] - }, - "支持的语言\\t: {}": { - "en": "Supported Languages\\t: {}", + "支持的语言\t: {}": { + "en": "Supported Languages\t: {}", "$file": [ + "compile.command.js", "extract.plugin.js" ] }, - "xxxxx": { - "en": "xxxxx", + "工程项目所在目录": { + "en": "Project Directory", "$file": [ - "babel-plugin-voerkai18n.js" - ] - }, - "id": { - "en": "id", - "$file": [ - "babel-plugin-voerkai18n.js" - ] - }, - "支持的语言\\t: {}\",languages.map(item=>`${item.title}(${item.name})`).join(": { - "en": "支持的语言\\t: {}\",languages.map(item=>`${item.title}(${item.name})`).join(", - "$file": [ - "compile.command.js" - ] - }, - "Now is { value | date | bjTime }": { - "en": "Now is { value | date | bjTime }", - "$file": [ - "templates\\formatters.js" + "index.js" ] } } \ No newline at end of file diff --git a/packages/tools/utils.js b/packages/tools/utils.js index 520e33f..abddae8 100644 --- a/packages/tools/utils.js +++ b/packages/tools/utils.js @@ -110,6 +110,71 @@ function createJsModuleFile(filename,defaultExports={},namedExports={},moduleTyp } } + +/** + * + * JSON.stringify在将一个JSON转化为字符串时会对字符串里面的\t等转义符进行再次转义 + * 导致在使用包含\t等转义符为key时会出现问题 + * + * + * @param {*} obj + * @returns + */ +function escape(str){ + return str.replaceAll("\t","\\t") +} + +function ObjectToString(obj,{indent=4,alignKey=true}={}){ + function nodeToString(node,level,last=false){ + let results = [],beginChar = "",endChar = "" + level++ + if(Array.isArray(node)){ + beginChar = "[\n" + node.forEach((value,index)=>{ + + }) + endChar =" ".repeat((level-1) * indent) + ( last ? "]" : "]\n") + }else if(isPlainObject(node)){ + beginChar = "{\n" + const length = Object.keys(node).length + const indentSpace = " ".repeat(level * indent) + let alignIndent = 0 + Object.entries(node).forEach(([key,value],index)=>{ + const isLastItem = index ===length-1 + alignIndent = Math.max(getStringWidth(key),alignIndent) + let item = [`${indentSpace}"${key}"`,value] + if(Array.isArray(value) || isPlainObject(value)){ + item[1] = nodeToString(value, level,isLastItem) + }else if(typeof(value)==="string"){ + item[1] = `"${value.toString()}"` + }else if(typeof(value)==="number"){ + item[1] = `${value.toString()}` + }else if(typeof(value)==="boolean"){ + item[1] = `${value.toString()}` + } + // 如果最后一项 + if(!isLastItem){ + item[1] = item[1]+"," + }else{ + item[1] = item[1]+"\n" + } + results.push(item) + }) + endChar =" ".repeat((level-1) * indent) + ( last ? "}" : "}\n") + return beginChar + results.map(item=>{ + if(alignKey){ + return `${escape(item[0])}${ " ".repeat(alignIndent-getStringWidth(item[0].trim())+2)}: ${escape(item[1])}` + }else{ + return `${escape(item[0])}: ${escape(item[1])}` + } + }).join("\n") + endChar + } + + } + return nodeToString(obj,0,true) +} + + module.exports = { importModule, findModuleType,