vue项目国际化i18n的实现及思考

国际化是什么?

国际化对应的英文单词为 Internationalization,又称“i18n”:

  • i 为单词的【第一个】字母
  • 18 为【i 和 n 之间】字母的个数
  • n 为单词的【最后一个】字母

如果你的项目是vue,那么相信你在实现国际化功能时,也必不可少的会使用到“vue-i18n”这个库,接下来本文也是通过这个库搭配vue实现最基本的国际化功能。

一、集成vue-i18n

1、安装依赖

npm i vue-i18n -S

2、配置vue-i18n

  • 在src目录下创建i18n目录用于保存和语言切换相关的内容
  • 在i18n目录下创建lang目录用于保存不同语言的映射关系,如中文对应zh.js、英文对应en.js等
  • 在i18n目录下创建index.js作为默认导出,并在其中创建i18n对象
// index.js
import { createI18n } from 'vue-i18n'
import A_zh from './lang/A/zh'
import A_en from './lang/A/en'
const i18n = createI18n({
  legacy: false,
  locale: 'zh',  // 初始化配置语言
  messages:{
    zh: {
      aFile: A_zh
    },
    en: {
      aFile: A_en
    }
  },
  silentTranslationWarn: true  // 隐藏警告
})

export default i18n

3、主文件main.js注册i18n

import { createApp } from 'vue'
import i18n from './i18n'
import store from './store'
import App from './App.vue'

createApp(App)
    .use(store)
    .use(i18n)
    .mount('#app')

实际上在通过use(i18n)时,会调用i18n.install()方法,大概内容如下:

  • 通过app.provide(app.__VUE_I18N_SYMBOL__, i18n)将i18n对象提供给应用中的所有后代组件可通过inject注入
  • 通过app.config.globalProperties.xxx = xxx的方式为应用添加全局属性/方法,实际上是对Vue2中Vue.prototype使用方式的一种替代
    • 常见全局属性,如$i18n通过app.config.globalProperties.$i18n=i18n添加到全局
    • 常见全局方法,如$t,$rt,$d,$n,$tm通过Object.defineProperty(app.config.globalProperties, `$${method}`, desc)添加到全局
  • 通过apply(...)方法注册常用的全局指令和全局组件i18n等
  • 在根组件卸载时移除/释放i18n相关内容
const unmountApp = app.unmount
  app.unmount = () => {
  i18n.dispose()
  unmountApp()
}
  • 注册vue-devtools的相关插件

二、根据数据信息填充国际化内容

1、填充lang目录下文件映射关系

在lang/A/zh.js文件中:

export default {
  name:'年龄'
}

在lang/A/en.js文件中:

export default {
  name: 'name'
}

2、页面渲染

翻译处理可通过如下方式处理:

  • 使用$t(...)方法
  • 使用v-t指令
  • 使用<i18n-t></i18n-t>组件

这里选择第一种,因为它更灵活,能使用到的范围也更广,指令和组件形式限定在了template中:

<template>
    <div>{{$t('aFile.name')}}</div>
</template>

基于以上简单的例子,已经能够实现了国际化切换功能。

三、思考

1、转换翻译文件类型(.js转.json)

上述的翻译文件是.js文件,因此,为了能够让其能够被其他文件导入,我们不得不在文件中使用export default或export将对应文件内容向外导出,但其实我们可以将.js文件转换为.json文件直接使用,避免新增一个国际化语言文件就需要手动导入一次翻译文件的问题。

在src/index.js文件中:

// index.js
import { createI18n } from 'vue-i18n'

// 动态读取.json文件中定义的国际化语言字段
const getMessage = () => {
  const messages = {}
  const modules = import.meta.globaEager('./lang/*')
  for(let key in modules){
    let langKey = key.replace(/\.\/lang\/(.+).json$/, (match, p1) => p1)
    messages[langKey] = modules[key].default
  }
  return messages
}

const i18n = createI18n({
  legacy: false,
  locale: 'zh',  // 初始化配置语言
  messages: getMessage()
})

export default i18n

2、考虑不同语言的样式

由于不同语言的表现形式不同,内容长度也不一致,因此在前端进行展示时,就必须要考虑到最终的显示问题,否则一旦切换语言环境那么一定会导致页面的布局展示出现问题,处理方式无非几种:

  • 允许文字内容换行展示,在文字发生换行时,要通过css设置按完整词换行;不允许换行的,就要控制固定宽度,超出部分打点展示,鼠标移入展示全部内容等
  • 单独为不同语言环境设置样式,具体还是得看展示需求,如需要考虑不同语言环境下文字的对齐方式、文字间距等
  • 针对难以处理的翻译内容,可以通过和业务沟通是否可以替换翻译内容、缩减文字长度等等

3、考虑后端接口语言环境变更

一个项目的国际化不可能都是前端来实现的,一些接口动态返回的内容也是需要后端去处理的,通常接口的请求头中会存储一个用于标识当前页面语言环境的字段,然后再决定返回给前端页面的具体内容。

基于前面处理的国际化切换功能,本身是会基于vue的响应式来切换翻译内容的,即不会刷新页面,因此在切换对应翻译内容后,同样需要修改后续接口请求头中的语言环境。

但这样还是有问题的,已经通过接口返回的数据内容,此时没有办法切换成对应的翻译内容,因此当前的国际化切换是基于页面的变动,但基于接口变动的部分还没重新请求获取新的内容,那怎么处理呢?

  • 前端切换语言环境后,重新刷新页面,再次调用接口获取新的内容
  • 后端在返回数据时,将对应的不同语言环境的翻译内容一起返回,由前端根据语言环境决定如何渲染
  • 将所有的翻译内容全部交由前端管理,一开始就初始化好各个语言环境对应的翻译内容

以上内容是基于国际化功能的一点思考,记录的只是自己在项目中遇到的点,并不一定适用所有项目。

posted @ 2023-02-06 14:30  阿彬~  阅读(2748)  评论(0编辑  收藏  举报