A Vite/Webpack plugin/loader that automatically transforms Chinese text in JS code into i18n translation functions based on AST.
一个基于AST自动转换JS代码中的中文为i18n翻译函数的 Vite/Webpack 插件/loader。
理论上支持任何JS框架,目前只测试了Vue2/3。
pnpm i -D @kapo/vite-plugin-i18n-transformer
// vite.config.ts
import Vue from "@vitejs/plugin-vue";
import VueJsx from "@vitejs/plugin-vue-jsx";
import I18nTransformer from "vite-plugin-i18n-transformer";
import {defineConfig} from 'vite'
import path from 'path'
export default defineConfig({
plugins: [
Vue(),
VueJsx(),
// 需要放在Vue和VueJsx插件之后
I18nTransformer({
include: ['**.js', '**.vue'], // 针对什么文件进行国际化
exclude: [ // 项目内不需要国际化的文件或文件夹
'src/locales/**',
'node_modules/**',
'src/store/modules/locale.ts'
],
i18nCallee: 'useI18n().t', // 调用国际化函数
dependency: { // 国际化函数依赖引入配置
name: 'useI18n', // 国际化函数依赖的名称
value: '@/hooks/web/useI18n', // 引入国际化函数的路径
objectPattern: true, // 引入的国际化函数依赖的形式。true为解构形式:import { name } from 'xxx'
preprocessing: 'const {t} = use18n()' // 这行代码将添加至import依赖之后,可以用来做一些处理
},
output: {
filename: 'zh-CN.json', // 生成中文配置的文件名
langList: ['en-US.json'], // 生成其他语言配置的文件名列表
path: path.resolve(process.cwd(), './public/lang'), // 生成文件的路径
}
}),
],
})
npm i -D @kapo/webpack-plugin-i18n-transformer
Webpack由于vue-loader版本不同,需要分版本处理。
以下是 vue-loader15.x
示例
// vue.config.js
const {I18nTransformerPlugin} = require('@kapo/webpack-plugin-i18n-transformer')
module.exports = {
...,
chainWebpack: (config) => {
const i18nOptions = {
include: ['**.js', '**.jsx', '**.vue'],
exclude: ['src/lang/**', 'node_modules/**', 'src/main.js',],
i18nCallee: 'i18n.default.t',
dependency: {
name: 'i18n',
path: '@/lang',
modules: 'CommonJS',
},
}
config.module
.rule('js')
.use('i18n-loader')
.loader('@kapo/webpack-plugin-i18n-transformer')
.options(i18nOptions)
.before('babel-loader')
.end()
.end()
.rule('vueTemplateRender')
.test(/\.vue$/)
.resourceQuery(/type=template/)
.enforce('post')
.use('i18n-loader')
.loader('@kapo/webpack-plugin-i18n-transformer')
.options(i18nOptions)
}
}
对于项目中可能存在并不想被翻译的项,在 vite/webpack 包中提供了 ignoreAutoI18n
函数,将不想翻译的条目使用该函数包裹起来即可。
为什么不采用类似 // eslint-disabled-next-line 形式?
export interface OutputSetting {
/**
* 生成中文配置的文件名
*/
filename: string;
/**
* 生成文件的路径
*/
path: string;
/**
* 生成其他语言配置的文件名列表
*/
langList: string[]
}
export interface DependencySetting {
/**
* 国际化函数依赖的名称
*/
name: string
/**
* 引入国际化函数的路径
*/
path: string
/**
* 引入的国际化函数依赖的形式
* 设置true为解构形式:import { name } from 'path'
*/
objectPattern: boolean
/**
* 这行代码将添加至import依赖之后,可以用来做一些处理
*/
preprocessing?: string
}
/**
* 收集到的国际化词条,key为通过keyRule生成的key,value为收集到的中文
*/
export type WordMap = Record<string, string>;
export interface GlobalSetting {
/**
* 生产文件配置
*/
output: OutputSetting;
/**
* 匹配需要翻译的正则表达式,默认/[\u4e00-\u9fa5]/
*/
localePattern: RegExp;
/**
* 自定义生成key的函数,参数为收集到的中文,中文在AST中对应的Node,收集到的所有词条配置
* 默认规则为通过中文生成一串md5作为key,重复的中文在md5后添加 -1,-2
*/
keyRule?: ((value: string, node: Node, map: WordMap) => string);
/**
* 针对哪些文件进行处理
*/
include?: string[];
/**
* 排除哪些文件
*/
exclude?: string[];
/**
* 调用国际化函数
*/
i18nCallee: string;
/**
* 国际化依赖配置
*/
dependency?: DependencySetting;
}