FrontEnd

react-intl (Format.js) を使ってi18n対応

投稿日:2021年12月6日 更新日:

はじめに

最近、Reactを勉強しているので、しばらくはReactの記事を書いていきたいと思います! 今回は、Reactでi18n対応する方法について紹介します。

react-intlとは?

ReactやVue.jsなどで、i18n対応ができるパッケージです。総称してFormat.jsと呼ばれていますが、実際に使用するパッケージは react-intl になります。GithubのStart数も多く、人気のパッケージです。
https://formatjs.io/

react-intlの導入

まずは、create-react-appします。

次に、Format.jsを追加します。また、今回はCSSフレームワークとしてMUIを使用するので、併せて追加します。

使い方

IntlProviderの実装

react-intlは、Reactコンテキストとして実装されており、i18n対応したい箇所を <IntlProvider> コンポーネントで囲う必要があります。IntlProviderは、ロケールや翻訳メッセージなどを持ち、配下の <Formatted*> コンポーネントで使用されます。
一般的には、Reactコンポーネントのルートに近い位置に <IntlProvider> コンポーネントを置き、アプリケーション全体で使えるようにした方が良いそうなので、そのように実装してみます。

index.tsxを編集します。

IntlProviderに渡しているPropsについて説明します。

  • locale
    ja、enなどのロケールが入ります。今回は、 navigator.language から取得しているため、ブラウザの言語設定が入ります。後ほど説明する日時フォーマットは、ここのlocaleによって適切にフォーマットされます。
  • messages
    翻訳メッセージを渡します。今回は selectMessages() で、 navigator.language によってメッセージを切り替えています。メッセージ自体は、JSONファイルに定義して、importしています。

メッセージ定義

今回は、JSONファイルにメッセージを定義していきます。構造はフラットにする必要があるため、構造を示す場合には . などで区切ります。

src/lang/en.json

src/lang/ja.json

<Foramatted*>コンポーネントの使用

IntlProviderの配下で、実際にi18nしていくには、 <Formatted*> コンポーネントを使います。

メッセージ

先ほど定義したメッセージを表示させるには、 <FormattedMessage> を使用します。

「こんにちは、太郎さん!」と表示されました。
この他にも、様々なMessage Syntaxに対応しているので、よく使いそうなものを紹介します。

複数形対応

複数形を表現するには、 plural フォーマットを使用します。

翻訳メッセージ内に {key, plural, matches} という形式で表します。

  • key
    複数化を判断するための数値を受け取ります。
  • plural
    複数形フォーマットを指定するため、 plural を指定します。
  • mathces
    keyの値によって表示させたいメッセージを指定します。書式は 条件 {文言} です。条件には、次のようなものがあります。

    • one: 単数
    • other: 複数
    • =value: 特定の数値

英語や日本語以外では、上記以外の条件を使うこともあるようです。詳しくはこちらの公式リファレンスが参考になります。
https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format

日時

まず、日付を表示させてみます。

これで、「2021年11月30日(火)」と表示されました。プロパティを渡さなくすれば、表示させないようにすることもできます。
また、 year , weekday , month , day などのプロパティを全て渡さなければ、デフォルトである「2021/12/1」と表示されるようになります。

次に、時間を表示させてみます。

こちらは、「19:21:54」と表示されました。もし秒数が不要であれば、 second= を削除すれば表示されなくなります。(その場合、デフォルト設定と同じになるため、hour, minute, secondを全て削除しても構いません。)

<FormattedDate><FormattedTime> は、使用箇所でいちいち定義するより、いずれもラップしたコンポーネントを作り、アプリケーション全体で共通化した方が良いと思いました。日時のフォーマットは、アプリケーション全体で統一感を持たせた方が良いと思うためです。

タイムゾーンについて

<FormattedDate><FormattedTime> は、valueに渡されたDateオブジェクトをもとにフォーマットを行います。そのため、ISO8606形式の日付を Date.parse() でパースすれば、ブラウザのタイムゾーンに変換して表示させることができます。

UTC時間で0時を指定していますが、ブラウザで表示してみると「2021年1月1日(金) 9:00:00」と表示され、ブラウザのタイムゾーンに変換されていることが分かります。

ちなみに、Chromeでタイムゾーンを変更するには、Developer Toolsを開き、「…」からSensorsを開きます。Locationを変更してからリロードすると、タイムゾーンによって時刻の表示が変わることが確認できます。

数値(通貨など)

数値のフォーマットを行うには、 <FormattedNumber> を使います。
まず、通貨の表示をやってみます。

USDは「$ 10.00」、JPYは「\ 1,000」と表示されました。このように、通貨に合わせてフォーマットされます。

その他にも、 style="unit" とすることで、様々な単位の数値を出力するこどがてきます。

たとえば、上記の場合は「10 MB」と表示されます。その他にも様々な単位が用意されています。詳しくは下記のを参照してください。
https://formatjs.io/docs/polyfills/intl-numberformat#SupportedUnits

命令型APIの呼び出し

ここまでに紹介した、 Formatted** は Reactコンポーネントとして描画するほかに、命令型APIとしても同じ機能が用意されています。 useIntl フックが用意されているので、これを使います。

例えば、MUIのSnackbarでは、表示するメッセージをstringで渡す必要があります。そこで、 intl.formatMessage() を使うと、 <FormattedMessage> と同じ結果を得られます。
基本的には、 format** という関数名で、先ほど紹介したReactコンポーネントと同じ結果を得ることができます。

言語の変更

ここまでのサンプルでは、 navigator.language でブラウザの言語を取得していましたが、今度は言語をアプリケーション内で変更できるようにしたいと思います。
今回は、 IntlProvider をラップしたReact コンテキストを実装することで、localeやmessagesを切り替えできるようにしたいと思います。

まずは、React コンテキストから実装していきます。

まず、 const langs に言語を定義していきます。ここで定義したプロパティは、そのまま IntlProvider に渡すため、 IntlProvider のプロパティのインターフェイスに合わせておきます。
また、 switchLang 関数を公開することで、子コンポーネントから言語を切り替えることができるようになっています。 switchLang 関数では、指定されたlocaleを探し、 setLang しています。
そして、 <IntlProvider {...lang}> とすることで、選択された言語情報を渡し、変更があったときに再描画されるようにしています。

最後に、index.tsxを修正します。

先ほど作成した <IntlProviderWrapper> で、 <App /> を囲います。これで、アプリケーション全体で、どこからでも言語を変更できるようになりました。
それでは、さっそく言語を変更してみましょう。

先ほど公開した switchLang 関数を呼び出し、言語を変更することができました。

さいごに

react-intlを使うと、i18nだけでなく、日時や単位のフォーマットもできることが分かりました。

おすすめ書籍

Reactハンズオンラーニング 第2版 ―Webアプリケーション開発のベストプラクティス プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

blog-page_footer_336




blog-page_footer_336




-FrontEnd
-

執筆者:

免責事項

このブログは、記事上部に記載のある投稿日時点の一般的な情報を提供するものであり、投資等の勧誘・法的・税務上の助言を提供するものではありません。仮想通貨の投資・損益計算は複雑であり、個々の取引状況や法律の変更によって異なる可能性があります。ブログに記載された情報は参考程度のものであり、特定の状況に基づいた行動の決定には専門家の助言を求めることをお勧めします。当ブログの情報に基づいた行動に関連して生じた損失やリスクについて、筆者は責任を負いかねます。最新の法律や税務情報を確認し、必要に応じて専門家に相談することをお勧めします。


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

Vue.jsのコードをTypeScriptで書く

1 はじめに2 TypeScriptでの書き方2.1 定義2.2 data2.3 methods2.4 computed2.5 props2.6 emit2.7 lifecycle hooks2.8 ...

svelte

Svelteのチュートリアルをやってみた

1 はじめに2 Svelteとは?2.1 Svelteの特徴2.2 Write less code2.3 No Virtual DOM2.4 Truly reactive3 Svelteのシンタックス ...

Vue.js入門その3〜簡単にTODOアプリを作ってみたよ〜

はじめに 7/12 修正 記事下部にて、filterメソッドを使用している箇所がありましたが、forEachの方が適しているとご指摘がありましたので、修正しました。 以前Qiitaの方に投稿した記事で ...

Go言語

Go WebAssemblyでPromiseを使って非同期化してみた

1 はじめに2 Go WebAssemblyで非同期化のコード3 Promise化する4 おまけ5 さいごに6 おすすめ書籍 はじめに 先日WebAssemblyに入門して、実際に以下のチュートリアル ...

laravel logo

Inertia使ってみた①

1 はじめに2 Inertiaとは3 ルーティング4 LaravelからReactに値渡し5 レスポンス5.1 初回5.2 page object5.3 2回目以降5.4 リロード時6 さいごに7 お ...

フォロー

blog-page_side_responsive

2021年12月
 1234
567891011
12131415161718
19202122232425
262728293031  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。