國際化 (i18n)
本文件詳細介紹如何在項目中使用和配置國際化功能,包括語言包管理、在 Vue 和 TypeScript 文件中的使用方法、語言切換、以及如何添加新語言等。
配置說明
1. 環境變數配置
在 .env
文件中設置預設語言:
bash
# .env.dev / .env.prod / .env.test
VITE_DEFAULT_LANG=zhTW
目前支持的語言代碼:
zhTW
: 正體中文zhCN
: 簡體中文enUS
: 美式英文
2. 語言包檔案位置
語言包檔案位於 locales/
目錄下:
locales/
├── zhTW.json # 正體中文
├── zhCN.json # 簡體中文
└── enUS.json # 美式英文
3. 核心設定檔
src/modules/i18n.ts
: i18n 實例配置src/utils/i18n.ts
: 工具函數和 Naive UI 語言配置src/store/model/language/index.ts
: 語言狀態管理src/utils/tools/defaultLang.ts
: 預設語言獲取邏輯
語言包結構
語言包採用嵌套的 JSON 結構,按功能模組組織:
json
{
"common": {
"confirm": "確認",
"cancel": "取消",
"save": "保存"
},
"userCenter": {
"updateEmail": "更新信箱",
"updateMobile": "更新手機號碼"
},
"language": {
"zhCN": "簡體中文",
"zhTW": "正體中文",
"enUS": "美式英文",
"confirmToSwitchLanguage": "確定要切換語言嗎?"
}
}
在 Vue 文件中使用
1. 在template中使用
vue
<script setup lang="ts">
// 無需額外導入,$t 已全局註冊
</script>
<template>
<div>
<!-- 直接使用 $t 函數 -->
<h1>{{ $t('common.title') }}</h1>
<!-- 在屬性中使用 -->
<n-button :placeholder="$t('common.inputPlaceholder')">
{{ $t('common.submit') }}
</n-button>
</div>
</template>
2. 在script中中使用
vue
<script setup lang="ts">
function handleSubmit() {
// 顯示成功消息
window.$message.success($t('common.saveSuccess'))
// 顯示確認對話框
window.$dialog.warning({
title: $t('common.warn'),
content: $t('common.deleteConfirm')
})
}
</script>
3. 動態語言切換範例
vue
<script setup lang="ts">
import { useLanguageStore } from '@/store/model/language'
const languageStore = useLanguageStore()
</script>
<template>
<n-popselect
:value="languageStore.current"
:options="languageStore.list"
@update:value="languageStore.setAppLang"
>
<CommonWrapper>
<icon-park-outline-translate />
</CommonWrapper>
</n-popselect>
</template>
在 TypeScript 文件中使用
typescript
import { $t } from '@/utils'
// 在函數中使用
export function validateEmail(email: string) {
if (!email) {
return $t('userCenter.inputEmail')
}
return true
}
語言切換
1. 使用語言切換組件
項目提供了 LangsSwitch
組件,可以直接使用:
vue
<template>
<LangsSwitch />
</template>
2. 編程式切換
typescript
import { useLanguageStore } from '@/store/model/language'
// 直接設置語言(不顯示確認對話框)
import { setLocale } from '@/utils'
const languageStore = useLanguageStore()
// 切換語言(會顯示確認對話框)
languageStore.setAppLang('enUS')
setLocale('enUS')
local.set('languageCurrent', 'enUS')
3. 語言切換流程
- 用戶選擇新語言
- 顯示確認對話框
- 確認後更新語言設定
- 更新本地儲存
- 重新載入頁面以應用新語言
設置預設語言
1. 環境變數設置
在 .env
文件中設置:
bash
VITE_DEFAULT_LANG=zhCN
2. 瀏覽器語言檢測
系統會自動檢測瀏覽器語言,如果瀏覽器語言在支持的語言列表中,則使用瀏覽器語言:
typescript
// src/utils/tools/defaultLang.ts
export function defaultLang(): Language {
const { VITE_DEFAULT_LANG } = import.meta.env
const browserLang = navigator.language.replace(/-/g, '')
if (Object.keys(language).includes(browserLang)) {
return browserLang as Language
}
return VITE_DEFAULT_LANG
}
3. 語言優先度
- 本地儲存中的
languageCurrent
- 瀏覽器語言(如果在支持列表中)
- 環境變數
VITE_DEFAULT_LANG
創建新語言
1. 添加語言類型定義
在 src/modules/i18n.ts
中添加新語言類型:
typescript
export type Language = 'enUS' | 'zhTW' | 'zhCN' | 'jaJP' // 添加日語
export const language = {
enUS,
zhTW,
zhCN,
jaJP, // 添加日語導入
}
2. 創建語言包文件
創建 locales/jaJP.json
文件:
json
{
"common": {
"confirm": "確認",
"cancel": "キャンセル",
"save": "保存"
},
"language": {
"jaJP": "日本語",
"confirmToSwitchLanguage": "言語を切り替えますか?"
}
}
3. 更新 i18n 配置
在 src/modules/i18n.ts
中導入新語言包:
typescript
import jaJP from '../../locales/jaJP.json'
export const language = {
enUS,
zhTW,
zhCN,
jaJP, // 添加新語言
}
4. 更新 Naive UI 語言配置
在 src/utils/i18n.ts
中添加 Naive UI 語言配置:
typescript
import { dateJaJP, jaJP as naiveJaJP } from 'naive-ui'
export const naiveI18nOptions: Record<string, { locale: NLocale | null, dateLocale: NDateLocale | null }> = {
// ... 現有配置
jaJP: {
locale: naiveJaJP,
dateLocale: dateJaJP,
},
}
5. 更新環境變數類型
在 src/typings/env.d.ts
中更新類型定義:
typescript
interface ImportMetaEnv {
readonly VITE_DEFAULT_LANG: 'zhCN' | 'zhTW' | 'enUS' | 'jaJP'
}
6. 添加語言顯示名稱
在所有語言包的 language
部分添加新語言:
json
// zhCN.json, zhTW.json, enUS.json
{
"language": {
"jaJP": "日語"
// 或 "jaJP": "日語", "jaJP": "Japanese"
}
}
7. 測試新語言
- 更新環境變數
VITE_DEFAULT_LANG=jaJP
- 重啟開發伺服器
- 檢查語言切換功能
- 驗證所有文本是否正確顯示
常見問題與避免踩坑
1. 語言包鍵值缺失
問題: 控制台出現 "Missing key" 警告
解決方案:
- 確保所有語言包都有相同的鍵結構
- 使用
missingWarn: true
配置來發現缺失的鍵 - 定期檢查語言包的一致性
2. 語言切換後頁面不更新
問題: 切換語言後部分文本沒有更新
解決方案:
- 確保使用
$t()
函數而不是寫死文本 - 檢查計算屬性是否正確響應語言變化
- 語言切換後會重新載入頁面,確保狀態正確重設
3. 類型安全問題
問題: TypeScript 類型檢查失敗
解決方案:
- 更新
Language
類型定義 - 確保環境變數類型正確
- 使用類型斷言時要謹慎
typescript
// 正確的類型使用
const currentLang = local.get('languageCurrent') as Language || defaultLang()
4. 語言包文件過大
問題: 語言包文件過大影響載入性能
解決方案:
- 按功能模組拆分語言包
- 使用動態導入載入語言包
- 考慮使用 CDN 載入語言包
5. 嵌套對象訪問
問題: 訪問深層嵌套的翻譯鍵
解決方案:
- 使用點號分隔的鍵路徑
- 避免過深的嵌套結構
- 考慮扁平化語言包結構
typescript
// 正確的方式
$t('userCenter.personalInfo.nickname')
// 避免過深嵌套
$t('userCenter.personalInfo.details.contact.mobile.placeholder')
6. 動態鍵值
問題: 需要根據變數動態生成翻譯鍵
解決方案:
- 使用模板字串
- 確保鍵值存在
- 提供預設值
typescript
// 動態鍵值範例
function getFieldLabel(fieldName: string) {
const key = `userCenter.${fieldName}Label`
return $t(key) !== key ? $t(key) : fieldName
}
7. 數字和日期格式化
問題: 不同語言的數字和日期格式
解決方案:
- 使用 Naive UI 的在地化配置
- 配置正確的
dateLocale
- 考慮使用
Intl
API 進行格式化
8. 語言包維護
最佳實踐:
- 定期檢查語言包一致性
- 使用工具驗證鍵值完整性
- 建立語言包更新流程
- 保持語言包結構簡單清晰
9. 性能最佳化
建議:
- 避免在模板中頻繁調用
$t()
- 使用計算屬性快取翻譯結果
- 考慮預載入常用語言包
vue
<script setup lang="ts">
// 好的做法:使用計算屬性
const pageTitle = computed(() => $t('common.title'))
// 避免:在模板中直接調用
// {{ $t('common.title') }}
</script>
10. 除錯技巧
除錯工具:
- 使用瀏覽器開發者工具檢查語言包載入
- 開啟
missingWarn
和fallbackWarn
- 檢查網路請求中的語言頭設置
typescript
// 在開發環境中啟用詳細警告
export const i18n = createI18n({
missingWarn: true,
fallbackWarn: true,
// ... 其他配置
})
通過遵循這些指南和最佳實踐,您可以有效地在項目中使用和管理國際化功能,避免常見問題,並提供良好的多語言用戶體驗。