[note] react-intl 起步走(getting started
keywords: i18n
, Internationalization
, intl
, format
- react-intl @ Github
- API @ react-intl doc
- Components @ react-int doc
這篇文章主要說明如何透過 React Intl 來實作網頁上的 i18n,先備知識必須要已經基本會使用 React。
⚠️ 文章使用的是 react-intl @ 2.9,部分功能在 3.0 後不再支援
開始使用 react-intl
我們直接用 create-react-app 的頁面來做練習:
建立 React 專案
直接透過 create-react-app 建立 React 專案:
$ create-react-app react-intl-sandbox
$ cd react-intl-sandbox
安裝 react-intl
$ npm install react-intl
接著就可以透過 npm run start
啟動專案。
使用 IntlProvider
IntlProvider @ react-intl components
將 <IntlProvider>
包在最外層,讓所有內部 component 都可以存取到它提供的屬性與方法。這裡方便操作,把它多包成一個名為 Root 的 functional component:
取得使用者語系並帶入 IntlProvider
接著:
- 透過
navigator.language
取得使用者在瀏覽器上所使用的語系,並且將它代入 IntlProvider 的local
屬性中 - 為了讓語系變動後可以重新轉譯 React 元件,因此也將取得的語系帶入
key
屬性中(參考:dynamic language selection) - 若有需要可以定義
defaultLocale
屬性
這時候打開瀏覽器會看到錯誤訊息:
表示它載不到預設的地區資料。
載入需要的語系資料
Basic Internationalization Principles @ Format.js
在 react-intl 中已經定義好許多地區的語系資料,這些資料會定義某個語系是否有其父子語系的關係,例如 zh-TW
是在 zh-Hant
底下,而 zh-Hant
又在 zh
底下這種關係。除此之外,裡面還定義了關於「時間」、「複數型態」時要怎麼呈現的資訊。
關於各地區的語系,最標準的可以參考 BCP 47 所定義的 locale code 規格文件。
react-intl 所定義好的語系檔都在安裝好的套件內,路徑為 node_modules/react-intl/locale-data/
,裡面列出了各語系的定義:
例如說這裡我們可以載入英文、中文和日文的語系資料,並且透過 addLocaleData
將語系檔載入:
⚠️ 在 react-intl 3 之後不在支援
addLocaleData
的方法,而是直接使用原生的 Intl API,關於使用方式可以參考 Migrate to using native Intl APIs。
定義多語系字典檔
做好上述設定後,就可以來定義多語系用的字典檔。假設我們要做 i18n 的內容是範例頁面中的「Learn React」這個部分:
這時候就可以先定義這個字典檔。首先在 ./src
資料夾內再新增一個 i18n
的資料夾,裡面分別放入 en.js
, zh.js
, ja.js
:
接著分別定義每支字典檔的內容,這裡的 app.learn
可以視為 id
,之後的使用 react-intl
提供的方法或元件時,他會根據你提供的這個 id
來帶入不同的內容,而 { }
刮起來的 name
表示它是動態的變數:
// ./src/i18n/en.js
const en = { 'app.learn': 'Learn {name}' };
export default en;
// ./src/i18n/zh.js
const zh_TW = { 'app.learn': '學習 {name}' };
export default zh_TW;
// ./src/i18n/ja.js
const ja_JP = { 'app.learn': '学び {name}' };
export default ja_JP;
撰寫切換語言的功能
因為一開始使用的是 functional component,想要添加狀態(state)的話,可以匯入 useState
近來用:
// ./src/index.js
import React, { useState } from 'react';
// ...
const Root = () => {
// 使用 useState 定義 locale 這個 state
const [locale, setLocale] = useState(navigator.language);
return (
<IntlProvider
locale={locale}
key={locale}
defaultLocale="en"
>
<!-- 將 setLocale 的方法傳到 App 內 -->
<App setLocale={setLocale} />
</IntlProvider>
);
};
在 App.js 的地方,撰寫三個按鈕可以來切換 locale
的狀態:
// ./src/App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
// 從 props 取得從 index 傳入的 setLocale 方法
function App({ setLocale }) {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<div>
<!-- 建立三顆按鈕可以切換 local 的狀態 -->
<button onClick={() => setLocale('en')}>英文</button>
<button onClick={() => setLocale('zh-Hant')}>中文</button>
<button onClick={() => setLocale('ja')}>日文</button>
</div>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
這時候的畫面會像這樣:
文字訊息多語系
String Formatting Components @ react-intl
這裡說明的是最一般用來轉換不同語系字串的作法,react-intl 提供了: