一个插件搞定网页多语言?请收下我的安利!

背景

我们公司近年来一直重视全球化。随着产品线不断扩展,为国际用户提供多语言支持变得尤为重要。然而,多且庞大的代码库和仓库规模给开发团队带来了很大的挑战,使用传统方式去做国际化,耗费的人力资源成本是巨大的。

经过深入研究各种技术方案,发现如果设计得当,插件有可能自动化识别代码中的可翻译字符串、生成翻译文件并同步不同语言 -- 一个搞定项目国际化的插件就此诞生。下面请看我娓娓道来~

注:目前,该插件稳定版已经在公司的研发协同平台中接入,得到各部门同事的认可,可放心使用。

插件解决什么技术问题

当前常用技术的不足

传统多语言本地化面临几个主要挑战:

1、开发人员需要手动添加本地化代码,这既耗时又容易出错或者遗漏;

2、所有文本需要人工翻译。随着产品国际化程度提高,这类手动工作效率日渐低下;

3、面对已经开发完成的项目,这时候想要再次接入国际化,需要全局去查找需要国际化的文本,且容易遗漏;

4、项目新成员的接入,容易导致国际化相关代码参差不齐,文本重复定义等。

国际化插件的优势

1、自动识别所有需要进行本地化的文本,根据文本的上下文自动调用api进行机器翻译;

2、翻译结果会生成对应的语言包en/index.js以及对应的机翻文件index.json,用户可传入自己的json文件对译文进行覆盖(针对不满足机翻结果的情况);

3、配置简单,对源码无破坏性;

4、提供了支持自定义译文的类似 $t 方法。

其他优势

1、支持多种文件格式翻译,如.vue、.js、.ts等文件;

2、利用翻译接口提高效率,通过特殊分隔符拼接文字,限制为5k字符发起一次请求,减少接口调用次数;

3、开发过程中实现实时检测和翻译,无需重启项目即可完成国际化;

4、多语言支持,根据需要配置单独文件夹实现超100+种语言翻译;

5、简单配置,仅1分钟完成依赖安装和配置;

6、支持忽略指定文本不进行翻译

与传统国际化方式的区别

插件运行原理示意图

演示

这个我们自己内部系统集成了国际化之后的效果,这里的国际化语言存储在cookie当中,前后端都可以通过cookie获取到当前的语言 可以看到,设置为英文模式后,对应中文均实现了语言切换。其中前端部分由插件实现

假设我说前端的文本替换5分钟就能搞定,你敢相信吗? 且往下看👇

1、安装国际化插件

sql 复制代码
yarn add webpack-i18n-plugin-plus @babel/plugin-transform-typescript -D

2、在webpack配置中添加插件配置,与此同时,在项目根目录下创建 文件夹 i18n ,用来作为国际化的输出目录

对应代码:

javascript 复制代码
const WebpackI18nPlugin = require('webpack-i18n-plugin-plus')
const i18nConfig = {
  i18nDir: path.resolve(__dirname, './i18n'), // 国际化配置输出目录
  translation: {
      en: {}
  },
  translatePort: 7890 // 🪜的对应端口
}
javascript 复制代码
plugins: [
    new WebpackI18nPlugin(i18nConfig)
]

webpack.dev.conf.js

3、启动项目(记得打开你的梯子🪜 ):启动项目之后,可以看到文件夹 i18n 下生成了对应的语言包文件

4、最后一步:在项目下创建 i18n.js , 添加以下代码,并在项目入口文件 main.js 中的第一行引入该文件。 i18n.js 5、至此,项目中的中文代码已经可以自由切换语言了~ 下面展示仅前端打开英文模式的效果(我在代码中将语言包设置为英文的语言包,cookie使用中文的键值):

文档教程

安装

bash 复制代码
npm install webpack-i18n-plugin-plus @babel/plugin-transform-typescript -D

sql 复制代码
yarn add webpack-i18n-plugin-plus @babel/plugin-transform-typescript -D

webpack plugins 配置

基础使用

javascript 复制代码
// webpack.config.js
const WebpackI18nPlugin = require('webpack-i18n-plugin-plus')
const i18nConfig = {
    i18nDir: path.resolve(__dirname, './i18n'), // 国际化配置输出目录,默认值:path.resolve(__dirname, './i18n')
    translation: {
        en: {}
    },
    translatePort: 7890 // 默认值7890,由于翻译调用的是谷歌翻译api,需要提供科学上网的端口,否则大概率翻译失败
}
plugins: [
  ...
  new WebpackI18nPlugin(i18nConfig)
  ...
]

注:如果出现编译死循环(未出现则忽略,下同),需要在webpack配置中添加配置忽略对输出目录的热更新

javascript 复制代码
config.devServer.watchOptions = {
    ignored: /i18n/
}

vue.config.js 配置

基础使用

javascript 复制代码
const WebpackI18nPlugin = require('webpack-i18n-plugin-plus')
const i18nConfig = {
    i18nDir: path.resolve(__dirname, './i18n'), // 国际化配置输出目录
    translation: {
        en: {}
    },
    translatePort: 7890 // 默认值7890,由于翻译调用的是谷歌翻译api,需要提供科学上网的端口,否则大概率翻译失败
}
module.exports = {
    configureWebpack: {
        plugins: [
            new WebpackI18nPlugin(i18nConfig)
        ]
    }
}

仅通过以上的简单配置 =》 项目--启动!!

你将会看到项目根目录下多出来一个 i18n 文件夹,里面文件夹下对应的 index.js 就是生成的语言包;

进阶用法

javascript 复制代码
const WebpackI18nPlugin = require('webpack-i18n-plugin-plus')
const i18nConfig = {
    i18nDir: path.resolve(__dirname, './i18n'), // 国际化配置输出目录
    translation: {
        en: {
          userJson: path.resolve(__dirname, './i18n/en/user.json') // 若对翻译结果不满意,可在对应目录下添加user.json文件,格式参照生成的index.json,最终翻译生成的语言包会优先取userJson中的text值,下面给出例子;
          formatter: value => value+ ' ' // 译文格式化,此处将翻译结果的末尾都加上了空格,在页面展示会更加友好
        }
    },
    translatePort: 7890 // 默认值7890,由于翻译调用的是谷歌翻译api,需要提供科学上网的端口,否则大概率翻译失败
}
module.exports = {
    configureWebpack: {
        plugins: [
            new WebpackI18nPlugin(i18nConfig)
        ]
    }
}

i18n/en/index.json

json 复制代码
[
  {
        "key": "lkxqg0",
        "cn": "开发",
        "text": "Dev"
    },
    {
        "key": "mf1f37",
        "cn": "测试",
        "text": "Test"
    }
]

i18n/en/user.json

json 复制代码
[
  {
        "key": "lkxqg0",
        "cn": "开发",
        "text": "Develop"
    }
]

根据上面的配置(配置了userJson,formatter),最终生成的语言包中,[开发] 会被翻译为 [Develop ];[测试]会被翻译为[Test ]。

使用方法|切换语言

项目启动后会在对应的语言包文件夹下生成 index.js 文件,这个文件就是对应语言的语言包

需要确保语言包最先被加载并注入

**最佳实践:**在项目目录下创建 i18n.js

javascript 复制代码
// i18n.js
import en from '../i18n/en/index.js'
import zh_CN from '../i18n/zh_CN/index.js'
const langMap = {
  'en': en,
  'zhcn': zh_CN
}
const lang = localStorage.getItem('lang') || 'en'
window.$i8n.locale(langMap[lang]) // 注意是$i8n,不是$i18n
// other code

main.js 中的 第一行 将上面的js文件引入

javascript 复制代码
// main.js
import './i18n.js'

如果需要切换语言我们只需要修改 localStorage中对应语言的值,并调用浏览器刷新即可

javascript 复制代码
window.location.reload()

命名空间(可跳过)

如果项目不是单独部署(作为插件/组件被其他项目引入(AMD模式));为避免语言包冲突,需要定义命名空间。

在使用上面,仅需要完成两个步骤:

  1. 在webpack配置中加入命名空间的key值:

    javascript 复制代码
    const i18nConfig = {
        i18nDir: path.resolve(__dirname, './i18n'), // 国际化配置输出目录
        translation: {
            en: {}
        },
        nameSpace: 'vueProject1'
    }
  2. 在注入语言包时,传入命名空间的key值(需与步骤1的key值保持一致)

    javascript 复制代码
    const langMap = {
      'en': en_US,
      'zhcn': zh_CN
    }
    const lang = localStorage.getItem('lang') || 'en'
    window.$i8n.locale(langMap[lang], 'vueProject1')

最终生成的语言包就会挂载在对应的命名空间上

配置参数

参数 说明 类型 默认值
i18nDir 国际化配置输出目录 string path.resolve(__dirname, './i18n')
translation 语言配置,每个key值对应一种语言,支持100+语种;具体见下 translation object
nameSpace 命名空间 string
isSync 是否同步执行 string true
translatePort 代理端口(科学上网的端口);用于调用翻译api number|string 7890
tsOptions ts文件配置选项,详见 配置项 object

translation[key]: object

key值对应的语言详见ISO-639

  • object:
javascript 复制代码
{
  userJSON: string|array, // 自定义翻译
  formatter: function(value) {} // value: 翻译文本,可对文本做格式化
}

eg:

javascript 复制代码
translation: {
  en: {
      userJson: path.resolve(__dirname, './i18n/en/user.json') // 若对翻译结果不满意,可在对应目录下添加user.json文件,格式参照生成的index.json,最终翻译生成的语言包会优先取userJson中的text值,下面给出例子;
      formatter: (value) => {
          return value + " "
        } // 译文格式化,此处将翻译结果的末尾都加上了空格,在页面展示会更加友好
    }, // 英语
  'zh-TW': {}, // 繁体
  ja: {} // 日语
  ...
}

方法

自定义翻译

window.$i8n 当项目中有相同的中文需要翻译成不同的单词时,提供的自定义翻译解决方法 (🐶注意是**$i8n**)

  • 类型: (key: string, val: string, nameSpace: string) => string
  • 参数:
    • key: 关键字对应的key值
    • val: 若语言包中未能匹配到对应的key值,则返回val
    • nameSpace: 命名空间,若项目中使用了命名空间,则该参数需要传递
  • 示例:

假设项目中出现两处 "需求" , 需要分别翻译为demand、DEMAND;则其中有一个可以借助插件进行自动翻译,另一个需要自己定义需要翻译的内容,我们以DEMAND为例:

javascript 复制代码
import en from '../i18n/en/index.js'
import zh_CN from '../i18n/zh_CN/index.js'
// 在项目下定义对应的语言JSON,如
const customLangMap = {
  'en': {
        '需求': 'DEMAND'
  },
  'zhcn': {
        '需求': '需求'
  }
}
// 在注入语言包时,将对应的语言包进行解构
const langMap = {
  'en': en_US,
  'zhcn': zh_CN
}
const lang = localStorage.getItem('lang') || 'en'
window.$i8n.locale({...langMap[lang], ...customLangMap[lang]})

// 在需要自定义翻译的地方使用$i18n进行包裹
$i8n('需求', '需求', nameSpace) // 对应语言下:需求/DEMAND

绕过翻译

主动绕过

window.$$i8n 当项目中有不需要进行国际化的中文时,可以通过该方法进行跳过(🐶注意是**$$i8n**)

  • 类型: (value: string) => value: string
  • 参数:
    • value:原始文案
  • 示例:
javascript 复制代码
$$i8n('需求') // 需求
被动绕过

插件针对以下方法绕过了扫描,也就是被以下方法包裹的内容,将不会被扫描到

$i8n$$i8nconsole.log$t

备注

  1. 编译后,可以关注 终端 输出日志,查看翻译情况;
  2. 本插件集成了谷歌翻译,翻译结果准确性有限,也可能调用失败(科学上网端口号默认指向7890,可通过配置port进行修改)。
  3. 如果对翻译结果不满意或者未生成对应的翻译结果,可前往 i18n/ 下对应语言包的 index.xlsx对翻译结果进行修改。
  4. 若自动翻译提示当前ip调用次数太多,可通过修改代理端口对应的节点来重置。
  5. 最终生成的译文以对应目录下的 index.js为准,你也可以在控制台通过 console.dir($i8n)查看相关的属性和方法。

结语

朋友们,如果您觉得这款插件对您有帮助,欢迎访问我的 GitHub 项目页:

github.com/xu-c去de/web...

您可以在该地址找到插件的详细文档、使用示例以及源代码。我会持续追加新特性和改进已有功能,让插件变得更加优质。 不知是否有兴趣帮我们点个 Star 支持一下呢?你们的每一个 Star 都是提升工程质量的动力源泉~~

如果您有任何问题或建议,也欢迎在 Issue 进行交流。相信只有源源不断的反馈才能帮助本插件不断优化,造福开发社区。

相关推荐
天天进步201523 分钟前
Vue+Springboot用Websocket实现协同编辑
vue.js·spring boot·websocket
疯狂的沙粒43 分钟前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员1 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
想自律的露西西★2 小时前
用el-scrollbar实现滚动条,拖动滚动条可以滚动,但是通过鼠标滑轮却无效
前端·javascript·css·vue.js·elementui·前端框架·html5
白墨阳2 小时前
vue3:瀑布流
前端·javascript·vue.js
程序媛-徐师姐4 小时前
Java 基于SpringBoot+vue框架的老年医疗保健网站
java·vue.js·spring boot·老年医疗保健·老年 医疗保健
余道各努力,千里自同风4 小时前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave4 小时前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟4 小时前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾5 小时前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js