react-i18next+i18next-icu使用详解

i18next-icu 是一个强大的 ICU 消息格式插件,提供了更丰富的国际化功能,包括复数、选择、格式等。

1. 安装

bash 复制代码
npm install react-i18next i18next i18next-icu
# 或者
yarn add react-i18next i18next i18next-icu

2. 基础配置

创建 i18n 配置文件

javascript 复制代码
// i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import ICU from 'i18next-icu';

// ICU 实例
const icu = new ICU();

i18n
  .use(icu)
  .use(initReactI18next)
  .init({
    resources: {
      en: {
        translation: {
          // 基础翻译
          welcome: "Welcome, {name}!",
          
          // 复数形式
          messageCount: `You have {count, plural,
            =0 {no messages}
            =1 {one message}
            other {# messages}
          }`,
          
          // 选择形式
          genderMessage: `{gender, select,
            male {He}
            female {She}
            other {They}
          } will respond shortly.`,
          
          // 数字格式
          price: "Price: {price, number, USD}",
          
          // 日期格式
          currentDate: "Today is {date, date, medium}",
          
          // 时间格式
          currentTime: "Now is {time, time, short}",
        }
      },
      zh: {
        translation: {
          welcome: "欢迎, {name}!",
          messageCount: `您有 {count, plural,
            =0 {没有消息}
            =1 {一条消息}
            other {# 条消息}
          }`,
          genderMessage: `{gender, select,
            male {他}
            female {她}
            other {他们}
          }会尽快回复。`,
          price: "价格: {price, number, CNY}",
          currentDate: "今天是 {date, date, medium}",
          currentTime: "现在是 {time, time, short}",
        }
      }
    },
    lng: "en", // 默认语言
    fallbackLng: "en",
    interpolation: {
      escapeValue: false, // React 已经处理了 XSS
    }
  });

export default i18n;

3. 在 React 应用中使用

在入口文件中引入

javascript 复制代码
// index.js 或 App.js
import React from 'react';
import ReactDOM from 'react-dom';
import './i18n'; // 引入 i18n 配置
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

使用 Hooks(推荐)

jsx 复制代码
// MyComponent.jsx
import React from 'react';
import { useTranslation, Trans } from 'react-i18next';

const MyComponent = () => {
  const { t, i18n } = useTranslation();

  const changeLanguage = (lng) => {
    i18n.changeLanguage(lng);
  };

  const user = {
    name: "John",
    messageCount: 5,
    gender: "male",
    price: 99.99,
    date: new Date(),
    time: new Date()
  };

  return (
    <div>
      {/* 基础翻译 */}
      <h1>{t('welcome', { name: user.name })}</h1>
      
      {/* 复数形式 */}
      <p>{t('messageCount', { count: user.messageCount })}</p>
      
      {/* 选择形式 */}
      <p>{t('genderMessage', { gender: user.gender })}</p>
      
      {/* 数字格式 */}
      <p>{t('price', { price: user.price })}</p>
      
      {/* 日期时间格式 */}
      <p>{t('currentDate', { date: user.date })}</p>
      <p>{t('currentTime', { time: user.time })}</p>
      
      {/* 语言切换 */}
      <button onClick={() => changeLanguage('en')}>English</button>
      <button onClick={() => changeLanguage('zh')}>中文</button>
      
      {/* 使用 Trans 组件处理复杂翻译 */}
      <Trans i18nKey="complexMessage">
        This is a <strong>complex</strong> message with <em>HTML</em> elements.
      </Trans>
    </div>
  );
};

export default MyComponent;

4. 高级 ICU 功能

嵌套格式

javascript 复制代码
// i18n.js 资源定义
const resources = {
  en: {
    translation: {
      advancedExample: `{gender, select,
        male {{count, plural,
          =0 {He has no messages}
          =1 {He has one message}
          other {He has # messages}
        }}
        female {{count, plural,
          =0 {She has no messages}
          =1 {She has one message}
          other {She has # messages}
        }}
        other {They have {count, plural,
          =0 {no messages}
          =1 {one message}
          other {# messages}
        }}
      }`
    }
  }
};
jsx 复制代码
// 在组件中使用
const AdvancedExample = () => {
  const { t } = useTranslation();
  
  return (
    <div>
      <p>{t('advancedExample', { gender: 'male', count: 5 })}</p>
      <p>{t('advancedExample', { gender: 'female', count: 1 })}</p>
    </div>
  );
};

自定义格式

javascript 复制代码
// i18n.js - 扩展配置
i18n
  .use(ICU)
  .use(initReactI18next)
  .init({
    // ... 其他配置
    interpolation: {
      format: (value, format, lng) => {
        if (value instanceof Date) {
          return new Intl.DateTimeFormat(lng, {
            year: 'numeric',
            month: 'long',
            day: 'numeric'
          }).format(value);
        }
        if (format === 'uppercase') {
          return value.toString().toUpperCase();
        }
        return value;
      }
    }
  });

5. 文件结构组织

推荐的文件结构

复制代码
src/
  i18n/
    index.js          # i18n 配置
    locales/
      en/
        common.json
        user.json
        product.json
      zh/
        common.json
        user.json
        product.json

按命名空间组织资源

javascript 复制代码
// i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import ICU from 'i18next-icu';
import Backend from 'i18next-http-backend'; // 可选:从服务器加载

const icu = new ICU();

i18n
  .use(ICU)
  .use(Backend) // 使用后端加载
  .use(initReactI18next)
  .init({
    lng: 'en',
    fallbackLng: 'en',
    ns: ['common', 'user', 'product'], // 命名空间
    defaultNS: 'common',
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json', // 资源文件路径
    },
    interpolation: {
      escapeValue: false,
    }
  });

export default i18n;

资源文件示例

json 复制代码
// locales/en/common.json
{
  "welcome": "Welcome, {name}!",
  "messageCount": "You have {count, plural, =0 {no messages} =1 {one message} other {# messages}}",
  "currentDate": "Today is {date, date, full}"
}
json 复制代码
// locales/en/user.json
{
  "profile": "User Profile",
  "settings": "Settings",
  "logout": "Logout"
}

6. 在组件中使用命名空间

jsx 复制代码
import React from 'react';
import { useTranslation } from 'react-i18next';

const UserProfile = () => {
  // 使用特定命名空间
  const { t } = useTranslation('user');
  
  // 使用多个命名空间
  const { t: tCommon } = useTranslation('common');
  
  return (
    <div>
      <h1>{t('profile')}</h1>
      <p>{tCommon('welcome', { name: 'John' })}</p>
      <button>{t('logout')}</button>
    </div>
  );
};

export default UserProfile;

7. 语言检测

javascript 复制代码
// i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import ICU from 'i18next-icu';
import LanguageDetector from 'i18next-browser-languagedetector';

const icu = new ICU();

i18n
  .use(ICU)
  .use(LanguageDetector) // 自动检测语言
  .use(initReactI18next)
  .init({
    detection: {
      order: ['localStorage', 'navigator', 'htmlTag'],
      caches: ['localStorage']
    },
    // ... 其他配置
  });

8. 最佳实践

错误处理

jsx 复制代码
const SafeTranslation = () => {
  const { t, i18n } = useTranslation();
  
  // 检查翻译是否存在
  const safeTranslate = (key, options) => {
    if (i18n.exists(key)) {
      return t(key, options);
    }
    return `[Missing translation: ${key}]`;
  };
  
  return (
    <div>
      <p>{safeTranslate('someKey', { value: 123 })}</p>
    </div>
  );
};

加载状态处理

jsx 复制代码
const MyComponent = () => {
  const { t, ready } = useTranslation();
  
  if (!ready) {
    return <div>Loading translations...</div>;
  }
  
  return (
    <div>
      <h1>{t('welcome')}</h1>
    </div>
  );
};

9. 完整示例

jsx 复制代码
// App.jsx
import React from 'react';
import { useTranslation } from 'react-i18next';
import './App.css';

const App = () => {
  const { t, i18n } = useTranslation();
  
  const userData = {
    name: "Alice",
    messageCount: 3,
    gender: "female",
    balance: 1234.56,
    lastLogin: new Date('2023-12-01'),
    membershipLevel: "premium"
  };

  const changeLanguage = (lng) => {
    i18n.changeLanguage(lng);
  };

  return (
    <div className="App">
      <header>
        <h1>{t('welcome', { name: userData.name })}</h1>
        <div className="language-switcher">
          <button onClick={() => changeLanguage('en')}>EN</button>
          <button onClick={() => changeLanguage('zh')}>中文</button>
        </div>
      </header>
      
      <main>
        <section>
          <h2>{t('userInfo')}</h2>
          <p>{t('messageCount', { count: userData.messageCount })}</p>
          <p>{t('genderGreeting', { gender: userData.gender })}</p>
          <p>{t('accountBalance', { balance: userData.balance })}</p>
          <p>{t('lastLogin', { date: userData.lastLogin })}</p>
          
          {/* 复杂嵌套示例 */}
          <p>{t('membershipStatus', { 
            level: userData.membershipLevel,
            messages: userData.messageCount 
          })}</p>
        </section>
      </main>
    </div>
  );
};

export default App;

这样配置后,react-i18next 配合 i18next-icu 可以提供强大的国际化功能,支持复杂的消息格式、复数、选择、日期时间格式化等高级特性。

相关推荐
彭于晏爱编程2 小时前
🌹🌹🌹bro,AntD 6.0.0 来了
前端
1024小神2 小时前
Electron实现多tab页案例,BrowserView/iframe/webview不同方式的区别
前端·javascript·electron
Amos_Web2 小时前
Rust实战(四):数据持久化、告警配置与Web API —— 构建监控系统的功能闭环
前端·后端·rust
java水泥工2 小时前
基于Echarts+HTML5可视化数据大屏展示-物流大数据展示
大数据·前端·echarts·html5·可视化大屏
U***e632 小时前
Vue自然语言
前端·javascript·vue.js
用户761736354012 小时前
浏览器渲染原理
前端·浏览器
拉不动的猪2 小时前
Vue 跨组件通信底层:provide/inject 原理与实战指南
前端·javascript·面试
得物技术2 小时前
从数字到版面:得物数据产品里数字格式化的那些事
前端·数据结构·数据分析
用户6600676685392 小时前
用 Symbol 解决多人协作中的对象属性冲突实战
前端·javascript