npm package: @gulibs/react-vintl
Description: Type-safe i18n library for React with Vite plugin and automatic type inference
Author: gulibs
Latest version: 0.0.20

# @gulibs/react-vintl

> 🌍 为 React 设计的类型安全 i18n 库，具有自动类型推断功能 - 无需单独的键文件！

## ✨ 特性

- 🎯 **完美的 IDE 自动补全** - 联合类型生成提供无与伦比的自动补全体验（例如，输入 `t('common.` 会显示所有 `common.*` 键）
- ⚡ **极致 API 设计** - `useTranslation()` 直接返回函数，无需解构！
- 🚀 **零配置** - 开箱即用，具有合理的默认设置
- 🔥 **热模块替换** - 翻译文件的更改会立即更新类型和 UI
- 📦 **Vite 插件** - 与您的 Vite 工作流无缝集成
- 🎨 **React Hooks 和组件** - 适用于所有用例的灵活 API
- 🌐 **多种文件格式** - 支持 JSON、TypeScript 和 JavaScript
- 💪 **完全类型安全** - 无效翻译键的编译时错误
- 🔄 **命名空间支持** - 使用点记法的有序分层键结构
- 🔄 **自动类型同步** - 添加新字段后编辑器立即识别，无需重启 TypeScript 服务器
- 🌐 **远程翻译加载** - 支持从网络接口动态加载翻译并自动合并

## 📦 安装

```bash
npm install @gulibs/react-vintl
# 或
pnpm add @gulibs/react-vintl
# 或
yarn add @gulibs/react-vintl
```

## 🚀 快速开始

### 1. 配置 Vite 插件

```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { createReactVintlPlugin } from '@gulibs/react-vintl'

export default defineConfig({
  plugins: [
    react(),
    createReactVintlPlugin({
      basePath: 'src/locales',
      debug: true
    })
  ]
})
```

### 2. 创建翻译文件

```
src/locales/
├── en/
│   ├── common.json
│   └── auth.json
└── zh/
    ├── common.json
    └── auth.json
```

**翻译文件示例：**

```json
// src/locales/en/common.json
{
  "welcome": "Welcome",
  "buttons": {
    "save": "Save",
    "cancel": "Cancel"
  }
}
```

```json
// src/locales/zh/common.json
{
  "welcome": "欢迎",
  "buttons": {
    "save": "保存",
    "cancel": "取消"
  }
}
```

### 3. 在您的应用中使用

```tsx
// src/App.tsx
import { I18nProvider, useTranslation, useI18n, Translation } from '@gulibs/react-vintl'
import { resources, supportedLocales } from '@gulibs/react-vintl-locales'

function ExampleComponent() {
  // ✅ 极致 API：useTranslation 直接返回翻译函数
  const t = useTranslation()

  // ✅ 用于全局状态的独立钩子
  const { locale, setLocale } = useI18n()

  return (
    <div>
      <h1>{t('common.welcome')}</h1>
      <button>{t('common.buttons.save')}</button>

      {/* 使用 Translation 组件 */}
      <Translation keyPath="common.welcome" />

      {/* 语言切换器 */}
      <select value={locale} onChange={e => setLocale(e.target.value)}>
        {supportedLocales.map(loc => (
          <option key={loc} value={loc}>{loc}</option>
        ))}
      </select>
    </div>
  )
}

export default function App() {
  return (
    <I18nProvider
      resources={resources}
      defaultLocale="en"
      supportedLocales={supportedLocales}
    >
      <ExampleComponent />
    </I18nProvider>
  )
}
```

## 📖 API 参考

### 插件选项

```typescript
interface I18nPluginOptions {
  basePath?: string              // 默认: 'src/locales'
  extensions?: string[]          // 默认: ['.json', '.ts', '.js']
  localePattern?: 'directory' | 'filename'  // 默认: 'directory'
  hmr?: boolean                  // 默认: true
  debug?: boolean                // 默认: false
}
```

### 钩子

#### `useTranslation(namespace?)`

**新特性**: 直接返回翻译函数 - 无需解构！

```typescript
// 无命名空间 - 完整键路径
const t = useTranslation()
t('common.welcome')           // ✅ 完整自动补全
t('auth.login.title')         // ✅ 所有键都可用

// 带命名空间 - 相对键路径
const tCommon = useTranslation('common')
tCommon('welcome')            // ✅ 仅 common.* 键
tCommon('buttons.save')       // ✅ 作用域自动补全

const tAuth = useTranslation('auth')
tAuth('login.title')          // ✅ 仅 auth.* 键

// 带参数
const text = t('messages.greeting', { name: 'World' })
```

**类型签名：**

```typescript
function useTranslation(): TranslationFunction
function useTranslation<N extends I18nNamespaces>(namespace: N): NamespacedTranslationFunction<N>
```

#### `useI18n()`

**新特性**: 从翻译函数中独立获取全局 i18n 状态。

```typescript
const { locale, supportedLocales, setLocale, resources } = useI18n()

// 现在您可以多次调用 useTranslation 而不会产生冗余状态
const t1 = useTranslation('common')
const t2 = useTranslation('auth')
const { locale } = useI18n()  // 只获取状态一次
```

#### `useLocale()`

用于语言切换的 `useI18n()` 简化版本。

```typescript
const { locale, supportedLocales, setLocale, isSupportedLocale } = useLocale()
```

#### `useTranslationKey(key, params?)`

返回带有记忆化的特定翻译。

```typescript
const { translation, t } = useTranslationKey('common.welcome')
```

#### `useLoadRemoteTranslations(source, options?)`

**新特性**: 从外部接口加载翻译资源并自动合并到现有资源。

支持三种加载方式：
- **URL 字符串**: 从 HTTP 接口加载
- **函数**: 从自定义加载函数获取
- **Promise**: 从 Promise 获取

```typescript
// 从 URL 加载
const { loading, error, data, retry } = useLoadRemoteTranslations(
  'https://api.example.com/translations/en',
  {
    namespace: 'remote',  // 合并到指定的 namespace
    locale: 'en',
    merge: true,         // 自动合并（默认 true）
    cache: true,         // 启用缓存（默认 true）
    onSuccess: (resources) => console.log('Loaded:', resources),
    onError: (error) => console.error('Error:', error),
    retry: 3,            // 重试次数
    retryDelay: 1000    // 重试延迟（毫秒）
  }
)

// 从函数加载
const loader = useLoadRemoteTranslations(
  () => fetch('/api/translations').then(r => r.json()),
  { namespace: 'remote' }
)

// 从 Promise 加载
const promiseLoader = useLoadRemoteTranslations(
  fetch('/api/translations').then(r => r.json()),
  { namespace: 'remote' }
)

// 使用合并后的翻译（立即可用）
const t = useTranslation()
t('remote.title' as any)  // 动态字段需要使用类型断言
```

**选项说明：**

```typescript
interface LoadRemoteTranslationsOptions {
  locale?: string        // 目标语言，默认使用当前语言
  namespace?: string     // 合并到指定的 namespace（可选）
  merge?: boolean        // 是否自动合并（默认 true）
  cache?: boolean        // 是否启用缓存（默认 true）
  onSuccess?: (resources: I18nResources) => void
  onError?: (error: Error) => void
  retry?: number         // 重试次数（默认 0）
  retryDelay?: number    // 重试延迟（毫秒，默认 1000）
}
```

**返回值：**

```typescript
interface LoadRemoteTranslationsResult {
  loading: boolean       // 是否正在加载
  error: Error | null    // 错误信息
  data: I18nResources | null  // 加载的数据
  retry: () => void      // 手动重试函数
}
```

**特性：**
- ✅ 自动合并到现有资源
- ✅ 支持 namespace 级别的合并
- ✅ 支持根级别合并（不指定 namespace）
- ✅ 加载状态管理（loading、error、data）
- ✅ 智能缓存机制避免重复请求
  - 不同的 `namespace` 配置使用不同的缓存键，避免冲突
  - 支持缓存过期时间（默认 5 分钟）
- ✅ 请求去重（多个组件同时加载相同资源）
- ✅ 错误处理和重试机制
- ✅ 加载后翻译立即可用
- ✅ 资源合并后自动更新翻译函数

**完整示例：**

查看 `test/src/RemoteTranslationDemo.tsx` 获取完整的使用示例。

### 组件

#### `<Translation>`

渲染带有可选参数和命名空间支持的翻译。

```tsx
{/* 无命名空间 - 完整键路径 */}
<Translation keyPath="common.welcome" />
<Translation keyPath="auth.login.title" params={{ name: 'React' }} />

{/* 带命名空间 - 相对键路径 */}
<Translation namespace="common" keyPath="welcome" />
<Translation namespace="auth" keyPath="login.title" />

{/* 自定义渲染 */}
<Translation keyPath="common.welcome" fallback="Welcome">
  {text => <strong>{text}</strong>}
</Translation>
```

#### `<T>`

`<Translation>` 组件的别名。

```tsx
<T keyPath="common.welcome" />
<T namespace="auth" keyPath="logout" />
```

#### `<LocaleSwitcher>`

内置语言切换器组件。

```tsx
<LocaleSwitcher />
```

## ⚡ 极致 API 设计

`react-vintl` 遵循现代 React Hooks 约定，通过**直接返回函数**而不是对象。

### 对象返回的问题

```typescript
// ❌ 传统方法 - 需要解构
const { t } = useTranslation()
const { t: tCommon } = useTranslation('common')
const { t: tAuth, locale } = useTranslation('auth')
// 问题：冗长，冗余的状态访问
```

### 我们的解决方案：直接函数返回

```typescript
// ✅ 极致 API - 直接函数返回
const t = useTranslation()              // 无需解构！
const tCommon = useTranslation('common')
const tAuth = useTranslation('auth')

// ✅ 独立的状态访问
const { locale, setLocale } = useI18n() // 仅在需要时
```

### 优势

1. **更简洁的代码**

   ```typescript
   const t = useTranslation()          // 对比 const { t } = useTranslation()
   ```

2. **清晰的关注点分离**
   - `useTranslation()` → 翻译函数
   - `useI18n()` → 全局状态管理
   - `useLocale()` → 语言切换

3. **更好的性能**
   - 使用多个命名空间时不会创建冗余对象
   - 减少内存占用

4. **遵循 React 约定**
   - 像 `useRef()` - 直接返回 ref
   - 像 `useCallback()` - 直接返回函数
   - 像 `useMemo()` - 直接返回值

### 实际示例

```typescript
function MyComponent() {
  // 多个翻译函数 - 无冗余
  const tCommon = useTranslation('common')
  const tAuth = useTranslation('auth')
  const tProducts = useTranslation('products')

  // 全局状态 - 只访问一次
  const { locale, setLocale } = useI18n()

  return (
    <div>
      <h1>{tCommon('welcome')}</h1>
      <p>{tAuth('login.title')}</p>
      <button>{tProducts('addToCart')}</button>
      <p>Current: {locale}</p>
    </div>
  )
}
```

## 🎯 类型推断魔法

`react-vintl` 的核心创新是**自动类型推断**，无需生成单独的类型文件！

### 工作原理

1. **启动时生成** - 插件扫描翻译文件并在 `react-vintl-locales.d.ts` 中生成联合类型
2. **联合类型推断** - 所有翻译键都被提取为字符串字面量联合类型
3. **热模块替换** - 文件更改会自动更新类型并触发 HMR
4. **完美的 IDE 集成** - TypeScript 为所有键提供即时自动补全

### 自动类型同步

当您添加新的国际化字段时，插件会：
1. **自动检测变化** - 监听 locale 文件夹的文件变化
2. **更新类型定义** - 自动更新 `react-vintl-locales.d.ts` 文件
3. **触发 TypeScript 服务器重新加载** - 通过文件系统事件通知 TypeScript 语言服务器
4. **立即生效** - 编辑器通常在几秒内识别新字段，无需手动重启

这意味着：
- ✅ 添加新字段后，编辑器立即提供自动补全
- ✅ 构建时类型检查自动通过，不会因为新字段而失败
- ✅ 无需手动重启 TypeScript 服务器
- ✅ 支持所有主流编辑器（VSCode、WebStorm、Sublime Text 等）

```typescript
// 插件自动在 react-vintl-locales.d.ts 中生成：

export type I18nKeys =
  | 'common.welcome'
  | 'common.buttons.save'
  | 'common.buttons.cancel'
  | 'auth.login.title'
  | 'auth.login.username'
  | ... // 所有您的翻译键作为联合类型！

// 您的编辑器获得完美的自动补全！
const text = t('common.')      // ✅ 显示：welcome, buttons.save, buttons.cancel...
const text = t('auth.login.')  // ✅ 显示：title, username, password...
```

**为什么使用联合类型？**
- ✅ 完美的 IDE 自动补全体验
- ✅ 即使有数千个键也能快速 TypeScript 编译
- ✅ 使用无效键时的清晰类型错误
- ✅ 命名空间感知建议（输入 `common.` 只显示 `common.*` 键）

### 无需单独的键文件！

与需要生成单独类型定义文件的传统 i18n 库不同，`react-vintl` 直接从虚拟模块推断类型：

```typescript
// ❌ 传统方法 - 需要单独生成
import { I18nKeys } from './i18n-keys' // 单独文件

// ✅ react-vintl - 自动推断
import { type I18nKeys } from '@gulibs/react-vintl-locales' // 来自虚拟模块！
```

## 🔧 高级用法

### 远程翻译加载

`react-vintl` 支持从外部接口动态加载翻译资源，实现文件翻译（基础）+ 接口翻译（动态）的混合模式。

#### 基本用法

```typescript
import { useLoadRemoteTranslations, useTranslation } from '@gulibs/react-vintl'

function MyComponent() {
  // 加载远程翻译
  const { loading, error } = useLoadRemoteTranslations(
    'https://api.example.com/translations/en',
    {
      namespace: 'remote',  // 合并到 'remote' namespace
      merge: true           // 自动合并
    }
  )

  const t = useTranslation()

  if (loading) return <div>Loading translations...</div>
  if (error) return <div>Error: {error.message}</div>

  // 远程翻译立即可用
  return <div>{t('remote.title' as any)}</div>
}
```

#### 合并策略

**Namespace 级别合并：**

```typescript
// 将远程翻译合并到指定的 namespace
useLoadRemoteTranslations(
  fetch('/api/translations').then(r => r.json()),
  { namespace: 'remote' }
)

// 结果结构：
// {
//   en: {
//     common: { ... },      // 文件翻译
//     remote: { ... }       // 远程翻译合并到这里
//   }
// }
```

**根级别合并：**

```typescript
// 不指定 namespace，合并到根级别（与现有 namespace 平级）
useLoadRemoteTranslations(
  Promise.resolve({
    en: {
      rootLevel: {
        message: "This is merged at root level"
      }
    },
    zh: {
      rootLevel: {
        message: "这是在根级别合并的"
      }
    }
  }),
  { merge: true }  // 不指定 namespace
)

// 结果结构：
// {
//   en: {
//     common: { ... },      // 文件翻译
//     rootLevel: { ... }   // 远程翻译（新 namespace，与 common 平级）
//   }
// }

// 使用合并后的翻译
const t = useTranslation()
t('rootLevel.message')  // ✅ 立即可用
```

**重要提示：**
- 根级别合并时，远程翻译中的每个顶级键都会作为新的 namespace 合并
- 不同的 `namespace` 配置会使用不同的缓存键，即使 `source` 相同也不会冲突
- 资源合并后，翻译函数会在下次渲染时自动更新，确保使用最新资源

#### 手动更新资源

您也可以手动更新资源：

```typescript
import { useI18nContext } from '@gulibs/react-vintl'

function MyComponent() {
  const { updateResources } = useI18nContext()

  const handleLoad = async () => {
    const remoteTranslations = await fetch('/api/translations').then(r => r.json())
    
    // 合并到指定的 namespace
    updateResources(remoteTranslations, {
      namespace: 'remote',
      merge: true
    })
  }

  return <button onClick={handleLoad}>Load Translations</button>
}
```

#### 工具函数

```typescript
import { mergeResources } from '@gulibs/react-vintl'

// 手动合并资源
const merged = mergeResources(
  baseResources,
  remoteResources,
  {
    namespace: 'remote',  // 可选：合并到指定 namespace
    locale: 'en'         // 可选：只合并指定 locale
  }
)
```

**完整示例：**

查看 `test/src/RemoteTranslationDemo.tsx` 获取完整的使用示例和所有功能演示。

### TypeScript 翻译文件

您可以使用 TypeScript 进行动态翻译：

```typescript
// src/locales/en/dynamic.ts
export default {
  currentYear: new Date().getFullYear(),
  greeting: (name: string) => `Hello, ${name}!`,
  environment: process.env.NODE_ENV === 'development' ? 'Dev' : 'Prod'
} as const
```

### 命名空间翻译

按功能组织翻译：

```
src/locales/
├── en/
│   ├── common.json
│   ├── auth/
│   │   ├── login.json
│   │   └── register.json
│   └── dashboard/
│       └── stats.json
```

使用点记法访问：

```typescript
t('auth.login.title')
t('dashboard.stats.users')
```

### 高级参数插值

`react-vintl` 支持强大的参数插值系统，包括多种格式化选项：

#### 简单插值

```json
{
  "greeting": "Hello, {{name}}!",
  "user_info": "User {{user.name}} has {{user.count}} messages"
}
```

```tsx
t('greeting', { name: 'John' })
// 结果: "Hello, John!"

t('user_info', { user: { name: 'Jane', count: 3 } })
// 结果: "User Jane has 3 messages"
```

#### 复数形式

```json
{
  "item_count": "{{count, plural, one=1 item, other=# items}}",
  "message_count": "{{count, plural, zero=No messages, one=1 message, other=# messages}}"
}
```

```tsx
t('item_count', { count: 1 })   // "1 item"
t('item_count', { count: 5 })   // "5 items"
t('message_count', { count: 0 }) // "No messages"
```

#### 选择形式

```json
{
  "gender_greeting": "{{gender, select, male=He, female=She, other=They}} is here",
  "status_message": "{{status, select, active=Online, inactive=Offline, other=Unknown}}"
}
```

```tsx
t('gender_greeting', { gender: 'male' })    // "He is here"
t('gender_greeting', { gender: 'female' })  // "She is here"
t('status_message', { status: 'active' })   // "Online"
```

#### 数字格式化

```json
{
  "price": "Price: {{amount, number}}",
  "decimal": "Value: {{value, number, minimumFractionDigits=2}}",
  "currency": "Cost: {{amount, currency, currency=USD}}"
}
```

```tsx
t('price', { amount: 1234.56 })        // "Price: 1,234.56"
t('decimal', { value: 1234.5 })        // "Value: 1,234.50"
t('currency', { amount: 99.99 })       // "Cost: $99.99"
```

#### 日期格式化

```json
{
  "created_date": "Created on {{date, date}}",
  "full_date": "{{date, date, year=numeric, month=long, day=numeric}}",
  "time": "Time: {{date, date, hour=numeric, minute=2-digit}}"
}
```

```tsx
t('created_date', { date: new Date() })
// 结果: "Created on 1/15/2024"

t('full_date', { date: new Date('2024-01-15') })
// 结果: "January 15, 2024"
```

#### 文本格式化

```json
{
  "text_format": "{{text, uppercase}} - {{text, lowercase}} - {{text, capitalize}}"
}
```

```tsx
t('text_format', { text: 'hello world' })
// 结果: "HELLO WORLD - hello world - Hello world"
```

#### 嵌套对象支持

```json
{
  "user_profile": "{{user.profile.name}} ({{user.profile.age}} years old)"
}
```

```tsx
t('user_profile', {
  user: {
    profile: {
      name: 'John',
      age: 25
    }
  }
})
// 结果: "John (25 years old)"
```

#### 错误处理和验证

`react-vintl` 提供了强大的错误处理机制：

```tsx
// 参数验证
t('greeting', { name: 'John' })           // ✅ 正常
t('greeting', { invalid: 'data' })        // ⚠️ 警告：参数不匹配
t('greeting', { name: null })             // ✅ 正常：null 值会被转换为字符串

// 循环引用检测
const circular = { name: 'John' }
circular.self = circular
t('greeting', circular)                   // ⚠️ 警告：检测到循环引用

// 格式错误处理
t('price', { amount: 'invalid' })         // ✅ 正常：返回原始值
t('date', { date: 'invalid-date' })       // ✅ 正常：返回原始值
```

## 🎨 与其他解决方案的对比

### vs vgrove-i18n

- ✅ 相同的类型推断方法
- ✅ React 特定的钩子和组件
- ✅ 无需 `keysOutput` 选项
- ✅ **更强大的参数插值系统** - 支持复数、选择、格式化等高级功能

### vs react-i18next

- ✅ 更好的 TypeScript 支持
- ✅ Vite 原生虚拟模块
- ✅ 无运行时开销
- ✅ 自动类型推断
- ✅ **内置格式化功能** - 无需额外插件即可使用数字、日期、货币格式化

### vs formatjs

- ✅ 更简单的 API
- ✅ 无需 ICU 消息格式
- ✅ 更好的开发者体验与自动补全
- ✅ **轻量级实现** - 无需复杂的 ICU 解析器
- ✅ **更好的性能** - 原生 JavaScript 实现，无外部依赖

## 📝 最佳实践

1. **使用目录模式进行本地化** - 更容易组织和维护
2. **保持翻译文件小巧** - 按功能或模块分割
3. **对动态内容使用 TypeScript** - 更好的类型安全
4. **利用自动补全** - 让您的编辑器指导您
5. **合理使用参数插值** - 避免过度复杂的插值表达式
6. **参数验证** - 始终验证传入的参数，避免运行时错误
7. **格式化一致性** - 在项目中保持数字、日期格式的一致性
8. **复数规则** - 根据目标语言正确设置复数规则
9. **远程翻译策略** - 使用文件翻译作为基础，远程翻译作为补充
10. **缓存管理** - 合理使用缓存机制，避免不必要的网络请求
    - 不同的 `namespace` 配置会自动使用不同的缓存键
    - 根级别合并和 namespace 合并不会共享缓存
11. **错误处理** - 为远程翻译加载提供适当的错误处理和重试机制
12. **资源同步** - 资源合并后，翻译函数会在下次渲染时自动更新
    - 如果需要在资源合并后立即使用翻译键，可以使用 `useI18n()` 检查资源是否已同步

## 🔧 日志配置

`react-vintl` 提供了统一的日志系统，允许您控制所有日志输出。所有模块（包括插件）都使用统一的 logger，确保日志行为一致。

### 日志级别

- **`debug`** - 调试日志，用于开发时的详细调试信息（如 `[useLoadRemoteTranslations]`、`[mergeResources]`）
- **`info`** - 一般信息日志，用于重要的运行时信息
- **`warn`** - 警告日志，用于潜在问题或非致命错误
- **`error`** - 错误日志，用于错误信息（始终输出，包括生产环境）

### 默认行为

- **开发环境** (`NODE_ENV=development`): 所有日志级别都启用
- **生产环境** (`NODE_ENV=production`): 仅 `error` 日志启用，`debug`、`info`、`warn` 自动禁用

### 控制日志输出

```typescript
import { logger } from '@gulibs/react-vintl'

// 禁用调试日志
logger.setConfig({ debug: false })

// 禁用信息日志
logger.setConfig({ info: false })

// 禁用警告日志
logger.setConfig({ warn: false })

// 禁用错误日志（不推荐，仅在特殊情况下使用）
logger.setConfig({ error: false })

// 同时配置多个选项
logger.setConfig({
  debug: false,
  info: true,
  warn: true,
  error: true
})
```

### 日志去重

Logger 默认启用去重机制，防止相同消息在短时间内（默认 5 秒）重复输出：

```typescript
// 禁用去重
logger.setConfig({ deduplicate: false })

// 自定义去重时间窗口（毫秒）
logger.setConfig({ deduplicationWindow: 10000 }) // 10 秒
```

### 调试日志和生产日志的区别

- **调试日志** (`debug`): 包含详细的执行流程信息，如资源加载、合并过程等，默认在生产环境禁用
- **生产日志**: 仅包含错误信息，确保生产环境不会输出过多日志影响性能

### 插件日志

插件中的日志也通过 logger 统一控制。插件会尊重其 `debug` 选项，但最终输出由 logger 配置决定：

```typescript
// vite.config.ts
createReactVintlPlugin({
  basePath: 'src/locales',
  debug: true  // 插件会使用 logger.debug() 输出日志
})
```

即使插件设置了 `debug: true`，如果 logger 的 `debug` 配置为 `false`，日志仍不会输出。

## 🐛 故障排除

### 类型在编辑器中不显示？

1. **等待自动同步** - 插件会自动更新类型文件并触发 TypeScript 服务器重新加载，通常几秒内生效
2. **手动重启 TypeScript 服务器** - 如果类型仍未更新，在编辑器中重启 TypeScript 服务器：
   - **VSCode**: `Cmd/Ctrl + Shift + P` → 输入 "TypeScript: Restart TS Server"
   - **WebStorm**: `File` → `Invalidate Caches...` → 选择 "Invalidate and Restart"
3. 检查插件是否在 `vite.config.ts` 中正确配置
4. 确保翻译文件位于正确的位置
5. 检查 `react-vintl-locales.d.ts` 文件是否存在且包含最新的类型定义

### 添加新字段后编辑器仍显示类型错误？

这是类型同步问题。插件会自动处理，但有时需要额外步骤：

1. **等待几秒钟** - 插件会在文件变化后自动更新类型并触发 TypeScript 服务器重新加载
2. **检查文件是否已更新** - 查看 `react-vintl-locales.d.ts` 文件，确认新字段已包含在类型定义中
3. **重启 TypeScript 服务器** - 如果类型文件已更新但编辑器仍显示错误，手动重启 TypeScript 服务器
4. **检查构建模式** - 在构建时，类型文件会自动更新，确保构建时类型检查通过
5. **查看插件日志** - 如果启用了 `debug: true`，检查控制台是否有类型更新相关的错误信息

**如果问题仍然存在：**
- 确保开发服务器正在运行（类型更新需要 HMR 支持）
- 检查文件权限，确保插件可以写入类型文件
- 尝试删除 `react-vintl-locales.d.ts` 文件，让插件重新生成

### 热重载不工作？

1. 检查插件选项中的 `hmr: true`
2. 验证文件路径是否正确
3. 重启开发服务器

### 参数插值不工作？

1. **检查参数格式** - 确保使用 `{{key}}` 格式
2. **验证参数传递** - 确保参数对象正确传递
3. **检查控制台警告** - 查看是否有参数验证错误
4. **测试简单插值** - 先测试 `{{name}}` 等简单格式
5. **检查嵌套对象** - 确保嵌套对象结构正确

### 格式化不生效？

1. **检查格式选项** - 确保格式选项拼写正确
2. **验证数据类型** - 确保传入的数据类型正确
3. **测试浏览器支持** - 某些格式化功能需要现代浏览器支持
4. **查看控制台错误** - 格式化失败时会回退到原始值

## 📄 许可证

MIT

## 🤝 贡献

欢迎贡献！请随时提交 Pull Request。

---

**由 gulibs 用 ❤️ 制作**