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

被折叠的 条评论
为什么被折叠?



