Vue2实现国际化多语言切换(后端传递语言包)

345 阅读3分钟

Vue2+vue-i18n实现国际化

整个功能依赖于vue-i18n插件,通过 t()方法实现文本的国际化。系统会根据当前设置的t() 方法实现文本的国际化。系统会根据当前设置的 i18n.locale 来显示对应语言的文本内容。

首先安装插件

npm install vue-i18n@8.28.2

yarn add vue-i18n@8.28.2

在main.js中配置插件

import VueI18n from 'vue-i18n'
import { getLanguage } from './api/Language' 

Vue.use(VueI18n)
//默认中文
const savedLanguage = localStorage.getItem('language') || 'zh-CN';

const i18n = new VueI18n({
  locale: savedLanguage,
  messages: {} // 初始化为空对象
})

async function initAppLanguage() {
  const [err, { Result: res }] = await getLanguage(savedLanguage);
  if (!err && res) {
    const backendLang = JSON.parse(res).message;
    i18n.setLocaleMessage(savedLanguage, backendLang);
  }
}
initAppLanguage();

这里的getLanguage 是获取后端语言的接口方法

在全局配置了i18n以及网页启动获取语言包并且配置语言,本地不需要配置lang文件

创建语言切换组件

​编辑

 <a-dropdown :trigger="['click']" class="language-switch" style="padding-right: 15px;">
          <a class="ant-dropdown-link" @click="e => e.preventDefault()">
            {{ currentLanguageName || $t('切换语言') }} <a-icon type="global" />
          </a>
          <a-menu slot="overlay" @click="changeLanguage">
            <a-menu-item v-for="item in languageList" :key="item.Code">
              {{ item.Name }}
            </a-menu-item>
          </a-menu>
        </a-dropdown>

在模板中使用 a-dropdown 和 a-menu 组件创建下拉菜单,通过 v-for 遍历 languageList 生成语言选项,其中currentLanguageName 意味着currentLanguageName 通过计算属性从 languageList 中匹配当前选中的语言名称,$t()指的是vue-i18n的方法。

语言切换逻辑

async changeLanguage({ key }) {
  const [err, { Result: res }] = await getLanguage(key)
  if (!err && res) {
    // 直接使用后端返回的语言数据,不加载本地文件
    const backendLang = JSON.parse(res).message;
    this.$i18n.setLocaleMessage(key, backendLang);
    this.$i18n.locale = key;
    localStorage.setItem('language', key);
  }
}

该方法通过调用 getLanguage 接口获取对应语言的翻译数据,并更新i18n配置

- 调用后端接口获取指定语言的翻译数据
- 使用 this.i18n.setLocaleMessage更新i18n的语言消息\-设置this.i18n.setLocaleMessage 更新i18n的语言消息 \- 设置 this.i18n.locale 切换当前语言
- 将选中的语言代码存储到localStorage中,以便下次页面加载时恢复。

静态文本翻译

在切换语言后如何另其他的部分实现翻译呢

​编辑​编辑

静态文本

{{$t('示例')}}

其他场景(输入提示语)

:placeholder="$t('用户名')"

动态文本:

表头数据

:tab="$t(item.title)"

{{(userInfo.userCode)}}

data()中的配置我这里是翻译失败了,有大佬解决可以分享一下

data(){
    return [
        {
          title: "标题",
          dataIndex: "title",
          scopedSlots: { customRender: 'name' },
        },
         {
          title: "类型",
          width:150,
          dataIndex: "typeName",
        },
        {
          title: "接收时间",
          width:200,
          dataIndex: "receivedTime",
        },
      ];
}

在合理直接用$t()去包裹会无法识别,也可以尝试在当前页面引用i18n的插件去翻译

另一种场景

{{ parent.$t(props.name) }}

函数式组件声明为template functiona , 没有实例化的Vue对象 ,因此无法通过 this 访问组件实例
常规组件中使用的 this.$t() 在此处不可用,必须通过其他方式获取i18n实例

当用了functional来包裹了组件

<template functional>
  <!-- 组件内容 -->
</template>

- parent 是函数式组件的内置参数,指向 父组件的Vue实例
- 通过 parent.t()可以间接调用父组件的i18n翻译方法\-等价于在普通组件中使用this.t() 可以间接调用父组件的i18n翻译方法 \- 等价于在普通组件中使用 this.parent.$t()

为什么不直接使用$t

- 函数式组件没有 this 上下文,无法直接访问t方法\-模板中直接使用t方法 \- 模板中直接使用t会报错(找不到该方法)
- 必须显式通过 parent 访问父组件的i18n实例

选择前端不配置文件的原因

实现方式

传统静态翻译

本项目动态翻译

翻译数据位置

前端JSON文件

后端数据库

更新方式

需修改文件并重新部署

后端直接更新,前端无感刷新

加载时机

应用打包时加载

运行时动态加载

灵活性

低(需前端发版

高(可随时更新)