当前位置: 首页 > 工具软件 > i18n-locales > 使用案例 >

Vue-i18n与Vuex-i18n等vue的国际化方案

东郭海阳
2023-12-01

Vue-i18n与Vuex-i18n等国际化方案

文档时间:2021-01-04
vue-i18nvuex-i18n两者皆为vue项目的国际化方案。

基础资料

vue-i18n

主要可参考此官网,掌握基础知识。
官网:http://kazupon.github.io/vue-i18n/zh/introduction.html
git:https://github.com/kazupon/vue-i18n

vuex-i18n

vuex-i18n是使用vuex作为存储的本地化插件,并非vue-i18n的升级版本,语法有一定的差异,不通用。
npm:https://www.npmjs.com/package/vuex-i18n
git:https://github.com/dkfbasel/vuex-i18n

基本概念

不论使用哪种方案国际化,自然都需要掌握以下基础的几点:初始化配置 语言环境信息 模板中使用 脚本中使用 修改语言环境
至于更复杂的功能可自行查阅相关文档。
以下例子主要基于vue-i18n讲解,实际使用时,vuex-i18n差别不大。

1.初始化配置

首先,需要安装和初始化i18n模块,安装比较简单,但是初始化就有多种方式了,可挑选适合自己项目的方式。

npm install vue-i18n --save

或者

yarn add vue-i18n

简易初始化官网原文

// 通过选项创建 VueI18n 实例
const i18n = new VueI18n({
  locale: 'en', // 设置地区
  messages, // 设置地区信息
})
// 通过 `i18n` 选项创建 Vue 实例
new Vue({ i18n }).$mount('#app')

通过插件方式初始化一

通过插件方式初始化,是较为推荐的方式,以下是例子一:
添加i18n.js文件

import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)

const i18n = new VueI18n({
      // 使用localStorage存储语言状态是为了保证页面刷新之后还是保持原来选择的语言状态
    locale: localStorage.getItem('lang') || 'en', // 定义默认语言
    messages: {
        'zh': require('@/assets/languages/zh.json'),
        'en': require('@/assets/languages/en.json')
    }
})

export default i18n

在main.js中引入

import i18n from '@/plugins/i18n' // 导入vue-i18n
new Vue({
  router,
  i18n, // 此处需要挂载上i18n,不要忘记
  render: h => h(App)
}).$mount('#app')

2.语言环境信息/翻译信息

即不同语言环境情况下的相关信息,最终会被显示在网页上。
一般的简介/教程,里都是直接定义个对象,实际项目使用中一般都使用文档,可以是js文件,也可以是json文件
每种语言单独对应一个文档,如此可以将文件交给不同的翻译。
此外,还可以用数据库存储翻译信息,然后在页面初始化时通过API同步到最新翻译,最好存储在vuex中。
en.js文件

//en.js
export default {
	common:{
		btnOK:"OK",
		btnCancel:"Cancel",
	},
	message:{
		greeting:"hello, world",
		hello: '{msg} world',
		hello2: '{0} world',
	},
	banana: 'no bananas | {n} banana | {n} bananas',//复数
}

zh.js文件

//zh.js
export default {
	common:{
		btnOK:"确定",
		btnCancel:"取消",
	},
	message:{
		greeting:"你好,世界",
		hello: '{msg} 世界',
	},
}

3.模板中使用

vue代码主要分为模板和脚本两部分,如何在模板中使用将直接决定显示效果。
尤其注意的是可以善用其多种format的写法。

<span>{{$t('message.greeting')}}</span>

强制翻译成某种语言,忽略全局设置

<span>{{$t('message.greeting', 'en')}}</span>

格式化 $t()
具名格式化,除了最基本的写法,此种写法比较常见

<p>{{ $t('message.hello', { msg: 'hello' }) }}</p>

列表格式,以下两种写法都支持

<p>{{ $t('message.hello', ['hello']) }}</p>
<p>{{ $t('message.hello', {'0': 'hello'}) }}</p>

此时,你会注意到en.js中有hello2,但是zh.js中没有,如果此时配置了回退本地化,指向英文,则会显示英文,否则会报错。
参考:官网回退本地化

复数 $tc()
利用分隔符|定义语言信息,可得到多种灵活多变的结果

banana: 'no bananas | {n} banana | {n} bananas',//复数
<p>{{ $tc('banana', 0) }}</p>
<p>{{ $tc('banana', 1, { n: 1 }) }}</p>
<p>{{ $tc('banana', 1) }}</p>
<p>{{ $tc('banana', 10) }}</p>
<p>{{ $tc('banana', 100, { n: 'too many' }) }}</p>

输出,也就是页面展示如下:

<p>no bananas</p>
<p>1 banana</p>
<p>1 banana</p>
<p>10 bananas</p>
<p>too many bananas</p>

第二个参数choice,是具体数量,同时也是筛选用第几个语言信息的标志,可以自动替换原文中的{n}或者{count}。
第三个参数{n: 'too many'}, 是用来替换n的。
以上内容,可以用变量x来写,达到相似效果。

<p>{{ $tc('banana', x, { n: (x>99? 'too many':x) }) }}</p>

Vuei18n初始化的时候,可以传入函数pluralizationRules,作为复数的运算规则。
使得某个特殊的语言不再使用英文的复数逻辑。

new VueI18n({
	pluralizationRules: {
		'en': function(choice, choicesLength) {
			if (choice == 0) return 0;
			return choicesLength>choice ? choice : choicesLength-1;
		}
	}
})

choice是具体数量。
choicesLength是语言配置中,配置了多少项。
函数返回值代表使用语言配置中的第几项。

自定义指令本地化 v-t

<p v-t="'hello'"></p>

若vue的js脚本中data有定义如data: { path: 'hello' }
则也可以写成

<p v-t="path"></p>

这使得model层的数据可以与i18n对接起来。
$t与v-t的对比官网资料
在官方对比中,可以看到如下缺点描述:

$t 在每次重新渲染时都会被执行,因此它确实有翻译成本。

所以实际上直接使用$t界面的效率并不高,当然小项目可以忽略此问题。

特别说明:官网的时间本地化$d()和数字本地化$n()说的不是很清楚,可能产生和预期不符的结果,一般不推荐使用,如果硬要使用,请先查阅一定的相关文档再用。

4.脚本中使用

主要用于在脚本中,生成一些语言文案相关的参数,例如生成文案,然后弹出toast、alert、confirm等等。
其参数与模板中使用一致。

this.$t('message.greeting')
this.$i18n.translate('message.greeting')

检测某个key是否存在,(检测某个语言环境下的key是否存在)

this.$te('message.greeting2');
this.$te('message.greeting2', "jp");

5.修改语言环境

直接修改实例的locale值即可。

this.$i18n.locale = "en";

或者像官网那样,设计一个select来手动挑选。官网例子
还可以考虑将值保存在cookielocalStorage里面,推荐localStorage,然后每次初始化语言系统的时候,先获取localStorage中的值。
为了避免和别的项目冲突,存储的时候,最好带上你的app_name
因此,初始化的时候,你可以这么写:

const i18n = new VueI18n({
  locale: localStorage.getItem('app_name_lang') || 'en',
  messages 
})

保存的时候

localStorage.setItem('app_name_lang', 'en');
this.$i18n.locale = "en";

特殊功能

基础功能是那些你只要使用i18n基本就一定会用到的功能,而特殊功能,只在少数情况下会用到,因此只做简单举例。

1.链接翻译/镶嵌翻译

翻译信息如下:

      the_world: 'the world',
      dio: 'DIO:',
      linked: '@:message.dio @:message.the_world !!!!'

此时,message.linked会被翻译成DIO: the world !!!!
除了@:的写法之外,还可以写成@:(message.foo.bar.baz)这种形式,要注意的是,层级比较深的时候,一定要使用括号,这样会有一个清晰的结构。

2.单文件组件翻译

简单点说,先安装vue-i18n-loader

npm i --save-dev @kazupon/vue-i18n-loader

然后在单文件组件,添加<i18n>,增加翻译信息。
并且,你可以指定多个<i18n>,或者是指定某个特有文件为翻译,这些翻译信息会自动合并。

<i18n src="./common/locales.json"></i18n>
<i18n>
{
  "en": {
    "hello": "hello world!"
  },
  "ja": {
    "hello": "こんにちは、世界!"
  }
}
</i18n>
<template>
	<p>message: {{ $t('hello') }}</p>
</template>
<script>
</script>

注意,当使用webpack等工具时,需要配置,参考文档
loader: 'vue-loader',之后,添加如下所示的5行配置。

  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
      },
      {
        resourceQuery: /blockType=i18n/,
        type: 'javascript/auto',
        loader: '@kazupon/vue-i18n-loader'
      }
    ]
  },

此外,<i18n>函数式组件<template functional>中无效。

3.热重载

你可以监视本地化文件中的更改,并将更改热重载到应用程序中。

if (module.hot) {
  module.hot.accept(['./en', './ja'], function () {
    i18n.setLocaleMessage('en', require('./en').default)
    i18n.setLocaleMessage('ja', require('./ja').default)
    // 同样可以通过 $i18n 属性进行热更新
    // app.$i18n.setLocaleMessage('en', require('./en').default)
    // app.$i18n.setLocaleMessage('ja', require('./ja').default)
  })
}

app的模式下,也可以在下载了新的js文件之后,调用i18n.setLocaleMessage('en', require('./en').default)进行更新。

4.组件差值

当你需要在包含 HTML 标签或组件的语言环境信息进行本地化。
例如一段文字中,包含了超链接:

<p>I accept xxx <a href="/term">Terms of Service Agreement</a></p>

这部分比较复杂,建议有兴趣的直接看官网。官网资料

5.延迟加载

核心在于按需加载所需语言的文档。
启动的时候,获取本地语言环境,或者按照默认语言,加载资源,
当用户切换语言的时候,再加载对应语言的文件。
官网资料

常见方案

对比而言,使用vuex可以使得任意一处修改了语言类型,全局刷新语言显示,不需要额外写强制刷新的代码,且比使用cookie或者localStorage(需要手动获取当前值)更加方便。
vuex-i18n使用者相对较少,网上资料少,翻译规则也略有不同。
因此推荐方案2,自己将vuexvue-i18n结合起来,如若结合网络请求刷新语言配置效果更好。

1. vue+vue-i18n

算是入门方案,初学必看,以了解i18n的基础相关知识。
博客园 在vue中使用vue-i18n
cnblogs使用 vue-i18n 切换中英文

2. vuex+vue-i18n

cnblogs 使用vuex+vue-i18n方式国际化
csdn 国际化插件i18n和vuex的混合使用

3. vuex+vuex-i18n

csdn vue中vuex-i18n使用
cnblogs 使用 VUEX-i18n 开发国际化网站

vuex-i18n和vue-i18n语法对比

类型vue-i18nvuex-i18n
常规$t('key')$t('key')
指定语言$t('key', 'lang')$tlang('lang', 'key') this.$i18n.translateIn()
复数$tc("key", n1, {n:n1})$t('key', {count:n1}, n1)
复数文本分隔符竖线 |::: 或者使用数组
修改当前语言this.$i18n.locale='en'this.$i18n.set(locale)
增加某语言翻译setLocaleMessage(locale, message)this.$i18n.add(locale, translations)
替换某语言翻译同上this.$i18n.replace(locale, translations)
设置回退语言初始化时设置fallbackLocale: 'en'this.$i18n.fallback(locale)
判断某语言key是否存在$i18n.te( key, [locale])$i18n.keyExists(key, 'strict')
$i18n.keyExists(key, 'locale')
$i18n.keyExists(key, 'fallback')

其他方案

1.vuex+自定义i18n

如果项目比较小,只使用i18n的基础功能,可以利用vuex直接简单自定义i18n。
注意此方案仅支持最基本的i18n翻译,也就是直接从key / path映射到翻译信息,相当于$t(message.hello),且不支持格式化翻译。好处是相对于$t(),在文案没有变化的时候,是不会重新计算的,减少了计算量。
当然,你可以把自定义i18n和方案vuex + vue-i18n结合起来使用。

定义插件
创建src/utils/i18n/index.js文件,文件夹下放翻译文件en.js zh.js等等。
文件内容如下,将自动读取所有的语言配置文件。

let default_lang = "en";    //默认语言

//默认加载语言类型------初始化的时候就加载
let load_langs = {
  "en":true, 
  "zh":false,
}

const context = require.context(".", true, /\.js$/);
const lang_messages = {};//所有的语言配置
context.keys().forEach(key => {
  if (key === "./index.js") return;
  const filename = key.replace(/(.*?\/)(\w*)(\.js)/, "$2");//文件名
  if (load_langs[filename]){
    lang_messages[filename] = context(key).default;
  }
});

//i18n.js
var i18n = {};
i18n.install = function(Vue, options) {
  Vue.prototype.$i18n = {
    getLang(language) {
      return lang_messages[language] || lang_messages[default_lang];
    },
  };
};
export default i18n;

使用自定义i18n插件

import i18n from "@/utils/i18n";
Vue.use(i18n);

vuex模块定义基本语言函数

  state: {
    language: "en", //默认语言
    lang: null,
  },
  actions: {
    async ["setLanguage"]({ commit, state, dispatch }, config = {}) {
      commit("setLanguage", config.language);
      commit("setLang", config.i18n);
    },
  },
  mutations: {
    ["setLanguage"](state, data) {
      state.language = data;
      localStorage.setItem(l_key, data);
    },
    ["setLang"](state, i18n) {
      state.lang = i18n.getLang(state.language);
    },
  },
  getters: {
    ["getLang"](state){
      return state.lang;
    }
  },

任意地方设定语言
记得全局一定要初始化一次

this.$store.dispatch("setLanguage", {
   language: "en",
   i18n: this.$i18n,
 });

使用
利用vuex功能,映射到当前文件。

computed: {
    ...mapState({
	    lang_common: state => state.lang.lang_common,
    })
}

则js代码函数中可以直接使用

this.lang_common.tips;

在模板中使用

<p>{{lang_common.tips}}</p>

优点,利用了vuex的特性,执行效率高,不论多少文案,只要没变,不用重新计算。
原版的i18n每次都要运行函数$t()

缺点,除了最基本的映射功能,剩下什么都做不了。

将vue-i18n和自定义i18n融合

还在计划,稍后放上代码。

2.uniapp+vuex-i18n

uniapp是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)、快应用等多个平台。
官网:https://uniapp.dcloud.io/

uniapp与vuex-i18n多语言处理
$t()无法正确调用的时候,可以用this.$i18n.translate()来代替

3.vux+vuex-i18n

vux是一个基于WeUI和Vue(2.x)开发的移动端UI组件库,主要服务于微信页面。个人开发。vux官网:https://vux.li/
vux UI 项目国际化

 类似资料: