
คู่มือ react-intl : ตั้งค่า React ให้รองรับหลายภาษา
ตั้งค่า FormatJS react-intl ในแอป React ด้วย IntlProvider, FormattedMessage, useIntl รูปแบบข้อความ ICU และการแปลอัตโนมัติ
กำลังใช้ react-i18next อยู่ใช่ไหม? ดูคู่มือ react-i18next ของเรา
ติดตั้ง react-intl
react-intl เป็นส่วนหนึ่งของโปรเจกต์ FormatJS มีคอมโพเนนต์และฮุก React สำหรับจัดรูปแบบข้อความ ตัวเลข วันที่ และพหูพจน์ด้วยมาตรฐาน ICU MessageFormat
npm install react-intlกำหนดค่า IntlProvider
ครอบแอปด้วย IntlProvider ที่ราก ส่งภาษาปัจจุบันและออบเจ็กต์ messages แบบแบน จากนั้นคอมโพเนนต์ทุกตัวข้างใต้จะเข้าถึงคำแปลผ่าน FormattedMessage หรือ 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>
);ไฟล์ข้อความ
สร้างไฟล์ JSON หนึ่งไฟล์ต่อภาษา react-intl ใช้ไวยากรณ์ ICU MessageFormat โดยตรง โดยเขียนพหูพจน์ select และตัวแปรในบรรทัดเดียวกับข้อความ
// 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"
}ใช้คำแปลในคอมโพเนนต์
react-intl มี API หลักสองแบบ ได้แก่ คอมโพเนนต์ FormattedMessage สำหรับเรนเดอร์ JSX ที่แปลแล้ว และฮุก useIntl สำหรับการเข้าถึงแบบสั่งงาน เช่น ตัวยึดตำแหน่ง ป้าย aria และการจัดรูปแบบด้วยโปรแกรม
คอมโพเนนต์ FormattedMessage
ใช้ FormattedMessage สำหรับคำแปลแบบประกาศใน JSX ส่ง ID ข้อความและค่าการแทรก ระบบจะเรนเดอร์ข้อความที่แปลแล้วโดยตรง
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>
);
}ฮุก useIntl
ใช้ useIntl() เมื่อต้องการข้อความที่แปลแล้วเป็นค่าธรรมดา เช่น ตัวยึดตำแหน่งอินพุต aria-label, document.title หรือเมื่อส่งข้อความให้ API ที่ไม่ใช่ React นอกจากนี้ยังมี formatNumber, formatDate และ 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>
);
}ข้อความที่มีรูปแบบสมบูรณ์ (HTML ในคำแปล)
ฝัง JSX ในคำแปลด้วยแท็กคล้าย XML ในข้อความ ส่งตัวจัดการแท็กผ่าน prop values เพื่อเรนเดอร์ลิงก์ ข้อความตัวหนา หรือคอมโพเนนต์ React ใดก็ได้ภายในข้อความที่แปลแล้ว
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>,
}}
/>
);
}การแยกข้อความด้วย @formatjs/cli
FormatJS มี CLI สำหรับแยก ID ข้อความจากซอร์สโค้ดลงในไฟล์ JSON โดยอัตโนมัติ วิธีนี้ทำให้ไฟล์ข้อความซิงค์กับคอมโพเนนต์โดยไม่ต้องบันทึกด้วยตนเอง
# 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.jsonพหูพจน์และ ICU Select
react-intl ใช้ ICU MessageFormat โดยตรง พหูพจน์ select ตามเพศ และการจัดรูปแบบซ้อนล้วนเขียนในข้อความโดยตรง ไม่ต้องใช้ข้อกำหนดส่วนต่อท้ายหรือคีย์แยก
// 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 สำหรับเพศและบทบาท
ใช้ไวยากรณ์ ICU select สำหรับคำแปลตามบริบท เช่น เพศ บทบาทผู้ใช้ หรือค่าสถานะ นิพจน์ select จะเลือกรูปแบบที่ถูกต้องตามค่าที่ได้รับ
// 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 }}
/>ทำให้คุณภาพการแปลเป็นอัตโนมัติ
ข้อผิดพลาดที่พบบ่อย
พึ่ง defaultMessage มากเกินไป
ใช้ออบเจ็กต์ซ้อนแทนคีย์แบบแบน
IntlProvider ทำให้เรนเดอร์ใหม่
ไม่มี IntlProvider ในการทดสอบ
โครงสร้างไฟล์ที่แนะนำ
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.jsonแปลรายการต่อไปนี้ได้ด้วย :
ลองใช้ i18n Agent ตอนนี้
ลากและวางไฟล์แปลของคุณที่นี่
JSON, YAML, PO, XML, CSV, Markdown, Properties
หรือคลิกเพื่อเลือกไฟล์
ภาษาเป้าหมาย
การใช้ภาษาสำรองด้วย react-intl-locale-chain
เมื่อไม่มีคีย์คำแปลในภาษาตามภูมิภาคอย่าง pt-BR react-intl จะข้ามไปใช้ภาษาเริ่มต้นทันทีแทนที่จะตรวจภาษาหลัก pt ก่อน
npm install react-intl-locale-chain<LocaleChainProvider
fallbacks={{
'pt-BR': ['pt', 'en'],
'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
}}
defaultLocale="en"
>
<App />
</LocaleChainProvider>ดูคู่มือการใช้ภาษาสำรองของเราสำหรับรายการเฟรมเวิร์กที่รองรับทั้งหมดและลำดับสำเร็จรูป 75 รายการ Learn more →