从零开始改造前端国际化

2,977 阅读3分钟

背景

笔者所属团队是一个很大的PC端系统,我们部门负责这一部分也有10个前端代码库,整体的前端架构采用微前端,一个代码库是主应用,其余9个前端代码库是根据业务拆分出来的子应用,因为页面非常多,而且要适配多语言。所以将后端国际化配置存储在后端。

常规前端国际化

常规的前端国际化就是讲message放到本地的的某个文件夹例如locales 然后在某个时机上调用后端的国际化接口,然后代码看起来是这样的

image.png

此时有一个同事准备接另一个同事的内容,此时这个新同事心里肯定有一万个为什么,这个page1.btnText 是个啥啊,我们是否可以不看页面在代码里面就知道这个page1.btnText代表什么呢,此处思考一下,大家是不是都有类似的疑问. 接下来笔者将一步步的带大家解决这些问题

首先先搭建后端服务器,并且暴露一个获取国际化接口

因为公司代码不能拷贝出来,所以此处使用nodejs + express模拟后端,新建server.js

此处国际化语言和国际化数据使用json文件模拟,这里就不做修改的操作了,笔者偷个懒


const express = require("express");
const fs = require("fs");
const path = require("path");
const app = express();
const port = 3000;

//设置跨域访问
app.all("*", function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});

// 获取国际化数据,返回以pageId作为key的国际化语言,实际情况有同时获取多个页面国际化的场景
app.get("/i18n/pageId/:pageId", function (req, res) {
  const { pageId } = req.params;
  // 实际上是从cookie中获取的语言,此处就直接写死
  const lang = "zh";
  // 实际上是从数据库获取的,但是此时就直接使用本地文件模拟从数据库获取
  res.send({
    [pageId]: JSON.parse(
      fs.readFileSync(
        path.resolve(process.cwd(), "i18nData", `${pageId}-${lang}.json`)
      )
    ),
  });
});
app.listen(port, () => {
  console.log(`i18n server listening on port ${port}`);
});


改造国际化第一步————调用后端国际化接口改造

既然要改造,那么分析一下我们做的第一件事是什么呢,肯定是先把本地写死在locals文件夹的内容通过接口获取先,那么第一个问题来了,在什么时候去获取呢?接口需要的pageId参数在哪里保存呢

首先pageId参数肯定是不会变化的,所以我们第一时间想到的就是在路由文件给页面的文件加一个meta 属性,然后将国际化所用到的参数都放到其中

image.png

然后在路由的钩子函数中调用

image.png

此时我们的第一步将本地国际化接入后端已经改造完成,我们也可以适当的在获取国际化数据的时候将数据放到storage,毕竟这些数据不是经常变更。

改造国际化第二步——————如何让前端页面的编码不看页面的前提下知道是什么

首先我们已知的是国际化的内容不会经常变化,那我们是不是可以将后端返回的国际化缓存下来放到项目的国际化下面呢,然后看一下是否有插件能显示编码?

经过笔者的不断的使用搜索引擎,最终发现了一个vscode插件Vue i18n ,装上之后看了下文档,发现对于$t('page1.btnText') 这种国际化,只需要在locales文件夹下面新建一个 page1.json 然后其中一个属性叫做 btnText,此时就可以在编辑器里面看到这个 page1.btnText是什么了

image.png

改造国际化第三步————本地开发不想调用接口

我们实际上本地开发的时候如果时刻去请求服务器,无疑是会慢很多,由于json文件我们很容易就得到,所以我们做出一点优化,本地开发的时候直接拿本地的内容不去获取后端 在 locales文件下 zh文件夹 新建index.js

const moduleFiles = require.context(".", false, /\.json$/);
export default moduleFiles.keys().reduce((prev, cur) => {
  // cur是 ./page1.json 这样,所以简单的替换 ./ 和.json 就得到了pageId
  prev[cur.replace("./", "").replace(".json", "")] = moduleFiles(cur);
  return prev;
}, {});

同时改造router

router.beforeEach(async (to, from, next) => {
  if(to.meta && to.meta.pageId){
    var  i18nData = {}
    // 开发环境直接取本地json
    if(process.env.NODE_ENV==="development"){
      i18nData = require('@/locales/zh').default
    }else{
      i18nData = await getI18nData(to.meta.pageId)
    }
    i18n.mergeLocaleMessage(i18n.locale,i18nData)
    next()
  }else{
    next()
  }
})

到此项目的国际化就改造完毕了

源码地址

源码地址都已放在github github.com/vincentchen…