当我们在处理Android、IOS、Web 国际化的时候,通常会不停的更新多语言字符串,大量的多语言字符串替换,导致大量繁琐的重复问题,故迫切需要开发一个工具类,来动态生成多语言文件,接下来便讲解一下开发工具的思想.
应该以那一种形式进行更好的解决多语言字符串大量更新的问题呢? 经过查找资料,发现了一种基于python的形式来处理多语言, 故我们参照twine传送门的思想,使用node.js编写对应的工具类
// sum.txt
[yes]
en = Yes
es = Sí
fr = Oui
ja = はい
工具类地址 传送门
//引入对应的文件模块
const fs = require("fs");
const readline = require("readline");
//所有多语言文件名
const langFileName = ['de', 'en', 'es', 'fr', 'it', 'ja', 'ko', 'pt', 'ru', 'tr', 'vi', 'zh', 'zh-tw'];
//读取文件路径
const updateFilePath = "./sumJs.txt";
//定义key的格式
const keyStart = "[";
const keyEnd = "]";
const valueSplitStr = "=";
//定义所有key的数组
var keyArr = [];
var keyValueArr = [];
//逐行地读取文件流
const rl = readline.createInterface({
input: fs.createReadStream(updateFilePath)
});
rl.on('line', function (line) {
line = line.toString().trim();
const lineStartStr = line.slice(0, 1);
const lineEndStr = line.slice(-1);
if (lineStartStr === keyStart && lineEndStr === keyEnd) {
//获取所有的key
keyArr.push(line.substring(1, line.length - 1));
} else {
//获取所有key对应的多语言
if (line.indexOf(valueSplitStr) > -1) {
var valueArr = line.split(valueSplitStr);
var key = keyArr[keyArr.length - 1];
if (valueArr.length > 1) {
keyValueArr.push({
key: key,
lang: valueArr[0],
langValue: valueArr[1]
});
}
}
}
});
rl.on("close", function () {
//创建所有的多语言文件
langFileName.map(function (item) {
var itemTemp;
if ((item !== "zh" && item !== 'zh-tw')) {
itemTemp = "en";
} else if (item === "zh-tw") {
itemTemp = "tw";
} else {
itemTemp = "zh";
}
//多语言内容格式
var fileContentStart = "module.exports = {\n";
var fileContent = "";
var fileContentEnd = "};";
keyValueArr.map(function (keyValue) {
var lang = keyValue["lang"].toString().trim();
var key = keyValue["key"].toString().trim();
var langValue = keyValue["langValue"].toString().trim();
if (lang === itemTemp) {
fileContent += " " + key + ": " + "'" + langValue + "'" + "," + "\n";
}
})
;
fileContent = fileContentStart + fileContent + fileContentEnd;
//写入文件
fs.writeFile("./JavaScript/" + item + ".js", fileContent, function (err) {
if (err) {
console.log("write file has exception");
}
}
)
;
// console.log(`${fileContent}`)
})
;
console.log("write file success")
});
运行默认为 javaScript平台
工具类地址 传送门
//引入对应的文件模块
const fs = require("fs");
const readline = require("readline");
//所有多语言文件名
const langFileNameJS = ['de', 'en', 'es', 'fr', 'it', 'ja', 'ko', 'pt', 'ru', 'tr', 'vi', 'zh', 'zh-tw'];
const langFileNameAndroid = ["", 'de', 'en', 'es', 'es-rES', 'fr', 'it', 'ja', 'ko', 'pt', 'ru', 'tr', 'vi', 'zh-rCN', "zh-rHK", 'zh-rTW'];
const langFileNameIOS = ['de', 'en', 'es', 'fr', 'it', 'ja', 'ko', 'pt', 'ru', 'tr', 'vi', 'zh-Hans', 'zh-Hant'];
const targetPathJS = "./JavaScript/";
const targetPathAndroid = "./AndroidNew/";
const targetPathIOS = "./IOSNew/";
const currentEnvJS = "JavaScript";
const currentEnvAndroid = "Android";
const currentEnvIOS = "IOS";
//读取文件路径
const updateFilePath = "./sumJs.txt";
const updateFilePathAndroidAndIOS = "./sum.txt";
const currentEnv = getCurrentEnv();
var langFileNameTemp = langFileNameJS;
var updateFilePathTemp = updateFilePath;
var targetPathTemp = targetPathJS;
var fileContentEnd;
var fileContentStart;
//获取默认配置
getDefaultConfig();
//定义key的格式
const keyStart = "[";
const keyEnd = "]";
const valueSplitStr = "=";
//定义所有key的数组
var keyArr = [];
var keyValueArr = [];
var langArr = [];
//逐行地读取文件流
const rl = readline.createInterface({
input: fs.createReadStream(updateFilePathTemp)
});
rl.on('line', function (line) {
line = line.toString().trim();
const lineStartStr = line.slice(0, 1);
const lineEndStr = line.slice(-1);
if (lineStartStr === keyStart && lineEndStr === keyEnd) {
//获取所有的key
keyArr.push(line.substring(1, line.length - 1));
langArr = [];
} else {
//获取所有key对应的多语言
if (line.indexOf(valueSplitStr) > -1) {
var valueArr = line.split(valueSplitStr);
var key = keyArr[keyArr.length - 1];
if (valueArr.length > 1) {
langArr.push(line.substr(0, line.indexOf(valueSplitStr)).trim());
keyValueArr.push({
key: key,
lang: line.substr(0, line.indexOf(valueSplitStr)).trim(),
langValue: line.substr(line.indexOf(valueSplitStr) + 1),
langArr: langArr
});
}
}
}
});
rl.on("close", function () {
//目标路径
// console.log("currentEnv:,langFileNameTemp:, targetPathTemp:,fileContentStart:,fileContentEnd:,keyValueArr", currentEnv, langFileNameTemp, targetPathTemp, fileContentStart, fileContentEnd, keyValueArr);
//创建所有的多语言文件
langFileNameTemp.map(function (item) {
//多语言内容格式
var fileContent = "";
keyValueArr.map(function (keyValue) {
var lang = keyValue["lang"].toString().trim();
var key = keyValue["key"].toString().trim();
var langValue = keyValue["langValue"].toString().trim();
var langArr = keyValue["langArr"];
var itemTemp = getItemTemp(item, lang, langArr);
if (lang === itemTemp) {
fileContent += getFileContent(key, langValue);
}
});
fileContent = fileContentStart + fileContent + fileContentEnd;
mkFileDir(getFileAllName(item));
fs.open(getFileAllName(item), 'w+', function (err, fd) {
if (err) {
return console.error(err);
}
console.log("create or open file success");
//写入文件
fs.writeFile(getFileAllName(item), fileContent, function (err) {
if (err) {
console.log("write file has exception");
}
}
);
// console.log(`${fileContent}`)
});
})
;
console.log("write file success")
});
// en=Regain after %@ s
// zh-CN =%@s后重新获取
function getItemTemp(item, lang, langArr) {
var itemTemp = "";
if (currentEnv === currentEnvAndroid) {
if (item === "zh-rCN") {
itemTemp = "zh-CN";
} else if (langArr.indexOf(item) > -1 && item === lang) {
itemTemp = item;
} else if (langArr.indexOf(item) === -1) {
itemTemp = "en";
}
} else if (currentEnv === currentEnvIOS) {
if (item === "zh-Hans") {
itemTemp = "zh-CN";
} else if (langArr.indexOf(item) > -1 && item === lang) {
itemTemp = item;
} else if (langArr.indexOf(item) === -1) {
itemTemp = "en";
}
} else {
if ((item !== "zh" && item !== "zh-tw")) {
itemTemp = "en";
} else {
itemTemp = "zh";
}
}
return itemTemp;
}
function mkFileDir(filepath) {
const dirCache = {};
const arr = filepath.split('/');
var dir = arr[0];
for (var i = 1; i < arr.length; i++) {
if (!dirCache[dir] && !fs.existsSync(dir)) {
dirCache[dir] = true;
fs.mkdirSync(dir);
}
dir = dir + '/' + arr[i];
}
}
function getFileContent(key, value) {
var fileContent = "";
if (currentEnv === currentEnvAndroid) {
var valueTemp = "";
if (value.indexOf("%@") > -1) {
var valueArr = value.split("%@");
if (valueArr.length > 2) {
valueArr.map(function (item, index) {
valueTemp += item + (index === valueArr.length - 1 ? "" : "%" + (index + 1) + "$s")
});
} else {
valueTemp = value.toString().replace(/%@/g, "%s")
}
value = valueTemp;
}
if (value.indexOf('@') > -1) {
value = value.toString().replace(/@/g, "\\@");
}
if (value.indexOf('<') > -1) {
value = value.toString().replace(/, "<");
}
if (value.indexOf('<u') > -1) {
value = value.toString().replace(/<u/g, ");
}
if (value.indexOf('</u') > -1) {
value = value.toString().replace(/<\/u/g, ");
}
if (value.indexOf('->') > -1) {
value = value.toString().replace(/->/g, ">");
}
if (value.indexOf("'" > -1)) {
value = value.toString().replace(/'/g, "\\'");
}
if (value.indexOf('"') > -1) {
value = value.toString().replace(/"/g, '\\"');
}
if (value.indexOf(' `') > -1) {
value = value.toString().replace(/ `/g, "\\u0020");
value = value.toString().replace(/`/g, "");
}
if (value.indexOf('` ') > -1) {
value = value.toString().replace(/` /g, "\\u0020");
value = value.toString().replace(/`/g, "");
}
fileContent = "\t" + "+ '"' + key + '"' + ">" + value + "\n";
} else if (currentEnv === currentEnvIOS) {
if (value.indexOf('"') > -1) {
value = value.toString().replace(/"/g, '\\"');
}
if (value.indexOf('`') > -1) {
value = value.toString().replace(/`/g, '');
}
fileContent = '"' + key + '"' + " = " + '"' + value + '"' + ";\n\n";
} else {
fileContent = " " + key + ": " + "'" + value + "'" + "," + "\n";
}
return fileContent;
}
function getFileAllName(item) {
var fileName = "";
if (currentEnv === currentEnvAndroid) {
fileName = targetPathTemp + (item === "" ? "values" : "values-") + item + "/" + "strings.xml";
} else if (currentEnv === currentEnvIOS) {
fileName = targetPathTemp + item + ".lproj/" + "Localizable.strings";
} else {
fileName = targetPathTemp + item + ".js";
}
return fileName;
}
function getDefaultConfig() {
if (currentEnv === currentEnvAndroid) {
langFileNameTemp = langFileNameAndroid;
targetPathTemp = targetPathAndroid;
updateFilePathTemp = updateFilePathAndroidAndIOS;
fileContentStart = "\n" + "\n" ;
fileContentEnd = "";
} else if (currentEnv === currentEnvIOS) {
langFileNameTemp = langFileNameIOS;
targetPathTemp = targetPathIOS;
updateFilePathTemp = updateFilePathAndroidAndIOS;
fileContentStart = "\n";
fileContentEnd = "\n";
} else {
langFileNameTemp = langFileNameJS;
targetPathTemp = targetPathJS;
updateFilePathTemp = updateFilePath;
fileContentStart = "module.exports = {\n";
fileContentEnd = "};";
}
}
function getCurrentEnv() {
var arguments = process.argv.splice(2);
var currentEnvTemp = currentEnvJS;
if (arguments.length > 0) {
var tempPath = arguments[0].toString().toLowerCase();
if (tempPath === "android") {
currentEnvTemp = currentEnvAndroid;
} else if (tempPath === "ios") {
currentEnvTemp = currentEnvIOS;
}
}
return currentEnvTemp;
}
以上的解决方式,便为我们做国际化,提供了完美的解决方案.我们也可以根据自己的想法,作出不同的形式的多国语言字符串文件,因此需要我们多去实践,找到适合我们自己的工具类.