i18nについて
React Ariaの実装読むぞ
この記事は他サイトから移行したものです。
この記事は React Aria の実装読むぞ - Qiita Advent Calendar 2024 の 21 日目の記事です。
こんにちは、フロントエンドエンジニアの mehm8128 です。 今日は i18n について書いていきます。
React Aria の i18n #
React Aria の i18n についてはこのページにまとめられています。 https://react-spectrum.adobe.com/react-aria/internationalization.html
React Aria では主に、文字列の翻訳、日付と数値のフォーマット、RTL がサポートされています。
そしてこれらはブラウザに組み込まれている Intl オブジェクトの各 API を利用して実装されています。
Intl については saji さんの 1 人アドベントカレンダーでまとめられているので、適宜参照しながら解説していきます。
Intl の全体像についてはこちらの記事をご覧ください。 https://zenn.dev/sajikix/articles/intl-advent-calendar-24-01
文字列の翻訳 #
useLocalizedStringFormatterを用いて現在の locale に基づいて翻訳されたテキストを取得できます。ここでは Intl は使われていません多分。
例えばuseNumberFieldだと、+/-ボタンに振られているラベルが翻訳されています。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/numberfield/src/useNumberField.ts#L93 https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/numberfield/src/useNumberField.ts#L285
en-US.jsonとja-JP.jsonを見てみます。IncreaseとDecreaseをそれぞれ「拡大」と「縮小」と訳すのはかなり微妙な気もするのですが、こんな感じに翻訳されています。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/numberfield/intl/en-US.json#L1-L6
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/numberfield/intl/ja-JP.json#L1-L5
useLocalizedStringFormatter関数内ではuseLocaleで現在の locale を取得し、その locale のテキストに翻訳するためのformatメソッドを含むLocalizedStringFormatterオブジェクトを返しています。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/i18n/src/useLocalizedStringFormatter.ts#L40-L44
useColorPickerでも、同じく翻訳用のパッケージが利用されていました。
https://portfolio.hm8128.me/adv2024-reactaria/day15
数値のフォーマット #
再びuseNumberFieldの話です。useNumberFieldでは様々な数値のフィーマットに対応していて、ブログ記事にまとめられています。
Intl.NumberFormatを用いて小数点や%や通貨、単位などのフォーマットをいい感じにしています。
Intl.NumberFormatについてはここらへんの記事を読みましょう。
https://zenn.dev/sajikix/articles/intl-advent-calendar-24-13
https://zenn.dev/sajikix/articles/intl-advent-calendar-24-14
https://zenn.dev/sajikix/articles/intl-advent-calendar-24-15
RTL #
アラビア語など、右から左に文字を書く言語圏の locale の場合、画面内の要素もミラーリングする必要があります。 ただし、React Aria はスタイリングにまでは責任を持っていないので、React Aria は主にキーボード操作などのインタラクション部分で RTL サポートをしています。
useLocaleからdirectionというltr | rtlの union 型の値を取得し、その値に応じてインタラクションの方向を変化させます。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/i18n/src/context.tsx#L54-L58
例えばuseTabListの場合、directionをTabsKeyboardDelegateというオブジェクトのコンストラクタに渡しています。
TabsKeyboardDelegateはこれを受け取り、flipDirectionを定義するのに使います。flipDirectionはtrueのときにキーボード操作を反転させます。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/tabs/src/TabsKeyboardDelegate.ts#L21-L26
getKeyLeftOfという関数では引数のkeyの 1 つ左のkeyを取得しますが、通常時(direction = ltrのとき)は 1 つ左というのは 1 つ前のkeyですが、flipDirection時には 1 つ左は 1 つ次のkeyになるので(見た目がミラーリングされても ← キーを押したときには左に移動する、みたいになっています)、getNextKey関数を使用しています。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/tabs/src/TabsKeyboardDelegate.ts#L28-L40
Typeahead #
useListBoxやuseGridList、useMenuでは Typeahead が実装されています。
useListBoxの記事で軽く言及していました。が、Typeahead についての説明が抜けていたので説明すると、リストにフォーカスしているときに頭文字を入力するとその文字から始まるリストアイテムにフォーカスを移動できるというものです。
これはuseCollatorを用いて実装されていて、内部でIntl.Collatorを使っています。
Intl.Collatorについてはこちらの記事をご覧ください。
https://zenn.dev/sajikix/articles/intl-advent-calendar-24-19
上記の 3 つの hooks で共通で使われているuseSelectableListでは、ここでuseCollatorを用いてcollatorを取得し、ListKeyboardDelegateオブジェクトのコンストラクタに渡しています。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/selection/src/useSelectableList.ts#L62-L73
ListKeyboardDelegateはこれを受け取り、getKeyForSearchでリストアイテムの検索に用いてます。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/selection/src/ListKeyboardDelegate.ts#L269-L290
日付のフォーマット #
日付も地域によって様々なフォーマットがあるので、フォーマットされています。詳しくは明日の記事で書いたり書かなかったりするのですが、useDateFormatterという hook が提供されていて、その中でIntl.DateTimeFormatを利用しています。
useDateSegmentではここらへんで使われています。
https://github.com/adobe/react-spectrum/blob/50c7ada5d1880a174b6b6d3f43e8d90ee9bd4ad8/packages/%40react-aria/datepicker/src/useDateSegment.ts#L42-L54
日付についての公式ブログ記事はこちらです。 https://react-spectrum.adobe.com/blog/date-and-time-pickers-for-all.html
Intl.DateTimeFormatについてはここらへんの記事を読むといいです。
https://zenn.dev/sajikix/articles/intl-advent-calendar-24-07
https://zenn.dev/sajikix/articles/intl-advent-calendar-24-08
https://zenn.dev/sajikix/articles/intl-advent-calendar-24-09
まとめ #
明日の担当は @mehm8128 さんで、DateField についての記事です。お楽しみにー