Nuix-i18n实现多语言切换


公司的项目现在经常要对接国外客户,所以我们的官网需要有个支持多语言切换的功能。一谈起多语言,第一反应就是 i18n,那我们就开始吧!

我们官网是基于 Nuxt 开发的,所以需要引入 @nuxtjs/i18n 依赖。

我们从创建 Nuxt 项目开始。

创建 Nuxt 项目

1
npx nuxi@latest init <project-name>

安装 i18n 依赖:

1
yarn add @nuxtjs/i18n

注意事项

我们用的是最新的Nuxt 3,感觉不太稳定。如果遇到某个包报以下错误:

1
2
3
node_modules\wide-align\align.js to a dynamic import() which is available in all CommonJS modules.

Instead change the require of index.js in node_modules\wide-align\align.js to a dynamic import() which is available in all CommonJS modules.

说明在 CommonJS 模块中使用了 ES Module 的 import 语法而导致的,这里指向的是 string-width 这个包。解决方案是,在 package.json 里添加以下配置:

1
2
3
4
5
"resolutions": {

"string-width": "4.2.3"

}

resolutions: 在项目中有多个包依赖于同一个模块,但这些包可能依赖于不同版本的该模块时,可能会遇到冲突或不兼容的问题。通过使用 resolutions,可以强制所有包使用指定的版本,从而解决这些冲突。

在 Yarn 中使用:这项功能主要用于 Yarn,因此确保使用的是 Yarn 而不是 npm。如果使用的是 Yarn,则可以在运行 yarn install 时,它会遵循 resolutions 字段的配置。记得把 lock 文件删掉再重新 yarn

创建语言文件

接下来,我们创建 lang 文件夹,并放置对应的语言文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// en.js

export default {
nav: {
home: "home",
ems: "ems",
cas: "cas",
factory: "factory",
about: "about",
},
home: {
test: "test"
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
zh.js

export default {
nav: {
home: "首页",
ems: "储能EMS",
cas: "碳核算CAS",
factory: "工厂数字化",
about: "关于我们",
},
home: {
test: "测试"
}
};

创建 i18n 配置

创建 i18n.config.js 文件:

1
2
3
export default defineI18nConfig(() => ({
legacy: false,
}));

配置 nuxt.config.ts

1
2
3
4
5
6
7
8
9
10
11
12
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
locale: 'zh',
locales: [
{ code: 'zh', name: '中文', file: 'zh.js' },
{ code: 'en', name: 'English', file: 'en.js' },
],
vueI18n: './i18n.config.js',
langDir: 'lang/',
}
});

创建中间件

我们还需要创建一个中间件,让页面跳转到 home,其实就是路由守卫。

创建 middleware 文件夹,文件名为 redirect.global.ts

1
2
3
4
5
export default defineNuxtRouteMiddleware((to, from) => {
if (to.fullPath === '/') {
return navigateTo('/home');
}
});

创建布局

app.vue 中加入:

1
<NuxtLayout></NuxtLayout>

然后创建 layouts 文件夹,并在其中创建 default.vue 默认文件:

1
2
3
4
5
<template>
<PageHeader />
<NuxtPage></NuxtPage>
</div>
</template>

开发导航组件

创建 components 文件夹,并在其中创建 PageHeader.vue

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<template>
<div class="hidden lg:flex header-menu-container items-center justify-end">
<div class="px-4 w-[100px] py-2 bg-[#409eff] cursor-pointer text-center rounded-md text-white" @click="setLocale('zh')">中文</div>
<div class="px-4 w-[100px] py-2 mx-6 bg-[#409eff] cursor-pointer text-center rounded-md text-white" @click="setLocale('en')">en</div>
<div class="flex">
<div
v-for="item in menus"
:key="item.link"
@mouseover="hoveredLink = item.link"
@mouseleave="hoveredLink = null"
class="box-border sm:text-lg md:text-xl lg:text-xl px-10 py-5 mx-5 text-[#0F2628] hover:text-black relative"
>
<NuxtLink :to="localePath(item.link)" @click="selectLink(item.link)">{{ $t(item.key) }}</NuxtLink>
<div
class="absolute left-0 right-0 bottom-0 h-[4px] bg-[#0F2628] transition-all duration-200 rounded"
:class="{ 'opacity-100': isActive(item.link) || hoveredLink === item.link, 'opacity-0': !(isActive(item.link) || hoveredLink === item.link) }"
></div>
</div>
</div>
</div>
</template>

<script setup>
import { ref, computed, watch } from 'vue';
import { useRoute } from 'vue-router';
const { locale, setLocale } = useI18n();
const localePath = useLocalePath();

const menus = ref([
{ link: "/home", title: "首页", key: "nav.home" },
{ link: "/ems", title: "储能EMS", key: "nav.ems" },
{ link: "/cas", title: "碳核算CAS", key: "nav.cas" },
{ link: "/factory", title: "工厂数字化", key: "nav.factory" },
{ link: "/about", title: "关于我们", key: "nav.about" },
]);

const hoveredLink = ref(null);
const selectedLink = ref(null);
const route = useRoute();

const selectLink = (link) => {
selectedLink.value = localePath(link);
};

const isActive = (link) => {
return selectedLink.value === link || route.path === localePath(link);
};

</script>

<style scoped>
.header-menu-container {
height: 140px;
margin-right: 30px;
}
</style>

创建页面

pages 文件夹里创建 homeems 文件:

1
2
3
4
5
home.vue 
{{ $t("home.description") }}

ems.vue
{{ $t("ems.description") }}

效果展示

ok,这样就搞定了。不但可以多语言切换,而且刷新浏览器的时候,也会记住对应menu状态和语言模式。

我的微信公众号: 梨的前端小屋


文章作者: 梨啊梨
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 梨啊梨 !
  目录