react-i18next+i18next-icu使用详解

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

1. 安装

npm install react-i18next i18next i18next-icu
# 或者
yarn add react-i18next i18next i18next-icu

2. 基础配置

创建 i18n 配置文件

// 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 应用中使用

在入口文件中引入

// 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(推荐)

// 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 功能

嵌套格式

// 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}
        }}
      }`
    }
  }
};
// 在组件中使用
const AdvancedExample = () => {
  const { t } = useTranslation();
  
  return (
    <div>
      <p>{t('advancedExample', { gender: 'male', count: 5 })}</p>
      <p>{t('advancedExample', { gender: 'female', count: 1 })}</p>
    </div>
  );
};

自定义格式

// 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

按命名空间组织资源

// 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;

资源文件示例

// 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}"
}
// locales/en/user.json
{
  "profile": "User Profile",
  "settings": "Settings",
  "logout": "Logout"
}

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

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. 语言检测

// 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. 最佳实践

错误处理

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>
  );
};

加载状态处理

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

9. 完整示例

// 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 可以提供强大的国际化功能,支持复杂的消息格式、复数、选择、日期时间格式化等高级特性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值