Vue3 如何接入 i18n 实现国际化多语言

1. 基本方法

在 Vue.js 3 中实现网页的国际化多语言,最常用的包是 vue-i18n,通常我们会与 vue-i18n-routing 一起使用。

vue-i18n 负责根据当前页面的语言渲染文本占位符,例如:

<span>{{ t('Login') }}</span>

当语言设置为中文时,会将 Login 渲染为“登录”。

vue-i18n-routing 负责将页面语言与 URL 绑定,例如:

https://githubstar.pro/zh-CN/repo

表示访问中文版的 /repo 路径。

将不同语言的网页放在不同的 URL 下有助于 SEO,因为可以在 <head> 部分添加语言信息,增加不同语言被搜索引擎索引的概率。

Google 对于多语言 Vue 站点的爬取机制如下:

  1. 类似 Vue 站点的 JS 动态页面是可以被爬取的,不影响权重 (参见 Google SEO)。
  2. 与用户首选语言匹配的页面将优先展示 (参见 Google SEO)。

2. 基础实现

第一步,安装一个 Vite 下使用 <i18n> 标签的插件:unplugin-vue-i18n

然后调整 vite.config.js

import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import VueDevTools from 'vite-plugin-vue-devtools';
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';export default defineConfig({plugins: [vue(),VueDevTools(),VueI18nPlugin({}),],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url)),},},
});

添加插件后,我们可以在组件内使用 <i18n> 块:

<script setup lang="ts">
import { useI18n } from 'vue-i18n';const { t, locale } = useI18n({ inheritLocale: true, useScope: 'local' });
</script><template><span>{{ t('Login') }}</span>
</template><i18n lang="yaml">
en:Login: 'Login to web'
zh-CN:Login: '登录'
</i18n>

这里我们定义了两种不同的语言。

3. 路径绑定

接下来,我们需要定义使用 URL 作为当前语言,编辑 router/index.ts

import { createRouter as _createRouter, type RouteLocationNormalized } from 'vue-i18n-routing';
import { createWebHistory } from 'vue-router';
import HomeView from '@/views/HomeView.vue';const locales = [{code: 'en',iso: 'en-US',name: 'English',},{code: 'zh-CN',iso: 'zh-CN',name: '中文',},
];export function createRouter(i18n: any) {const router = _createRouter(i18n, {version: 4,locales: locales,defaultLocale: 'zh-CN',history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/home',name: 'home',component: HomeView,},],});return router;
}

我们定义了支持的语言种类,并将原来的 routes 包装起来,vue-i18n-routing 会自动生成所有支持语言的 routes

  • /home = 中文
  • /en/home = 英文

由于我们设置了 defaultLocale: 'zh-CN',默认路径为中文。

然后,我们需要将源代码中涉及跳转的部分,例如:

router.push({ name: 'home' });

全部加上 localePath,表示是当前语言的 URL 路径下:

import { useLocalePath } from 'vue-i18n-routing';const localePath = useLocalePath();router.push(localePath({ name: 'home' }));

这样就完成了路径绑定。

4. 自动切换

有时,我们希望没有默认语言,而是根据用户的浏览器语言自动选择:

  • /zh-CN/home = 中文
  • /en/home = 英文
  • /home -> 重定向 (浏览器偏好中文) -> /zh-CN/home = 中文
  • /home -> 重定向 (浏览器偏好英文) -> /en/home = 英文

这时我们需要定义一个 store,这里使用 Pinia store,Vuex 同理。

import { usePreferredLanguages, useStorage } from '@vueuse/core';
import { defineStore } from 'pinia';export const useLangStore = defineStore('lang', {state: () => {const savedLang = useStorage<string | null>('lang', null, undefined);const systemLang = usePreferredLanguages();return { savedLang, systemLang };},getters: {lang: (state) => {const lang = state.savedLang || state.systemLang[0];if (lang.startsWith('zh')) {return 'zh-CN';} else {return 'en';}},},actions: {setLang(l?: string) {if (!l) {this.savedLang = null;} else {this.savedLang = l;}},}
});

这段代码使用了 VueUse 中的 usePreferredLanguages 来获得用户偏好的浏览器语言,并用 useStorage 添加了一个 LocalStorage 中的存储项。

逻辑是:如果用户手动设定了语言(savedLang),则使用之;如果没有,则使用系统偏好的第一个语言。这样,我们只要取 lang 的值就可以得到最终的偏好语言是中文还是英文。

然后,我们需要定义一个路径守卫,以自动处理 URL 中没有语言的情况。

import { createRouter as _createRouter, type RouteLocationNormalized } from 'vue-i18n-routing';
import { createWebHistory } from 'vue-router';
import HomeView from '@/views/HomeView.vue';const locales = [{code: 'en',iso: 'en-US',name: 'English',},{code: 'zh-CN',iso: 'zh-CN',name: '中文',},{code: '',iso: '',name: '',}
];export function createRouter(i18n: any) {const router = _createRouter(i18n, {version: 4,locales: locales,history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/home',name: 'home',component: HomeView,},],});router.beforeEach((to: RouteLocationNormalized, from: RouteLocationNormalized) => {const lang = useLangStore();const pathLocale = to.path.split('/')[1];if ((!pathLocale) || (!locales.some(locale => locale.code === pathLocale))) {return `/${lang.lang}${to.path}`;}});return router;
}

这里需要注意三点:

  1. 我们增加了一个新的空 locales,这样请求才能到达 router.beforeEach
  2. 我们去掉了 defaultLocale
  3. 使用刚才定义的 store:useLangStore() 这行代码必须放在 router.beforeEach 中,而不能放在模块顶端,因为加载模块时 Pinia 还没有启动。

这样,就实现了无语言路径自动跳转到当前偏好语言路径。

5. 导航栏切换按钮

然后,可以在导航栏增加一个按钮,来手动切换语言,例如:

<script setup lang="ts">
import { useLocalePath, useSwitchLocalePath } from 'vue-i18n-routing';
import { useLangStore } from '@/stores/lang';const lang = useLangStore();
const { t, locale } = useI18n({ inheritLocale: true, useScope: 'local' });
</script><template>
<div@click="lang.setLang('en');router.push(switchLocalePath('en'));menuShown = '';"class="py-2 px-2 gap-2 flex items-center cursor-pointer hover:bg-slate-400/10":class="{ 'text-sky-300': locale == 'en' }"role="option"tabindex="-1":aria-selected="locale == 'en'"
><IconEnglish class="w-5 h-5 text-slate-400 dark:text-slate-200" />English
</div>
<div@click="lang.setLang('zh-CN');router.push(switchLocalePath('zh-CN'));menuShown = '';"class="py-2 px-2 gap-2 flex items-center cursor-pointer hover:bg-slate-400/10":class="{ 'text-sky-300': locale == 'zh-CN' }"role="option"tabindex="-1":aria-selected="locale == 'zh-CN'"
><IconChinese class="w-5 h-5 text-slate-400 dark:text-slate-200" />中文
</div>
</template>

这里,我们在刚才定义的 store 中存储当前手动设定的语言,同时使用 switchLocalePath 来实现路径和语言的切换。

6. SEO 和 Head Meta

同一内容的不同语言版本应该在 head 中进行标注,并指向所有其他替代页面(参见 Google SEO)。这里我们可以在 App.vue 中用 useLocaleHead 和来自 @unhead/vue 包的 useHead 进行设置:

import { useLocaleHead } from 'vue-i18n-routing';
import { useHead } from '@unhead/vue';const i18nHead = useLocaleHead({ addSeoAttributes: true, defaultLocale: null, strategy: null });onMounted(() => {useHead({htmlAttrs: computed(() => ({lang: i18nHead.value.htmlAttrs!.lang,})),link: computed(() => [...(i18nHead.value.link || [])]),meta: computed(() => [...(i18nHead.value.meta || [])]),});
});

这样就基本实现了一个多语言的国际化站点。可能在进行前端翻译的同时,后端也需要进行翻译,请期待下一期:Python Flask 后端如何接入 i18n 实现国际化多语言!

6. 案例分析

案例:GithubStar.Pro 的前端界面国际化多语言,是使用本文所述的方法实现的,各位可以看看效果。

也欢迎各位使用 GithubStar.Pro 互赞平台,提高您的开源项目知名度,收获更多用户。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/740800.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【安全运营】企业钓鱼演练实践

一、 群智集锦 问:请教各位师傅个问题,你们多长时间做一次钓鱼演练?答:全员型的半年一次,小范围的一个季度一次;答:我们内部每月都有做钓鱼演练,主要针对新员工,钓鱼主题一般不改变,针对全员的时候会换一下套路;问:请教个问题,大家进行钓鱼演练统计是怎么统计展示…

植物大战僵尸 杂交版

下载地址:https://download.csdn.net/download/hello_hlqk/89525708?spm=1001.2101.3001.9500 植物大战僵尸杂交版是一款由B站UP主 @潜艇伟伟迷 基于原版植物大战僵尸魔改的塔防类游戏。这款游戏在保留原有游戏精髓的基础上,进行了大胆的创新和尝试。UP主将不同的植物进行了…

Modbus转Profibus模块连SmartPLC接汇川630伺服案例

Modbus转Profibus模块(XD-MDPB100)是一种通讯协议转换器,能够实现Modbus 协议与Profibus-DP协议的信息共享。汇川630伺服作为一种先进的运动控制设备,其平稳性和准确性获得了充分肯定。本文将详细分析怎么使用Profibus转Modbus模块(XD-MDPB100)连接SmartPLC以及配备汇川630…

6.20+rand()%10~7.8

集训、集训、集训忘了放假之前的事了 首先排除是因为点分治调破防了 (发现一写数据结构专题闲话就变月记了) 其实还有原因是每次写这东西到一半就会因为点睡眠就会不小心点成关机所以似了 换校区(放假) 说实话放的还挺久的 在衡水住的酒店,打了一下午崩铁 速成了一下超击破…

matlab中神经网络预测模型的调用

本章以一道多自变量的例题来表述如何用调用matlab的包进行神经网络预测 目录一、问题提出二、训练集,验证集和测试集三、使用神经网络进行训练1.导入数据2.选择训练方法四、结果解读1.性能图2.回归图3.训练方法比较4.保存结果五、进行预测 一、问题提出 如图所示,现在有401个…

常见的排序算法——堆排序

本文记述了堆排序的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。 ◆ 思想 J.W.J Williams 提出了堆排序的算法,该算法利用了二叉堆有序的性质,将排序的过程分为先构建堆再排序的两个阶段。 先构建堆。从当前待排序范围一半的位置开始向第一个位…

vulnhub - JIS-CTF

泡面机vulnhub - JIS-CTF 这个靶场一共有5个flag 信息收集 靶机ip:192.168.157.172 kali ip:192.168.157.161 nmap 192.168.157.0/24 nmap -sT --min-rate 10000 -p- 192.168.157.172 sudo nmap -sT -sV -sC -O -p22,80 192.168.157.172一眼看到robots.txt User-agent: * Dis…

暑假进度表

7.8 个人赛打的还可以,就是F题敲得太慢了,最后差十分钟做出来。 补了一个重要但是原来没注意到的一个知识点 \(01bfs\) ,做了四道相关题,将F题写进了双端队列的内容中,感觉非常不错的一题。

私有云盘-可道云-安装和使用和数据迁移

私有云盘是什么 随着云计算和移动办公大潮的到来,iPad、智能手机等家庭联网设备不断增多,以及搭载小容量SSD笔记本电脑的流行,能够跨平台分享的个人云服务需求不断增长;而今天的个人云服务也已经极大丰富,从2TB的百度网盘到商务人士中流行的Dropbox和Box个人云,不但免费,…

比赛获奖的武林秘籍:04 电子类比赛嵌入式开发快速必看的上手指南

本文主要介绍了电子类比赛中负责嵌入式开发同学的上手比赛的步骤、开发项目的流程和具体需要学习的内容,并结合自身比赛经历给出了相关建议。比赛获奖的武林秘籍:04 电子类比赛嵌入式开发快速必看的上手指南 摘要 本文主要介绍了电子类比赛中负责嵌入式开发同学的上手比赛的步…

线程饥饿问题——b2b - Thread starvation or clock leap detected (housekeeper delta=5h28m19s393ms972......

原因:在方法上配置了 @Async 注解进行异步执行,但是没有在主配置类上配置 @EnableAsync 启动异步执行。 修改前 修改后

SpringBoot项目启动,运行停留在标题处

详情: 原因:yml文件存在问题,比如:在切换生产环境和开发环境的配置文件时,yml名称写错,如下,图,此处多写了一个p。解决办法:修改为正确的配置文件,即可。