158 lines
5.2 KiB
JavaScript
158 lines
5.2 KiB
JavaScript
/**
|
||
* 实现将{}转化为字符串
|
||
*
|
||
* 为什么不使用JSON.stringify?
|
||
*
|
||
* 假设有这样的翻译内容
|
||
* {
|
||
* "保存{}\n": "Save{}\n",
|
||
* }
|
||
* 这个内容中包含了转义字符\n,JSON.stringify会将\n转义为\\n
|
||
* 因此,在保存后文件中就变成:
|
||
* {
|
||
* "保存{}\\n": "Save{}\n",
|
||
* }
|
||
* 这个转义方式比较不符合我们的预期,更关键的是,在require("zh.js")时,
|
||
* 得到的是:
|
||
* {
|
||
* "保存{}\\n": "Save{}\n",
|
||
* }
|
||
* 这样当我们调用t函数时就会找不到对应在的key
|
||
*
|
||
* 问题的关键就在于,JSON.stringify对转义字符的处理不能符合我们的要求。
|
||
*
|
||
* 因此,不得不自己来处理转义字符.
|
||
*
|
||
* 使用objectToString方法后,就可以确保在翻译文件中的转义字符能按预期的方式工作。
|
||
*
|
||
*
|
||
*
|
||
*/
|
||
|
||
const { isPlainObject } = require("./utils")
|
||
/**
|
||
*
|
||
* JSON.stringify在将一个JSON转化为字符串时会对字符串里面的\t等转义符进行再次转义
|
||
* 导致在使用包含\t等转义符为key时会出现问题
|
||
*
|
||
*
|
||
* @param {*} obj
|
||
* @returns
|
||
*/
|
||
function escape(str){
|
||
return str.replaceAll(/\\\\(?![trnbvf'"]{1})/g,"\\\\")
|
||
.replaceAll("\t","\\t")
|
||
.replaceAll("\n","\\n")
|
||
.replaceAll("\b","\\b")
|
||
.replaceAll("\r","\\r")
|
||
.replaceAll("\f","\\f")
|
||
.replaceAll("\'","\\'")
|
||
.replaceAll('\"','\\"')
|
||
.replaceAll('\v','\\v')
|
||
}
|
||
function unescape(str){
|
||
return str
|
||
.replaceAll("\\t","\t")
|
||
.replaceAll("\\n","\n")
|
||
.replaceAll("\\b","\b")
|
||
.replaceAll("\\r","\r")
|
||
.replaceAll("\\f","\f")
|
||
.replaceAll("\\'","\'")
|
||
.replaceAll('\\"','\"')
|
||
.replaceAll('\\v','\v')
|
||
//.replaceAll("\\\\",'\\')
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取字符串的长度,中文算两个字符
|
||
* @param {*} s
|
||
* @returns
|
||
*/
|
||
function getStringWidth(s){
|
||
let str = String(s)
|
||
var realLength = 0, len = str.length, charCode = -1;
|
||
for (var i = 0; i < len; i++) {
|
||
charCode = str.charCodeAt(i);
|
||
if (charCode >= 0 && charCode <= 128) realLength += 1;
|
||
else realLength += 2;
|
||
}
|
||
return realLength;
|
||
}
|
||
|
||
function objectStringify(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)=>{
|
||
const isLastItem = index ===node.length-1
|
||
let item = value
|
||
if(Array.isArray(value) || isPlainObject(value)){
|
||
item = nodeToString(value, level,isLastItem)
|
||
}else if(typeof(value)==="string"){
|
||
item = `"${escape(value)}"`
|
||
}else if(typeof(value)==="number"){
|
||
item = value.toString()
|
||
}else if(typeof(value)==="boolean"){
|
||
item = value.toString()
|
||
}
|
||
// 如果最后一项
|
||
if(!isLastItem){
|
||
item = item+","
|
||
}else{
|
||
item = item+"\n"
|
||
}
|
||
results.push(item)
|
||
})
|
||
endChar =" ".repeat((level-1) * indent) + "]"
|
||
return beginChar + results.map(item=>{
|
||
return `${" ".repeat(level * indent)}${item}`
|
||
}).join("\n") + endChar
|
||
}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(escape(key)),alignIndent)
|
||
let item = [`${indentSpace}"${escape(key)}"`,value]
|
||
if(Array.isArray(value) || isPlainObject(value)){
|
||
item[1] = nodeToString(value, level,isLastItem)
|
||
}else if(typeof(value)==="string"){
|
||
item[1] = `"${escape(value)}"`
|
||
}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) + "}"
|
||
return beginChar + results.map(item=>{
|
||
if(alignKey){
|
||
return `${item[0]}${" ".repeat(alignIndent-getStringWidth(item[0].trim())+2)}: ${item[1]}`
|
||
}else{
|
||
return `${item[0]}: ${item[1]}`
|
||
}
|
||
}).join("\n") + endChar
|
||
}
|
||
|
||
}
|
||
return nodeToString(obj,0,true)
|
||
}
|
||
module.exports = {
|
||
objectStringify,
|
||
escape,
|
||
escape2,
|
||
unescape
|
||
}
|
||
|