Vue3?接入?i18n?實(shí)現(xiàn)國際化多語言案例分析
1. 基本方法
在 Vue.js 3 中實(shí)現(xiàn)網(wǎng)頁的國際化多語言,最常用的包是 vue-i18n,通常我們會(huì)與 vue-i18n-routing 一起使用。
vue-i18n 負(fù)責(zé)根據(jù)當(dāng)前頁面的語言渲染文本占位符,例如:
<span>{{ t('Login') }}</span>當(dāng)語言設(shè)置為中文時(shí),會(huì)將 Login 渲染為“登錄”。
vue-i18n-routing 負(fù)責(zé)將頁面語言與 URL 綁定,例如:
https://githubstar.pro/zh-CN/repo
表示訪問中文版的 /repo 路徑。
將不同語言的網(wǎng)頁放在不同的 URL 下有助于 SEO,因?yàn)榭梢栽?nbsp;<head> 部分添加語言信息,增加不同語言被搜索引擎索引的概率。
Google 對于多語言 Vue 站點(diǎn)的爬取機(jī)制如下:
- 類似 Vue 站點(diǎn)的 JS 動(dòng)態(tài)頁面是可以被爬取的,不影響權(quán)重 (參見 Google SEO)。
- 與用戶首選語言匹配的頁面將優(yōu)先展示 (參見 Google SEO)。
2. 基礎(chǔ)實(shí)現(xiàn)
第一步,安裝一個(gè) Vite 下使用 <i18n> 標(biāo)簽的插件:unplugin-vue-i18n。
然后調(diào)整 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)),
},
},
});添加插件后,我們可以在組件內(nèi)使用 <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 作為當(dāng)前語言,編輯 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 會(huì)自動(dòng)生成所有支持語言的 routes:
/home= 中文/en/home= 英文
由于我們設(shè)置了 defaultLocale: 'zh-CN',默認(rèn)路徑為中文。
然后,我們需要將源代碼中涉及跳轉(zhuǎn)的部分,例如:
router.push({ name: 'home' });全部加上 localePath,表示是當(dāng)前語言的 URL 路徑下:
import { useLocalePath } from 'vue-i18n-routing';
const localePath = useLocalePath();
router.push(localePath({ name: 'home' }));這樣就完成了路徑綁定。
4. 自動(dòng)切換
有時(shí),我們希望沒有默認(rèn)語言,而是根據(jù)用戶的瀏覽器語言自動(dòng)選擇:
/zh-CN/home= 中文/en/home= 英文/home-> 重定向 (瀏覽器偏好中文) ->/zh-CN/home= 中文/home-> 重定向 (瀏覽器偏好英文) ->/en/home= 英文
這時(shí)我們需要定義一個(gè) 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 添加了一個(gè) LocalStorage 中的存儲(chǔ)項(xiàng)。
邏輯是:如果用戶手動(dòng)設(shè)定了語言(savedLang),則使用之;如果沒有,則使用系統(tǒng)偏好的第一個(gè)語言。這樣,我們只要取 lang 的值就可以得到最終的偏好語言是中文還是英文。
然后,我們需要定義一個(gè)路徑守衛(wèi),以自動(dòng)處理 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;
}這里需要注意三點(diǎn):
- 我們增加了一個(gè)新的空
locales,這樣請求才能到達(dá)router.beforeEach。 - 我們?nèi)サ袅?nbsp;
defaultLocale。 - 使用剛才定義的 store:
useLangStore()這行代碼必須放在router.beforeEach中,而不能放在模塊頂端,因?yàn)榧虞d模塊時(shí) Pinia 還沒有啟動(dòng)。
這樣,就實(shí)現(xiàn)了無語言路徑自動(dòng)跳轉(zhuǎn)到當(dāng)前偏好語言路徑。
5. 導(dǎo)航欄切換按鈕
然后,可以在導(dǎo)航欄增加一個(gè)按鈕,來手動(dòng)切換語言,例如:
<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 中存儲(chǔ)當(dāng)前手動(dòng)設(shè)定的語言,同時(shí)使用 switchLocalePath 來實(shí)現(xiàn)路徑和語言的切換。
6. SEO 和 Head Meta
同一內(nèi)容的不同語言版本應(yīng)該在 head 中進(jìn)行標(biāo)注,并指向所有其他替代頁面(參見 Google SEO)。這里我們可以在 App.vue 中用 useLocaleHead 和來自 @unhead/vue 包的 useHead 進(jìn)行設(shè)置:
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 || [])]),
});
});這樣就基本實(shí)現(xiàn)了一個(gè)多語言的國際化站點(diǎn)??赡茉谶M(jìn)行前端翻譯的同時(shí),后端也需要進(jìn)行翻譯,請期待下一期:Python Flask 后端如何接入 i18n 實(shí)現(xiàn)國際化多語言!
7. 案例分析
案例:GithubStar.Pro 的前端界面國際化多語言,是使用本文所述的方法實(shí)現(xiàn)的,各位可以看看效果。
也歡迎各位使用 GithubStar.Pro 互贊平臺(tái),提高您的開源項(xiàng)目知名度,收獲更多用戶。
到此這篇關(guān)于Vue3 如何接入 i18n 實(shí)現(xiàn)國際化多語言的文章就介紹到這了,更多相關(guān)Vue3 國際化多語言內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue項(xiàng)目el-upload?上傳文件及回顯照片和下載文件功能實(shí)現(xiàn)
本次需求是上傳多種固定格式的文件,且回顯的時(shí)候,圖片可以正常顯示,文件可以進(jìn)行下載,主要采用element的el-upload組件實(shí)現(xiàn),對Vue項(xiàng)目el-upload?上傳文件及回顯照片和下載文件功能實(shí)現(xiàn)感興趣的朋友跟隨小編一起看看吧2023-12-12
iview實(shí)現(xiàn)動(dòng)態(tài)表單和自定義驗(yàn)證時(shí)間段重疊
這篇文章主要介紹了iview實(shí)現(xiàn)動(dòng)態(tài)表單和自定義驗(yàn)證時(shí)間段重疊,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
vue之elementUi的el-select同時(shí)獲取value和label的三種方式
這篇文章主要介紹了vue之elementUi的el-select同時(shí)獲取value和label的三種方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
使用Vue.js和Flask來構(gòu)建一個(gè)單頁的App的示例
本篇文章主要介紹了使用Vue.js和Flask來構(gòu)建一個(gè)單頁的App的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03
vue中實(shí)現(xiàn)子組件相互切換且數(shù)據(jù)不丟失的策略詳解
項(xiàng)目為數(shù)據(jù)報(bào)表,但是一個(gè)父頁面中有很多的子頁面,而且子頁面中不是相互關(guān)聯(lián),但是數(shù)據(jù)又有聯(lián)系,所以本文給大家介紹了vue中如何實(shí)現(xiàn)子組件相互切換,而且數(shù)據(jù)不會(huì)丟失,并有詳細(xì)的代碼供大家參考,需要的朋友可以參考下2024-03-03
vue+echarts實(shí)現(xiàn)進(jìn)度條式柱狀圖
這篇文章主要為大家詳細(xì)介紹了vue+echarts實(shí)現(xiàn)進(jìn)度條式柱狀圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09

