nodejs和Ext双端国际化

一、当前问题汇总

  • 前后端国际化在同一个文件中,web的和nodejs的没有分离,造成页面需要加载更多的字典,影响首次加载性能
  • 国际化文件存在大量的key冲突,重复定义
  • 国际化没有分模块管理,各个模块维护自己的国际化字段太困难了,非常容易冲突或者覆盖别人的代码
  • 前端源码的国际化文件暴露,点击查看源码

二、解决方法

1.前后端国际化分离

创建前后端国际化目录

在locales目录下创建web、server目录,分别存放前后端(nodejs)的国际化文件
nodejs当前采用的是npm 的i18n库,该函数会根据lang自动加载directory配置项下的‘lang’.json;因此需重新设置directory

T.configure({
    locales: ['en_US', 'zh_CN'],
    defaultLocale: APP.config.app.lang,
    directory: __dirname + '/locales/server', //此处将原来的locales目录修改为 '/locales/server'
    updateFiles: false
});

前端Ext采用的是自定义函数_(),该函数需要读取dict进行key的匹配进行国际化;需修改读取前端国际化json的目录为/locales/web

2.分模块管理

按照模块分json

根据现有的模块,自行创建模块目录,将自己的前后端国际化内容写在自定义json中

自定义json

注:名称可以随便写,文件格式为json格式,且大模块可以在细分小模块创建对应目录

3.key冲突

国际化key需按照模块名称作为顶级作用于,采用包命名的方式,采用驼峰命名

{
    "sysmng.serverList.grid.title":"服务器列表"
}

4.首页国际化内容直接暴露

国际化内容暴露,且首页家在性能下降

创建i18n文件,自定义Ajax方法获取后端的dict字典,将字典缓存在内存中

var request = new XMLHttpRequest();
var url = '/lang/get_i18n_dict?lang=' + APP.lang
request.open("get", url); 
request.send(null); 
request.onload = function () {
    if (request.status == 200) {
        var json = JSON.parse(request.responseText);
        APP.dict = json.dict;
        console.log("dict", json.dict);
    }
}
// i18n func
var _ = function (s) {
    if (APP.dict[s] != undefined) {
        return APP.dict[s];
    }
    return s;
};

// console.log(_('My title'));
// console.log(_('Login Successfully!'));
// console.log(_('Alarms'));

后端返回

router.get('/get_i18n_dict', async function(req, res, next) {
    // req.setLocale(req.query.lang);
     let dict = require(path.join(path.resolve(), '/locales/web', req.app.locals.lang + ".json"));
//    let dict=await readJsonFile(localsPath);
   console.log("dict", dict)
    res.json(200, {
        success: true,
        lang: req.app.locals.lang,
        // dict: req.getCatalog()
        dict:dict
    });  
});

5.国际化文件的管理

在modules目录下创建i18n模块,用来管理前后端的国际化文件
webapp在首次运行时会加载该模块,并负责合并各个模块的语言json,创建生成制定名称的json文件。
之后nodejs的i18n模块会负责管理后端国际化
前端页面在首次加载时会调用接口请求前端国际化文件数据

var fs = require('fs');
var path = require('path');
const localsArr = ['en_US', 'zh_CN'];
exports.createLocalesFile = function () {
    for(let lang of localsArr){
        let srcPath = path.resolve();
        let localesDir = path.join(srcPath, 'locales');
        let langWebPath = path.join(localesDir, 'web',lang);
        let langServerPath = path.join(localesDir, 'server', lang);
        createJsonFile(lang, langWebPath);
        createJsonFile(lang, langServerPath);
    }
    
}
function getJsonFilePath(localsPath) {
    let components = [];
    const files = fs.readdirSync(localsPath);
    files.forEach(function (item, index) {
        let itemPath = path.join(localsPath, item);
        let stat = fs.lstatSync(itemPath);
        if (stat.isDirectory()) {
            let subItemJsonFile = getJsonFilePath(itemPath);
            components.push.apply(components, subItemJsonFile);
        } else {
            if (item.substr(item.lastIndexOf(".") + 1) === "json") {
                components.push(itemPath);
            }
        }
    })
    
    return components;
}
async function createJsonFile(lang, langDir) {
    let jsonName=lang+".json";
    let jsonPath = path.join(langDir,"../", jsonName);
    let json = await readJsonFile(langDir);
    fs.writeFile(jsonPath, JSON.stringify(json), (err) => {
        if (err) throw err;
        console.log('文件已被保存');
    });
}
async function readJsonFile(localsPath) {
    let jsonPathArr = getJsonFilePath(localsPath);
    console.log("allARR", jsonPathArr);
    let allJson = {};
    for (let item of jsonPathArr) {
        let json = await readOneFile(item);
        Object.assign(allJson, json);
    }
    return allJson;

}
async function readOneFile(item) {
    return new Promise(function (resolve, reject) {
        fs.readFile(item, "utf8", function (err, data) {
            // console.log("json", data);
            let json = JSON.parse(data);
            // console.log("data", json);
            resolve(json);
        });
    });
}
根据语言种类生成对应的合并json文件

6.风险评估

原来的zh_CN.json的内容移植到了base.json文件中,各模块可以暂时不处理base.json中的内容,日后项目的新增国际化在模块国际化文件中编写,有时间可以将base.json中的属于本模块的国际化内容修改并移植到本模块国际化文件中

image.png

  • 该方案采用渐进式修改,兼容性强。
  • 可维护性强
  • 修改较少,各模块的工作量小
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容