国际化vue-i18n之i18next-scanner自动化(vue3配置)

1,774 阅读1分钟

1、安装node包

npm install vue-i18n -S //安装8.x版本是为了兼容vue的2.x版本

npm install i18next-scanner -D // 开发依赖

npm install crc -S // 中文通过crc32转码获得唯一的key, 也避免中文作为索引导致性能不佳和索取不准确问题

image.png

2、根目录新建 i18next-scaner.config.js 文件

const fs = require('fs')
const { crc32 } = require('crc')

const systemLanguage = {
  zh: 'zh-cn',
  en: 'en'
}
// 读取已经存在在en.json文件的词条
const existJsonData = fs.readFileSync('./scan/i18n/en.json')
let existData = {}
try {
  existData = JSON.parse(existJsonData)
} catch {
  existData = {}
}

const keyList = Object.keys(existData)

module.exports = {
  input: [
    'src/**/*.{js,jsx,vue}',
    // 不需要扫描的文件加!
    '!src/i18n/**',
    '!src/locales/**',
    '!**/node_modules/**'
  ],
  output: './scan', // 输出目录
  options: {
    debug: true,
    func: false,
    trans: false,
    lngs: [systemLanguage.zh, systemLanguage.en],
    defaultLng: systemLanguage.zh,
    resource: {
      loadPath: './i18n/newJson/{{lng}}.json', // 输入路径 (手动新建目录)
      savePath: './i18n/newJson/{{lng}}.json', // 输出路径 (输出会根据输入路径内容自增, 不会覆盖已有的key)
      jsonIndent: 2,
      lineEnding: '\n'
    },
    removeUnusedKeys: true,
    nsSeparator: false, // namespace separator
    keySeparator: false, // key separator
    interpolation: {
      prefix: '{{',
      suffix: '}}'
    }
  },
  // 这里我们要实现将中文转换成crc格式, 通过crc格式key作为索引, 最终实现语言包的切换.
  transform: function customTransform(file, enc, done) {
    // 自己通过该函数来加工key或value
    const { parser } = this
    const content = fs.readFileSync(file.path, enc)
    parser.parseFuncFromString(content, { list: ['t'] }, (key, options) => {
      options.defaultValue = key
      const hashKey = `K${crc32(key).toString(16)}` // crc32转换格式
      // 如果词条不存在,则写入
      if (!keyList.includes(hashKey)) {
        parser.set(hashKey, options)
      }
    })
    done()
  }
}

3、根目录package.json配置扫描的运行命令

"scripts": {
    "serve": "vite",
    "dev": "vite --mode development",
    "build": "vite build",
    "preview": "vite preview",
    "prepare": "husky install",
    "prod": "vite --mode production",
    "scan": "i18next-scanner --config i18next-scaner.config.js"
  },

4、执行 npm run scan 扫描自动生成中英文档

image.png

5、这个文件根据业务自行存放, 我的放在src/locale/index.js

import { createI18n } from 'vue-i18n'
import zhCN from 'ant-design-vue/es/locale/zh_CN'
import enGB from 'ant-design-vue/es/locale/en_GB'
import localZh from '@scan/i18n/zh-cn.json' // 本地翻译中文文件
import localEn from '@scan/i18n/en.json' // 本地翻译英文文件
import crc32 from 'crc/crc32'
import tool from '@/utils/tool'
import sysConfig from '@/config/index'

export const messages = {
  'zh-cn': {
    lang: zhCN,
    ...localZh
  },
  'en': {
    lang: enGB,
    ...localEn
  }
}
const defaultLang = tool.data.get('APP_LANG') || sysConfig.LANG
const i18n = createI18n({
  legacy: false, // 是否允许在 Legacy API 模式下使用 Composition API
  locale: defaultLang,
  fallbackLocale: defaultLang,
  globalInjection: true,
  silentTranslationWarn: true, // 去除国际化警告
  messages
})

// --------这里是i18next-scanner新增的配置-------------
function lang(key, params) {
  const hashKey = `K${crc32(key).toString(16)}` // 将中文转换成crc32格式去匹配对应的json语言包
  let words = i18n.global.t(hashKey)
  if (words === hashKey) {
    words = key
  }

  // 配置传递参数的场景, 目前仅支持数组,可在此拓展
  if (Array.isArray(params)) {
    const reg = /\((\d)\)/g
    words = words.replace(reg, (a, b) => {
      return params[b]
    })
  }
  return words
}
// --------这里是i18next-scanner新增的配置-------------
window.$t = lang
export const _lang = lang
export default i18n

6、main.js里配置

import i18n, {_lang} from './locales'
const app = createApp(App)
app.use(i18n)
app.config.globalProperties.$t = _lang

7、页面中使用

image.png

8、语言切换

在App.vue中设置

<template>
  <a-config-provider :locale="locale">
    <router-view />
  </a-config-provider>
</template>

// import { useI18n } from 'vue-i18n'
// const { locale } = useI18n()
// locale.value = lang // 设置当前语言

import i18n from './locales'
import 'dayjs/locale/zh-cn'
  
const locale = ref(null);
locale.value = i18n.global.messages.value[lang].lang
i18n.global.locale.value = lang