
Hướng dẫn react-intl: Thiết lập quốc tế hóa React
Thiết lập FormatJS react-intl trong ứng dụng React bằng IntlProvider, FormattedMessage, useIntl, định dạng thông điệp ICU và dịch thuật tự động.
Bạn đang dùng react-i18next? Xem hướng dẫn react-i18next
Cài đặt react-intl
react-intl thuộc dự án FormatJS. Thư viện cung cấp component và hook React để định dạng chuỗi, số, ngày tháng và số nhiều theo tiêu chuẩn ICU MessageFormat.
npm install react-intlCấu hình IntlProvider
Bọc gốc ứng dụng bằng IntlProvider. Truyền ngôn ngữ đang hoạt động và một đối tượng messages phẳng. Sau đó, mọi component con đều có thể truy cập bản dịch qua FormattedMessage hoặc useIntl.
import React from 'react';
import ReactDOM from 'react-dom/client';
import { IntlProvider } from 'react-intl';
import App from './App';
import enMessages from './messages/en.json';
import deMessages from './messages/de.json';
const messages: Record<string, Record<string, string>> = {
en: enMessages,
de: deMessages,
};
// Detect locale from browser or your routing layer
const locale = navigator.language.split('-')[0] || 'en';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<IntlProvider locale={locale} messages={messages[locale] || messages.en}>
<App />
</IntlProvider>
</React.StrictMode>
);Tệp thông điệp
Tạo một tệp JSON cho mỗi ngôn ngữ. react-intl dùng trực tiếp cú pháp ICU MessageFormat: số nhiều, select và biến đều nằm ngay trong chuỗi thông điệp.
// messages/en.json
{
"app.greeting": "Hello, {name}!",
"nav.home": "Home",
"nav.about": "About",
"nav.settings": "Settings",
"cart.itemCount": "{count, plural, one {# item} other {# items}} in your cart"
}
// messages/de.json
{
"app.greeting": "Hallo, {name}!",
"nav.home": "Startseite",
"nav.about": "Über uns",
"nav.settings": "Einstellungen",
"cart.itemCount": "{count, plural, one {# Artikel} other {# Artikel}} in Ihrem Warenkorb"
}Dùng bản dịch trong component
react-intl cung cấp hai API chính: component FormattedMessage để kết xuất JSX đã dịch và hook useIntl để truy cập theo lối mệnh lệnh (placeholder, nhãn aria, định dạng bằng mã).
Component FormattedMessage
Dùng FormattedMessage để khai báo bản dịch trong JSX. Truyền ID thông điệp và các giá trị nội suy. Component sẽ kết xuất trực tiếp chuỗi đã dịch.
import { FormattedMessage } from 'react-intl';
function Greeting({ userName }: { userName: string }) {
return (
<div>
<h1>
<FormattedMessage
id="app.greeting"
values={{ name: userName }}
/>
</h1>
<nav>
<a href="/"><FormattedMessage id="nav.home" /></a>
<a href="/about"><FormattedMessage id="nav.about" /></a>
</nav>
</div>
);
}Hook useIntl
Dùng useIntl() khi cần chuỗi đã dịch dưới dạng giá trị thuần, chẳng hạn placeholder của ô nhập, aria-label, document.title hoặc khi truyền chuỗi cho API ngoài React. Hook này cũng cung cấp formatNumber, formatDate và formatRelativeTime.
import { useIntl } from 'react-intl';
function SearchBar() {
const intl = useIntl();
return (
<input
type="search"
placeholder={intl.formatMessage({ id: 'search.placeholder' })}
aria-label={intl.formatMessage({ id: 'search.ariaLabel' })}
/>
);
}
// useIntl also gives you formatNumber, formatDate, formatRelativeTime:
function PriceTag({ amount, currency }: { amount: number; currency: string }) {
const intl = useIntl();
return (
<span>{intl.formatNumber(amount, { style: 'currency', currency })}</span>
);
}Văn bản đa dạng thức (HTML trong bản dịch)
Nhúng JSX vào bản dịch bằng thẻ kiểu XML trong chuỗi thông điệp. Truyền trình xử lý thẻ qua prop values để kết xuất liên kết, chữ đậm hoặc bất kỳ component React nào trong thông điệp đã dịch.
import { FormattedMessage } from 'react-intl';
// Message: "By signing up, you agree to our <link>Terms</link>."
// Key: "signup.terms"
// Value: "By signing up, you agree to our <link>Terms</link>."
function SignUp() {
return (
<FormattedMessage
id="signup.terms"
values={{
link: (chunks) => <a href="/terms" className="underline">{chunks}</a>,
}}
/>
);
}Trích xuất thông điệp bằng @formatjs/cli
FormatJS cung cấp CLI tự động trích xuất ID thông điệp từ mã nguồn vào tệp JSON. Nhờ đó, tệp thông điệp luôn đồng bộ với component mà không cần theo dõi thủ công.
# Install the CLI
npm install -g @formatjs/cli
# Extract messages from source code into a JSON file
formatjs extract 'src/**/*.tsx' --out-file messages/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'
# Or use explicit IDs (recommended):
formatjs extract 'src/**/*.tsx' --out-file messages/en.json
# Compile messages for production (optional, improves perf)
formatjs compile messages/en.json --out-file compiled/en.json
formatjs compile messages/de.json --out-file compiled/de.jsonSố nhiều và ICU select
react-intl dùng trực tiếp ICU MessageFormat. Số nhiều, select theo giới tính và định dạng lồng nhau đều nằm ngay trong chuỗi thông điệp, không cần quy ước hậu tố hay khóa riêng.
// ICU MessageFormat syntax — react-intl uses this natively
// English
{
"cart.itemCount": "{count, plural, one {# item} other {# items}} in your cart",
"inbox.unread": "You have {count, plural, =0 {no unread messages} one {# unread message} other {# unread messages}}"
}
// Arabic — 6 plural forms
{
"cart.itemCount": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}} في سلتك"
}
// Japanese — 1 form (other)
{
"cart.itemCount": "カートに{count}個の商品があります"
}ICU select cho giới tính và vai trò
Dùng cú pháp ICU select cho bản dịch phụ thuộc vào ngữ cảnh như giới tính, vai trò người dùng hoặc giá trị trạng thái. Biểu thức select chọn biến thể phù hợp theo giá trị được cung cấp.
// Gender-dependent messages using ICU select
{
"user.greeting": "{gender, select, male {He} female {She} other {They}} liked your post.",
"user.invitation": "{role, select, admin {You can manage all settings.} editor {You can edit content.} other {You can view content.}}"
}
// Usage:
<FormattedMessage
id="user.greeting"
values={{ gender: user.gender }}
/>Tự động kiểm soát chất lượng bản dịch
Lỗi thường gặp
Phụ thuộc quá nhiều vào defaultMessage
Đối tượng lồng nhau thay vì khóa phẳng
IntlProvider gây kết xuất lại
Thiếu IntlProvider trong kiểm thử
Cấu trúc tệp khuyên dùng
my-react-app/
├── messages/
│ ├── en.json # Source of truth (English)
│ ├── de.json # German
│ ├── ja.json # Japanese
│ └── es.json # Spanish
├── compiled/ # Optional: compiled messages for prod
│ ├── en.json
│ └── ...
├── src/
│ ├── main.tsx # App entry with IntlProvider
│ ├── App.tsx
│ └── components/
│ ├── Greeting.tsx # Uses FormattedMessage
│ └── SearchBar.tsx # Uses useIntl
└── package.jsonDùng thử i18n Agent ngay
Thả tệp bản dịch của bạn vào đây
JSON, YAML, PO, XML, CSV, Markdown, Properties
hoặc nhấp để duyệt
Ngôn ngữ đích
Dự phòng ngôn ngữ với react-intl-locale-chain
Khi thiếu khóa bản dịch trong một ngôn ngữ vùng như pt-BR, react-intl chuyển thẳng sang ngôn ngữ mặc định thay vì kiểm tra ngôn ngữ cha pt trước.
npm install react-intl-locale-chain<LocaleChainProvider
fallbacks={{
'pt-BR': ['pt', 'en'],
'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
}}
defaultLocale="en"
>
<App />
</LocaleChainProvider>Xem Hướng dẫn dự phòng ngôn ngữ để biết danh sách đầy đủ các framework được hỗ trợ và 75 chuỗi tích hợp sẵn. Learn more →