JS、Android、IOS 批量生成国际化字符串工具

概述

当我们在处理Android、IOS、Web 国际化的时候,通常会不停的更新多语言字符串,大量的多语言字符串替换,导致大量繁琐的重复问题,故迫切需要开发一个工具类,来动态生成多语言文件,接下来便讲解一下开发工具的思想.

效果展示

  • 国际化字符串 文本维护文件
    JS、Android、IOS 批量生成国际化字符串工具_第1张图片
  • 国际化多语言文件 (内容支持自定义)
    JS、Android、IOS 批量生成国际化字符串工具_第2张图片
    JS、Android、IOS 批量生成国际化字符串工具_第3张图片

问题分析

应该以那一种形式进行更好的解决多语言字符串大量更新的问题呢? 经过查找资料,发现了一种基于python的形式来处理多语言, 故我们参照twine传送门的思想,使用node.js编写对应的工具类

  • 首先定义一个文件来维护多国语言文本
// sum.txt
[yes]
		en = Yes
		es = Sí
		fr = Oui
		ja = はい
  • 根据当前多语言文本,来获取所有的key, 并获取所有key对应的语言,遍历所有的内容来创建多国语言的文件.

编写工具类

工具类地址 传送门

//引入对应的文件模块
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平台

  • node 当前文件名.js
    运行Android平台
  • node 当前文件名.js android
    运行iOS平台
  • node 当前文件名.js iOS

效果展示
JS、Android、IOS 批量生成国际化字符串工具_第4张图片
JS、Android、IOS 批量生成国际化字符串工具_第5张图片

工具类地址 传送门

//引入对应的文件模块
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, "&gt;");
        }
        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;
}

结束语

以上的解决方式,便为我们做国际化,提供了完美的解决方案.我们也可以根据自己的想法,作出不同的形式的多国语言字符串文件,因此需要我们多去实践,找到适合我们自己的工具类.

你可能感兴趣的:(html5,js,web,android,多语言国际化,批量制作)