Vue3 i18n 实践

在之前公司有做过国际化,但是并非自己搭建 ,如果你也没有相关经验且需要对日期插件支持,这篇文章应该对你有用。

实现方式

Vue3中实现国际化(i18n)大概分两种方式:

  1. 使用Vue I18n插件:Vue I18n是一个官方支持的国际化插件,它提供了一种在Vue应用程序中轻松管理多语言的方式。您可以通过安装并导入Vue I18n库,然后在Vue应用程序的入口文件中创建一个I18n实例,并使用各种功能和选项来定义翻译消息、语言环境和翻译规则等。
  2. 自立更生:官方给我们提供了两个不错的思路,一是使用全局变量的方式,二则是利用Provide/inject

由于自立更生式实现复杂翻译(变量翻译和某些需要在翻译文本里插入参数)过于繁琐,所以我选择使用Vue I18n插件。

搭建与使用

安装Vue I18n:首先,使用npmyarn安装Vue I18n

1
npm install vue-i18n

创建翻译文件:在你的项目中创建一个文件夹,用于存储不同语言的翻译文件。每个语言的翻译文件都是一个JSON对象。

1
2
3
4
5
src/ 
└── i18n/
├── index.ts
├── en.json
└── zh.json

配置Vue I18n:在你的Vue应用程序的入口文件中,导入Vue I18n并进行配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// index.ts
import { createI18n } from "vue-i18n";
import en from "./en.json";
import zh from "./zh-cn.json";

enum LANG_VALUE {
En = 'en',
Zh = 'zh-cn'
}

// 创建i18n实例
const i18n = createI18n({
legacy: false, // 使用Composition Api 需要设置为false
locale: getLanguage(), // 获取当前语言
messages: {
[LANG_VALUE.Zh]: zh,
[LANG_VALUE.En]: en
}
})

// 如果localStorage存在Language则从中获取当前语言环境,否则默认为中文模式
function getLanguage() {
if (typeof window === 'undefined') return;
const chooseLanguage = localStorage.getItem('Language');
if (chooseLanguage) return chooseLanguage;

const language = navigator.language.toLowerCase()
const locales = [LANG_VALUE.En, LANG_VALUE.Zh]
for (const locale of locales) {
if (language.indexOf(locale) > -1) {
return locale
}
}
return LANG_VALUE.Zh
}

export {
i18n,
LANG_VALUE,
getLanguage
}
1
2
3
4
// main.ts
import { i18n } from "./i18n";

app.use(i18n).mount("#app");

以上是创建i18n实例获取当前语言环境并引入到vue全局。

在组件中使用翻译文本:通过$t函数在组件模板中访问翻译文本,通过t函数翻译组件脚本中的文本。

1
2
3
4
5
6
<!-- 组件模板 -->
<template>
<div>
{{ $t('greeting') }}
</div>
</template>
1
2
3
4
5
6
7
// 组件脚本
import { i18n } from "../i8n";
const { t } = i18n.global;

onMounted(() => {
console.log(t('greeting'));
})

上面值得注意的是,在组件脚本中直接使用 $t 会提示”找不到 $t 声明”,这是由于 Compositon API 作用域导致的,这里选择获取 i18n 实例中的可访问属性 t 来达到与 $t 一样的效果。

问题一:控制台提示

1
You are running the esm-bundler build of vue-i18n. It is recommended to configure your bundler to explicitly replace feature flag globals with boolean literals to get proper tree-shaking in the final bundle.

如果遇到上述警告,则需要在webpack或Vite中添加配置:

1
2
3
4
5
define: {
__VUE_I18N_FULL_INSTALL__: true,
__VUE_I18N_LEGACY_API__: false, // 禁用 vue-i18n 旧式 API 支持,默认为true
__INTLIFY_PROD_DEVTOOLS__: false,
},

webpack 则需要配置 DefinePlugin

相关资料链接:
vue i18n issues
Reduce bundle size with feature build flags

问题二:日期国际化

当切换Language时,所使用的DayJSMomentJS不会切换到对应的语言。
对此在dayJS下面提过issues,仔细考虑发现这好像并不属于bug也不属于feature,于是只好自己封装。

DayJS为例,对dayjs对象进行封装:

1
2
3
4
5
export function i18nDayjs(date?: string | number | dayjs.Dayjs | Date | null | undefined): dayjs.Dayjs {
const i18nStore = useI18nStore(); // 获取当前语言环境
const _dayjs = date ? dayjs(date) : dayjs();
return computed(() => _dayjs.locale(i18nStore.language || 'zh-cn')).value;
}

上面 i18nDayjs 封装在”useFunction”内,利用computed动态计算存储在pinia的变量language,从而实现动态切换dayjs.locale,这样在切换language后,日期也会随之变化。

最后

以上就是关于Vue3中国际化的实践了,主要用来记录i18n的实现思路,以及遇到的坑。
上述代码只是片段,与之相关的commit: f60ea7af1fcb0c

$The\,End$