前端国际化优化方案

国际化一般都是使用 i18n 这个库,在开发过程中需要对中英文两个文件内容中添加对应中英文文本,业务代码中使用可读性差。通过下面的脚本可以实现1.业务代码可以直接写$t(中文)。2.不需要创建中英文件。最后只需要将最后生成的内容放在自己项目对应的国际化文件夹下并正确引入就可以了,每次提测前跑一边脚本既可。可以省去很多体力工作,解放双手

使用到的node内置库和方法

内置库:fs(操作文件) path(获取路径) crypto(加密解密)
fs.readdir 读取目录
fs.readFile 读取指定文件的内容
fs.stat 检测是文件还是目录
fs.writeFile 写入文件
fs.rmdir:删除目录
fs.mkdir:创建目录
fs.unlink:删除文件

新增tool/readFlie.js(目的是扫描所有业务层代码中的$t()包含的内容,输出成文件)

// fs.readdir 读取目录
// fs.readFile 读取指定文件的内容
// fs.stat 检测是文件还是目录
// fs.writeFile 写入文件
// fs.rmdir:删除目录
// fs.mkdir:创建目录
// fs.unlink:删除文件
// xxx.isDirectory();//检查目录是否存在的方法
const fs = require('fs');
// 加载 path 模块
const path = require('path');

// 给导出的对象key做转化
const { encrypt } = require('./cryptolalia');

// 默认读取整个业务层文件的位置
const filename = path.resolve(__dirname, '../src');
// 默认需要编译的文件类型
const fileType = ["vue", "js"];
// 存放查找到的所有文件路径
const fileList = [];
// 存放所有文案的集合
const texts = [];




/**
 * 
 * 执行脚本
 * 
 */
createCatalogue();
/**
 * 
 * 创建i18n目录
 * 
 */
function createCatalogue() {
    const i18nPath = path.resolve(__dirname, '../src/i18n');
    try {
        //检查某个文件是否存在-不能拿到外面  因为开始没有这层目录statSync方法会抛异常
        const stat = fs.statSync(i18nPath);
        if (stat.isDirectory()) {
            const filePath = path.resolve(__dirname, '../src/i18n/zh.js');
            //如果可以执行到这里那么就表示存在了
            // 存在此文件夹就删除
            fs.unlink(filePath, (error) => {
                if (error) {
                    console.log('删除文件失败');
                }
                console.log('删除文件成功');
                // 写入的位置
                const outputFilePath = path.resolve(__dirname, '../src/i18n/zh.js');
                createFile(outputFilePath);
            });
        }
    } catch (e) {
        //捕获异常
        console.log('检查i18n文件夹不存在,创建新的文件夹');
        fs.mkdir(i18nPath, (err) => {
            if (err) {
                console.log('创建文件夹时出错')
            } else {
                console.log('创建文件成功')
                // 写入的位置
                const outputFilePath = path.resolve(__dirname, '../src/i18n/zh.js');
                createFile(outputFilePath);
            }
        });
    }
}
/**
 * 
 * @param {输出位置} outputPath 
 * 执行生成文件
 * 
 */

function createFile(outputPath) {
    readDirRecur(filename, function () {
        const LENGTH = fileList.length;
        fileList.forEach(file => {
            // //读取指定文件夹下的VUE和JS文件
            fs.readFile(file, "utf-8", function (err, data) {
                if (err) {
                    throw err;
                }
                // 匹配$t() 包裹的内容
                const rge = /\$t\(.*?\)/g
                const array = data.match(rge);
                // 需要把每个文件内扫描出符合规则的数组在合并到一个新数组中
                getText(LENGTH, array, function () {
                    const obj = {};
                    texts.forEach(item => {
                        const firstIndex = item.indexOf("(");
                        const lastIndex = item.lastIndexOf(")");
                        let text = item.substring(firstIndex + 2, lastIndex - 1);
                        // 这里需要使用加密算法包裹,这里没有使用的时候自己加
                        const h = encrypt(text);
                        obj[h] = text;
                    })
                    // 写入文件
                    fs.writeFile(outputPath, JSON.stringify(obj), function (err) {
                        if (err) {
                            return console.log('文件写入失败!' + err.message);
                        }
                        console.log("生成文件成功!");
                    });
                })
            })
        })
    })
}
/**
 * 
 * @param {*} fileList 
 * @param {*} array 
 * @param {*} callback 
 * 获取所有文案
 */
let count = 0;
function getText(LENGTH, array, callback) {
    count++;
    if (array) {
        array.forEach(txt => {
            texts.push(txt)
        })
    }
    if (LENGTH === count) {
        callback();
    }
}
/**
 * 
 * @param {目录位置} folder 
 * @param {所有文件查找成功的回调} callback 
 * 读取指定文件 路径,回调函数
 * 
 */
function readDirRecur(folder, callback) {
    // 读取目录
    fs.readdir(folder, function (err, files) {
        let count = 0;
        // 为了最后能执行回调函数成功获取到所有.*结尾的文件
        let checkEnd = function () {
            ++count == files.length && callback()
        }
        files.forEach(function (file) {
            const fullPath = path.resolve(__dirname, folder + '/' + file);
            // 检测是文件还是目录
            fs.stat(fullPath, function (err, stats) {
                if (stats.isDirectory()) {
                    return readDirRecur(fullPath, checkEnd);
                } else {
                    const suffix = file.split(".")[1];
                    if (fileType.includes(suffix)) {
                        fileList.push(fullPath)
                    }
                    checkEnd()
                }
            })
        })
        //为空时直接回调
        files.length === 0 && callback()
    })
}
新增tool/restore.js(目的是把生成好的中英文文件给转换成正常的中文key)

// fs.readdir 读取目录
// fs.readFile 读取指定文件的内容
// fs.stat 检测是文件还是目录
// fs.writeFile 写入文件
// fs.rmdir:删除目录
// fs.mkdir:创建目录
// fs.unlink:删除文件
// xxx.isDirectory();//检查目录是否存在的方法
const fs = require('fs');
// 加载 path 模块
const path = require('path');

// 给导出的对象key做转化
const { decrypt } = require('./cryptolalia');

/**
 * 
 * 执行读取脚本
 * 
 */
restoreFile();
/**
 * 
 * 读取文件内容并转化
 * 
 */
function restoreFile() {
    const filePath = path.resolve(__dirname, '../src/i18n');
    // 读取目录
    fs.readdir(filePath, (err, files) => {
        if (err) {
            console.log('读取目录出现错误,请先执行npm run translate');
        } else {
            console.log('读取目录成功');
            files.forEach(file => {
                const fullPath = path.resolve(__dirname, filePath + '/' + file);
                fs.readFile(fullPath, "utf-8", (err, data) => {
                    if (err) {
                        console.log('读取内容出现错误');
                    }
                    console.log('读取内容成功');
                    const object = JSON.parse(data);
                    const newObject = {};
                    for (const key in object) {
                        if (Object.hasOwnProperty.call(object, key)) {
                            const element = object[key];
                            const newKey = decrypt(key);
                            newObject[newKey] = element;
                        }
                    }
                    // 写入文件
                    fs.writeFile(fullPath, JSON.stringify(newObject), function (err) {
                        if (err) {
                            return console.log('文件写入失败!' + err.message);
                        }
                        console.log("更新文件成功!");
                    });
                })
            })
        }
    })
}
新增tool/cryptolalia.js(加密文件没什么好介绍的)
const CryptoJS = require("crypto");
// 加密
const encrypt = (content) => {
    const nameBuffer = Buffer.from(content); // 等同于 Buffer.from(name, "utf-8")
    const enecodedName = nameBuffer.toString("base64");
    return enecodedName
}
// 解密
const decrypt = (content) => {
    const decodeBuffer = Buffer.from(content, "base64"); // 第二个参数就不能省略了
    const decodedName = decodeBuffer.toString("utf-8");
    return decodedName
}

//暴露出去
module.exports = {
    encrypt,
    decrypt
};
脚本有了,使用方式如下

1.打开根目录下package.json,增加两行命令

"scripts": {
    "translate": "node ./tool/readFlie.js",
    "restore": "node ./tool/restore.js"
  },

2.执行npm run translate 生成文件
3.找到src/i18n/zh.js,复制里面的内容
4.将复制的内容在谷歌翻译中进行机翻
5.在src/i18n文件夹中新建en.js
6.将机翻内容粘贴进去并保存
7.执行npm run restore 还原内容

此案例中使用的是VUE框架别的框架暂时还没有尝试,有兴趣的同学可以尝试一些别的框架。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容