npm package: @oukeye/meetfun-i18n
Description: 基于 vue-i18n 的 uni-app 国际化解决方案，支持多语言缓存、远程语言包、动态加载等功能
Author: meetfun
Latest version: 1.0.0

# @meetfun/i18n

基于 vue-i18n 的 uni-app 国际化解决方案，支持多语言缓存、远程语言包、动态加载等功能。

## 特性

- 🚀 **开箱即用** - 简单的 API 设计，快速集成到 uni-app 项目
- 📦 **多语言缓存** - 自动缓存语言包到本地，支持离线使用
- 🔄 **动态语言包** - 支持从远程服务器动态加载语言包
- 🎯 **缺失键上报** - 自动收集并上报缺失的翻译键
- 🔧 **变量替换** - 支持复杂的变量替换，包括嵌套对象访问
- 🎨 **代理模式** - 提供 I18nProxy 类，轻松处理枚举翻译
- 📱 **跟随系统** - 支持跟随系统语言自动切换
- 💪 **TypeScript** - 完整的类型定义支持

## 安装

```bash
pnpm add @meetfun/i18n
```

## 快速开始

### 1. 准备语言包文件

创建语言包文件，例如 `src/locales/zh-Hans.json`：

```json
{
  "TALENTS": {
    "欢迎": "欢迎",
    "你好，{name}": "你好，{name}"
  }
}
```

### 2. 创建 API 函数

创建获取语言包的 API 函数，例如 `src/api/translate.ts`：

```typescript
import { translateRequest } from '@/utils/request'
import type { LangDictResponse, QueryLangDictColdDataParams } from '@meetfun/i18n'

/**
 * 获取热数据（常用翻译）
 */
export const queryLangDictHotData = (params: { systemCode: string }) => {
  return translateRequest.post<LangDictResponse>(
    '/api/translate/langDict/queryLangDictHotData',
    params,
  )
}

/**
 * 获取冷数据（缺失翻译上报）
 */
export const queryLangDictColdData = (params: QueryLangDictColdDataParams) => {
  return translateRequest.post<LangDictResponse>(
    '/api/translate/langDict/queryLangDictColdData',
    params,
    { custom: { loading: false } },
  )
}
```

### 3. 初始化 i18n

在 `src/locales/index.ts` 中初始化：

```typescript
import { createMeetFunI18n } from '@meetfun/i18n'
import { queryLangDictHotData, queryLangDictColdData } from '@/api/translate'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
import en from './en.json'

// 基础语言包
const baseMessages = {
  'zh-Hans': zhHans,
  'zh-Hant': zhHant,
  en: en,
}

// API 配置
const apiConfig = {
  queryLangDictHotData,
  queryLangDictColdData,
}

// 创建 i18n 实例
const i18nInstance = createMeetFunI18n(baseMessages, apiConfig, {
  defaultLocale: 'zh-Hans',
  defaultLangDictDomainCode: 'TALENTS',
  systemCode: 'TALENTS_STUDENT',
  localeCacheKey: 'APP_LOCALE_SETTING',
  langDictCacheKey: 'APP_LANG_DICT_CACHE',
  cacheMaxAge: 365 * 24 * 60 * 60 * 1000, // 365天
  reportDelay: 5000, // 5秒
})

export default i18nInstance
```

### 4. 在 Vue 应用中使用

在 `main.ts` 中安装：

```typescript
import { createSSRApp } from 'vue'
import i18nInstance from './locales'

export function createApp() {
  const app = createSSRApp(App)
  
  // 安装 vue-i18n
  app.use(i18nInstance.getI18n())
  
  return {
    app,
  }
}
```

### 5. 在组件中使用

```vue
<template>
  <view>
    <!-- 使用 $t 函数翻译 -->
    <text>{{ $t('欢迎') }}</text>
    
    <!-- 带变量的翻译 -->
    <text>{{ $t('你好，{name}', { name: '张三' }) }}</text>
  </view>
</template>

<script setup lang="ts">
import i18nInstance from '@/locales'

// 直接使用 i18n 实例
const welcomeText = i18nInstance.$t('欢迎')

// 带参数
const greetingText = i18nInstance.$t('你好，{name}', { name: '李四' })
</script>
```

## API 文档

### createMeetFunI18n(baseMessages, apiConfig, userConfig?)

创建 i18n 实例的工厂函数。

**参数：**

- `baseMessages`: `Record<string, any>` - 基础语言包
- `apiConfig`: `ApiConfig` - API 配置
  - `queryLangDictHotData`: 获取热数据的函数
  - `queryLangDictColdData`: 获取冷数据的函数
- `userConfig?`: `Partial<I18nConfig>` - 用户配置（可选）
  - `defaultLocale?`: 默认语言，默认 `'zh-Hans'`
  - `defaultLangDictDomainCode?`: 默认领域代码，默认 `'TALENTS'`
  - `systemCode?`: 系统代码
  - `localeCacheKey?`: 语言设置缓存键，默认 `'APP_LOCALE_SETTING'`
  - `langDictCacheKey?`: 语言包缓存键，默认 `'APP_LANG_DICT_CACHE'`
  - `cacheMaxAge?`: 缓存最大有效期（毫秒），默认 365 天
  - `reportDelay?`: 上报延迟时间（毫秒），默认 5000ms

**返回：** `MeetFunI18n` 实例

### MeetFunI18n 实例方法

#### $t(key, params?)

翻译函数，支持变量替换。

```typescript
const text = i18nInstance.$t('你好，{name}', { name: '张三' })
```

#### fetchLangDictHotData()

获取远程语言包（热数据）。

```typescript
await i18nInstance.fetchLangDictHotData()
```

#### switchLocale(locale)

切换语言。

```typescript
import { LANGUAGE_OPTIONS_CONFIGURATION } from '@meetfun/i18n'

// 切换到英文
i18nInstance.switchLocale(LANGUAGE_OPTIONS_CONFIGURATION.EN)

// 跟随系统
i18nInstance.switchLocale(LANGUAGE_OPTIONS_CONFIGURATION.FOLLOW_SYSTEM)
```

#### getCurrentLocale()

获取当前语言。

```typescript
const locale = i18nInstance.getCurrentLocale() // 'zh-Hans'
```

#### getHeaderLang()

获取用于请求头的语言标识。

```typescript
const headerLang = i18nInstance.getHeaderLang() // 'zh_cn'
```

#### updateI18nMessages(langDictData, saveToCache?)

更新语言包。

```typescript
await i18nInstance.updateI18nMessages(newLangData, true)
```

#### flushMissingKeys()

立即上报所有缓存的缺失翻译键。

```typescript
await i18nInstance.flushMissingKeys()
```

#### getTranslationKeysStats()

获取翻译键统计信息。

```typescript
const stats = i18nInstance.getTranslationKeysStats()
console.log(stats.missingKeys) // { TALENTS: 10 }
console.log(stats.usedKeys) // { TALENTS: 100 }
```

#### clearLangDictCache()

清除语言包缓存。

```typescript
i18nInstance.clearLangDictCache()
```

## 高级功能

### I18nProxy - 枚举翻译代理

使用代理模式轻松处理枚举翻译：

```typescript
import { createI18nProxy } from '@meetfun/i18n'
import i18nInstance from '@/locales'

// 定义角色枚举翻译映射
const roleNamesMap = {
  PRODUCING_AREA: 'role.PRODUCING_AREA',
  PRESENTATION_AREA: 'role.PRESENTATION_AREA',
  STORE_MANAGER: 'role.STORE_MANAGER',
}

// 创建代理对象
const roleNames = createI18nProxy(roleNamesMap, i18nInstance.$t)

// 直接访问即可获得翻译后的文本
console.log(roleNames.PRODUCING_AREA) // '产区'
console.log(roleNames.STORE_MANAGER) // '店长'
```

### 变量替换

支持嵌套对象访问的变量替换：

```typescript
const template = '用户 {user.name} 的年龄是 {user.age}'
const params = {
  user: {
    name: '张三',
    age: 25,
  },
}

const result = i18nInstance.interpolateVariables(template, params)
console.log(result) // '用户 张三 的年龄是 25'
```

### 条件编译支持

在不同的编译环境使用不同的系统代码：

```typescript
let systemCode = 'TALENTS_STUDENT'
// #ifdef SYSTEM_S
systemCode = 'TALENTS_STUDENT'
// #endif

// #ifdef SYSTEM_M
systemCode = 'TALENTS_MANAGEMENT_APP'
// #endif

const i18nInstance = createMeetFunI18n(baseMessages, apiConfig, {
  systemCode,
})
```

## 语言包数据格式

服务器返回的语言包格式：

```json
{
  "zh_cn": {
    "TALENTS": {
      "欢迎": "欢迎",
      "你好": "你好"
    }
  },
  "zh_hk": {
    "TALENTS": {
      "欢迎": "歡迎",
      "你好": "你好"
    }
  },
  "en": {
    "TALENTS": {
      "欢迎": "Welcome",
      "你好": "Hello"
    }
  }
}
```

库会自动将 `zh_cn` 转换为 `zh-Hans`，`zh_hk` 转换为 `zh-Hant`。

## 最佳实践

### 1. 在 App.vue 中加载远程语言包

```vue
<script setup lang="ts">
import { onLaunch } from '@dcloudio/uni-app'
import i18nInstance from '@/locales'

onLaunch(() => {
  // 加载远程语言包
  i18nInstance.fetchLangDictHotData()
})
</script>
```

### 2. 在页面卸载时上报缺失键

```vue
<script setup lang="ts">
import { onUnmounted } from 'vue'
import i18nInstance from '@/locales'

onUnmounted(() => {
  // 立即上报缺失的翻译键
  i18nInstance.flushMissingKeys()
})
</script>
```

### 3. 语言切换组件

```vue
<template>
  <view>
    <picker :value="langIndex" :range="langOptions" @change="handleLangChange">
      <view>{{ langOptions[langIndex] }}</view>
    </picker>
  </view>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { LANGUAGE_OPTIONS_CONFIGURATION } from '@meetfun/i18n'
import i18nInstance from '@/locales'

const langOptions = ['跟随系统', '简体中文', '繁體中文', 'English']
const langIndex = ref(0)

const handleLangChange = (e: any) => {
  const index = e.detail.value
  langIndex.value = index
  
  const langMap = [
    LANGUAGE_OPTIONS_CONFIGURATION.FOLLOW_SYSTEM,
    LANGUAGE_OPTIONS_CONFIGURATION.ZH_HANS,
    LANGUAGE_OPTIONS_CONFIGURATION.ZH_HANT,
    LANGUAGE_OPTIONS_CONFIGURATION.EN,
  ]
  
  i18nInstance.switchLocale(langMap[index])
  
  uni.showToast({
    title: '切换成功',
    icon: 'success',
  })
}
</script>
```

## 注意事项

1. **uni 对象依赖**：本库依赖 uni-app 的 `uni` 全局对象，仅适用于 uni-app 项目。
2. **API 配置**：必须提供 `queryLangDictHotData` 和 `queryLangDictColdData` 两个 API 函数。
3. **缓存策略**：语言包缓存默认有效期为 365 天，可根据需求调整。
4. **缺失键上报**：使用防抖机制，默认延迟 5 秒上报，避免频繁请求。

## 类型定义

本库提供完整的 TypeScript 类型定义，支持类型提示和检查。

```typescript
import type {
  I18nConfig,
  ApiConfig,
  LangDictResponse,
  TranslationKeysStats,
  // ... 更多类型
} from '@meetfun/i18n'
```

## License

MIT

## 作者

meetfun