国际化(i18n)
13:16概述
项目集成了 vue-i18n 库,提供了完整的多语言国际化解决方案。支持在运行时动态切换语言,所有的文本内容都能实时更新。
项目特性
- 🌍 多语言支持 - 支持中文、英文等多语言
- 🔄 动态切换 - 运行时即时切换语言无需重新加载
- 📦 JSON 配置 - 使用 JSON 文件管理语言包
- 💬 组件级别 - 支持在组件中使用翻译
- 🎯 类型安全 - TypeScript 支持完整的类型检查
初始化配置
vue-i18n 配置
在 src/locale/index.ts 中:
typescript
import { createI18n } from 'vue-i18n'
import enUS from './lang/en-US.json' // 英文
import zhCN from './lang/zh-CN.json' // 简体中文
const messages = {
'en': enUS,
'zh-Hans': zhCN,
}
// 安全获取 locale,避免在 SSR 环境下出现问题
function getSafeLocale() {
try {
return uni.getLocale() || 'zh-Hans'
}
catch {
return 'zh-Hans'
}
}
const i18n = createI18n({
locale: getSafeLocale(), // 初始语言
fallbackLocale: 'zh-Hans', // 回退语言
messages, // 语言包
allowComposition: true, // 允许在 Composition API 中使用
legacy: false, // 使用 Composition API 模式
globalInjection: true, // 全局注入
})
export default i18n在 main.ts 中初始化
typescript
import i18n from '@/locale'
import uViewPro from 'uview-pro'
const app = createSSRApp(App)
// 引入 i18n
app.use(i18n)
// 引入 uView Pro 组件并初始化中文语言
app.use(uViewPro, {
locale: 'zh-CN'
})语言包结构
简体中文语言包
创建 src/locale/lang/zh-CN.json:
json
{
"common": {
"appName": "uView Pro 启动项目",
"home": "首页",
"about": "关于",
"settings": "设置",
"logout": "退出登录",
"confirm": "确定",
"cancel": "取消",
"loading": "加载中...",
"noData": "暂无数据"
},
"home": {
"welcome": "欢迎使用 uView Pro",
"description": "这是一个快速启动项目"
},
"about": {
"title": "关于我们",
"version": "版本"
}
}英文语言包
创建 src/locale/lang/en-US.json:
json
{
"common": {
"appName": "uView Pro Starter",
"home": "Home",
"about": "About",
"settings": "Settings",
"logout": "Logout",
"confirm": "OK",
"cancel": "Cancel",
"loading": "Loading...",
"noData": "No Data"
},
"home": {
"welcome": "Welcome to uView Pro",
"description": "This is a quick start project"
},
"about": {
"title": "About Us",
"version": "Version"
}
}基本使用
在模板中使用
vue
<template>
<view class="container">
<!-- 使用 $t 翻译文本 -->
<text>{{ $t('common.appName') }}</text>
<text>{{ $t('home.welcome') }}</text>
</view>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
</script>在 Script 中使用
vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const appName = t('common.appName')
const message = t('home.welcome')
const getMessage = () => {
return t('common.loading')
}
</script>带参数的翻译
语言包配置
json
{
"messages": {
"hello": "你好,{name}",
"count": "你有 {count} 条消息"
}
}使用翻译
vue
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
// 简单参数
const greeting = t('messages.hello', { name: '张三' })
// 输出: 你好,张三
// 复数形式
const message = t('messages.count', { count: 5 })
// 输出: 你有 5 条消息
</script>
<template>
<text>{{ greeting }}</text>
<text>{{ message }}</text>
</template>高级用法
动态切换语言
创建 src/hooks/useLang.ts:
typescript
import { useLocale } from 'uview-pro'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
export function useLang() {
const { locale } = useI18n()
const { setLocale, currentLocale, locales } = useLocale()
// 派生当前语言(基于 uView Pro 的 currentLocale),确保模板自动响应更新
const currentLang = computed(() => {
return currentLocale.value?.name || currentLocale.value || ''
})
// 当前语言标签
const currentLangLabel = computed(() => {
return getLangLabel(currentLang.value)
})
// 可用语言列表
const availableLangs = computed(() => {
return locales.value.map(locale => ({
name: locale.name,
label: getLangLabel(locale.name),
}))
})
// 辅助函数:根据不同的语言代码格式,返回i18n使用的语言代码
function getI18nLocale(value: string) {
switch (value) {
case 'zh-CN':
case 'zh-Hans':
return 'zh-Hans'
case 'en-US':
case 'en':
return 'en'
default:
return 'zh-Hans'
}
}
// 辅助函数:根据不同的语言代码格式,返回uView Pro使用的语言代码
function getUProLocale(value: string) {
switch (value) {
case 'zh-Hans':
case 'zh-CN':
return 'zh-CN'
case 'en':
case 'en-US':
return 'en-US'
default:
return 'zh-CN'
}
}
// 根据语言代码返回对应的语言文字标签
function getLangLabel(localeName: string) {
const normalized = getUProLocale(localeName)
if (normalized === 'zh-CN')
return '简体中文'
if (normalized === 'en-US')
return 'English'
return normalized
}
// 切换语言
function switchLang(lang: string) {
const i18nLocale = getI18nLocale(lang)
const uProLocale = getUProLocale(lang)
// 切换uniapp语言
uni.setLocale(i18nLocale)
// 切换vue-i18n语言
locale.value = i18nLocale
// 切换uView Pro语言
setLocale(uProLocale)
}
return {
currentLang,
currentLangLabel,
availableLangs,
getLangLabel,
switchLang,
}
}在组件中使用:
vue
<script setup lang="ts">
import { useLang } from '@/composables/useLocale'
const { switchLang, currentLangLabel, currentLang, availableLangs } = useLang()
const handleLocaleChange = (locale: string) => {
switchLang(locale)
}
</script>
<template>
<view class="locale-selector">
<text>当前语言:{{ currentLocale }}</text>
<view v-for="loc in availableLocales" :key="loc.name">
<u-button
@click="handleLocaleChange(loc.name)"
:type="currentLang === loc.name ? 'primary' : 'default'"
>
{{ loc.label }}
</u-button>
</view>
</view>
</template>在 Store 中使用国际化
typescript
import { useI18n } from 'vue-i18n'
import { defineStore } from 'pinia'
export const useAppStore = defineStore('app', () => {
const { t } = useI18n()
function showNotification() {
// 使用翻译的文本
const message = t('common.noData')
console.log(message)
}
return { showNotification }
})常见场景
条件渲染
vue
<script setup lang="ts">
import { useLang } from '@/composables/useLang'
const { currentLang } = useLang()
</script>
<template>
<view v-if="currentLang === 'zh-CN'" class="zh-only">
仅中文显示
</view>
<view v-else class="en-only">
English only
</view>
</template>复数形式
语言包配置:
json
{
"items": "你有 {count} 个项目 | 你有 {count} 个项目"
}使用:
typescript
// 当 count = 1 时,使用第一个,count > 1 时,使用第二个
const text = t('items', { count: 5 })嵌套翻译
json
{
"user": {
"profile": {
"name": "姓名",
"email": "邮箱"
}
}
}使用:
vue
<template>
<text>{{ $t('user.profile.name') }}</text>
</template>动态翻译
typescript
const keys = ['home.welcome', 'home.description', 'about.title']
const translations = keys.map(key => t(key))从 uni.getLocale() 获取系统语言
typescript
// 获取系统语言
const systemLocale = uni.getLocale()
// 映射到支持的语言
const localeMap: Record<string, string> = {
'zh-Hans': 'zh-CN', // 简体中文
'zh-Hant': 'zh-CN', // 繁体中文 → 简体中文
'en': 'en-US',
'en-US': 'en-US',
}
const mappedLocale = localeMap[systemLocale] || 'zh-CN'组织大型项目的语言包
对于大型项目,建议分文件组织:
src/locale/
├── index.ts
└── lang/
├── zh-CN/
│ ├── index.ts
│ ├── common.json
│ ├── home.json
│ ├── about.json
│ └── user.json
└── en-US/
├── index.ts
├── common.json
├── home.json
├── about.json
└── user.jsonsrc/locale/lang/zh-CN/index.ts:
typescript
import common from './common.json'
import home from './home.json'
import about from './about.json'
import user from './user.json'
export default {
common,
home,
about,
user,
}最佳实践
- 统一的 key 命名规范 - 使用
module.feature.name的命名方式 - 避免硬编码 - 所有可见文本都应该使用翻译
- 为默认语言优化 - 确保默认语言的翻译质量最高
- 使用回退语言 - 配置回退语言以处理缺失的翻译
- 注意文本长度 - 不同语言的文本长度可能差异很大,要在 UI 设计时考虑
- 测试多语言 - 在所有支持的语言环境下进行测试
- 定期审查 - 定期检查和更新翻译内容
故障排除
翻译不显示
- 检查语言包文件是否存在
- 检查 key 是否拼写正确
- 确保 i18n 已正确初始化
- 在浏览器控制台检查是否有错误信息
语言不切换
typescript
// 确保使用正确的方式修改 locale
import { useI18n } from 'vue-i18n'
const { locale } = useI18n()
// 正确
locale.value = 'en'
// 错误
locale = 'en'