
Panduan react-intl: Penyiapan Internasionalisasi React
Siapkan react-intl dari FormatJS dalam aplikasi React dengan IntlProvider, FormattedMessage, useIntl, format pesan ICU, dan penerjemahan otomatis.
Menggunakan react-i18next? Lihat panduan react-i18next kami
Instal react-intl
react-intl adalah bagian dari proyek FormatJS. Library ini menyediakan komponen dan hook React untuk memformat string, angka, tanggal, dan bentuk jamak menggunakan standar ICU MessageFormat.
npm install react-intlKonfigurasikan IntlProvider
Bungkus aplikasi dengan IntlProvider di root. Teruskan bahasa aktif dan objek messages datar. Setiap komponen di bawahnya kemudian dapat mengakses terjemahan melalui FormattedMessage atau 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>
);File Pesan
Buat satu file JSON per bahasa. react-intl menggunakan sintaks ICU MessageFormat secara native—bentuk jamak, select, dan variabel semuanya dinyatakan inline dalam string pesan.
// 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"
}Gunakan Terjemahan dalam Komponen
react-intl menyediakan dua API utama: komponen FormattedMessage untuk merender JSX terjemahan dan hook useIntl untuk akses imperatif (placeholder, label aria, pemformatan programatis).
Komponen FormattedMessage
Gunakan FormattedMessage untuk terjemahan deklaratif dalam JSX. Teruskan ID pesan dan nilai interpolasi apa pun. Komponen merender string terjemahan secara langsung.
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
Gunakan useIntl() saat memerlukan string terjemahan sebagai nilai biasa—untuk placeholder input, label aria, document.title, atau saat meneruskan string ke API non-React. Hook juga menyediakan formatNumber, formatDate, dan 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>
);
}Teks Kaya (HTML dalam Terjemahan)
Sematkan JSX dalam terjemahan menggunakan tag seperti XML di string pesan. Teruskan penangan tag melalui prop values untuk merender tautan, teks tebal, atau komponen React apa pun di dalam pesan terjemahan.
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>,
}}
/>
);
}Ekstraksi Pesan dengan @formatjs/cli
FormatJS menyediakan CLI untuk mengekstrak ID pesan secara otomatis dari kode sumber ke file JSON. Ini memastikan file pesan tetap sinkron dengan komponen tanpa pencatatan manual.
# 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.jsonBentuk Jamak dan ICU Select
react-intl menggunakan ICU MessageFormat secara native. Bentuk jamak, select berbasis gender, dan pemformatan bertingkat semuanya dinyatakan langsung dalam string pesan—tanpa konvensi sufiks atau kunci terpisah.
// 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 untuk Gender dan Peran
Gunakan sintaks ICU select untuk terjemahan bergantung konteks seperti gender, peran pengguna, atau nilai status. Ekspresi select memilih varian yang benar berdasarkan nilai yang diberikan.
// 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 }}
/>Otomatiskan Kualitas Terjemahan
Kesalahan Umum
Terlalu Mengandalkan defaultMessage
Objek Bertingkat, Bukan Kunci Datar
IntlProvider Menyebabkan Render Ulang
IntlProvider Hilang dalam Pengujian
Struktur File yang Disarankan
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.jsonCoba i18n Agent Sekarang
Lepaskan file terjemahan Anda di sini
JSON, YAML, PO, XML, CSV, Markdown, Properties
atau klik untuk menjelajahi
Bahasa target
Fallback Bahasa dengan react-intl-locale-chain
Saat kunci terjemahan tidak ada dalam bahasa regional seperti pt-BR, react-intl langsung beralih ke bahasa default alih-alih memeriksa bahasa induk pt terlebih dahulu.
npm install react-intl-locale-chain<LocaleChainProvider
fallbacks={{
'pt-BR': ['pt', 'en'],
'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
}}
defaultLocale="en"
>
<App />
</LocaleChainProvider>Lihat Panduan Fallback Bahasa kami untuk daftar lengkap framework yang didukung dan 75 rantai bawaan. Learn more →