老项目一键国际化i18n方案,vue、react通用

前言

最近公司要把几个没有做过国际化的老项目接入国际化,其中有react也有vue的项目。看了好几篇写国际化的文章,效果我都觉得不太好,什么“终极方案”,并没有很方便。于是自己写了一个。注:本文用到的eslint插件开发相关功能,eslint相关的api不过多细讲

方案

首先,这个方法react和vue可以通用。原理是:

  1. 通过自定义eslint插件,检查代码的时候自动收集中文,然后形成一个大的json
  2. 丢给chapgpt翻译,这样中英文的json都得到了
  3. 通过eslint的自动修复功能,将代码中的中文替换为i18n语法

效果

直接看测试用例吧

{
  code: `<span>测试</span>`,
  output: `<span>{t('es.test')}</span>`,
},
{
  code: `<span title="测试"></span>`,
  output: `<span title={t('es.test')}></span>`,
},
{
  code: `export const A = {b: '测试'}`,
  output: `export const A = {b: t('es.test')}`,
},

实现(以react为例)

初始化eslint插件

  1. 官网提供的Yeoman生成器快速创建插件项目eslint-plugin-i18n
  2. yo eslint:rule命令创建规则getChinese

中文收集

create(context) {
  const sourceCode = context.getSourceCode()
  return {
    Literal (node) {
      addCnData(node.value)
    },
    JSXText (node) {
      addCnData(node.value)
    },
    // 模板语法,去掉前后引号
    TemplateLiteral (node) {
      addCnData(sourceCode.getText(node).slice(1, -1))
    }
  }
}

react的中文收集比较简单,AST只需要捕获LiteralJSXTextTemplateLiteral这三种类型即可,然后用addCnData方法将收集到的中文字符保存起来

async function addCnData (value) {
  if (typeof value !== 'string') return
  // 删除多余换行和空格
  const val = value.replaceAll('\r', '').replaceAll('\n', '').trim()
  if (!val) return
  // 匹配中文
  if(/.*[\u4e00-\u9fa5]+.*$/.test(val)) {
    // 将中文追加写入文件
    const writeHandle = await fs.open('D:\yourpath\chinese.js', 'a')
    await writeHandle.appendFile(val + '---\n')
  }
}
  1. chinese.js中的中文整理成如下格式
module.exports = {
  "测试": "es.test"
}

中文替换成i18n语法

同样的方法创建新的规则:setChinese

create(context) {
  return {
    Literal (node) {
      // cnJson为上述chinese.js里的对象
      if (cnJson[node.value]) {
        context.report({
          node,
          loc: node.loc,
          messageId: `err1`,
          fix: fixer => {
            if (node.parent.type === 'JSXAttribute') {
              return fixer.replaceTextRange(node.range, `{t('es.test')}`)
            } else {
              return fixer.replaceTextRange(node.range, `t('es.test')`)
            }
          }
        })
      }
    },
    JSXText (node) {
      if (cnJson[node.value]) {
        context.report({
          node,
          loc: node.loc,
          messageId: `err2`,
          fix: fixer => {
            return fixer.replaceTextRange(node.range, `{t('es.test')}`)
          }
        })
      }
    }
  }
},

代码很简单,TemplateLiteral节点涉及i18n的变量,需要手动处理下,就不用自动化修复了。

使用

  1. 因为没有发布npm,用npm link命令本地调试
  2. 假设我们的插件名叫eslint-plugin-i18n,在你的eslint配置文件中加入
plugins: ['i18n'],
rules: {
  'i18n/getChinese': 2
}
  1. 执行eslint src --fix --ext .js,.jsx,收集中文并翻译
  2. 将rules替换为'i18n/setChinese': 2
  3. 重复执行eslint src --fix --ext .js,.jsx,只需等待片刻,你的代码就自动修改完成了

总结

vue的处理也是同理,只不过是把AST节点换一换。eslint的功能十分强大,在日常开发中好好利用下可以提升很多效率。当然我也尝试过直接用babel来改代码,但是babel重新generate的时候,会无法保持原来的代码格式(有知道的大佬可以指点下),所以最后还是选择了eslint来处理。

原文链接:https://juejin.cn/post/7341533476663312447 作者:Ref_Aimer

(0)
上一篇 2024年3月2日 下午4:16
下一篇 2024年3月2日 下午4:26

相关推荐

发表回复

登录后才能评论