Storybookにアイコンでのロケール変更機能を追加する

React + Next.js で、多言語対応したアプリケーションを開発している。

日本語から、英語などのラテン文字で記述する言語に切り替えた場合、文字が長くなり、レイアウトが崩れることがあるため、各言語でのレイアウトを簡潔に確認したい。

アプリケーション側にロケール切り替え機能を用意しているが、デザイナーなど非エンジニアでも確認しやすいよう、Storybookにロケール切り替えアイコンを追加する方法を調べたのでメモ。

環境

名前 バージョン
React 18.2.0
Next.js 12.1.6
Storybook 6.5.13
Storybook Addon Next 1.6.10

Storybookへのアイコン追加方法

Storybookに、ロケール切り替えアイコンを追加したい。Storybook Addon Contextsstorybook-addon-localeなどの拡張機能も見つかったが、公式ガイドのToolbars & globalsに、アイコン追加方法の記載があった。

.storybook/preview.jsglobalTypes を宣言するだけで、アイコンを追加できる。 globalTypes は、ストーリー内では context.globals として参照可能。

また、Advanced usageに、そのものズバリなロケール切り替えのアイコン追加例が記載されている。

storybook.js.org

今回のユースケースであれば、 globalTypes で十分なため、この方法を使用。

toolbar.iconで指定可能な文字列

以下の What icons are available for my toolbar or my addon? に文字列の一覧、および実際にアイコンを表示するStorybookへのリンクがある。

storybook.js.org

記事作成時点でのStorybookへのリンクはこちら

ロケールのNext.jsアプリケーションへの反映

Next.jsアプリケーションでStorybookを扱う際の問題を一括で対応してくれるアドオン、Storybook Addon Nextを使用している。

storybook.js.org

Next.jsではロケールを参照するのに useRouter を用いるが、Storybook Addon Nextを用いるとRouterをモックしてくれる。

上記リンクの「Default Router」に記載があるが、モックされたRouterのlocaleは context?.globals?.locale を参照しているため、 globalTypeslocale を変更できるようにすればいい。

const defaultRouter = {
  locale: context?.globals?.locale,
  ...
}

ロケール切り替えアイコンの設定

.storybook/preview.js に、以下を追加。

export const globalTypes = {
  locale: {
    name: 'Locale',
    description: 'Change locale', // アイコンホバー時に表示
    defaultValue: 'ja-JP',
    toolbar: {
      icon: 'globe',
      items: [
        { value: 'ja-JP', right: 'ja-JP', title: '日本語' },
        { value: 'en-US', right: 'en-US', title: 'American English' },
        { value: 'en-GB', right: 'en-GB', title: 'British English' },
      ],
    },
  },
}

これで、地球儀アイコンが追加される。クリックすると、以下のようにメニューが展開され、いずれかの言語をクリックすることで context.globals.localetoolbar.itemsvalue で指定した値が設定される。

アイコンの表示位置について

globalTypes で追加したアイコンは、拡張機能のアイコンの左に、区切り線なしで追加される。表示位置の調整や、セパレーターの追加などが可能かは未確認。

(調査中に、位置を調整したいというissueが対応不要でcloseされているのを見かけた気がするが、確認できなかった)

stories.tsx 内での globals の参照方法

今回は使わなかったが、Story関数の第2引数に globals が設定されているため、Reactであれば以下の記述で各ストーリー内で globals を参照できる。

import { Story } from '@storybook/react'

import { MyComponent } from 'components/myComponent'

export default { component: MyComponent }

export const Default: Story = (_, { globals }) => (
  <MyComponent locale={globals.locale} />
)

React以外でストーリーを記述している場合、以下を参照。

storybook.js.org

振り返り

「Storybook ロケール切り替え」あたりで検索すると、 react-i18nextvue-i18n の例ばかり出てくるので、面倒なのかと思い先延ばしにしていた。

いよいよ待ったなしになったので、本腰入れて調査したら、アドオンなど使わなくても設定できたので一安心。

また、さらっと流しているが、Storybookのロケール設定がNext.jsに反映されるのも、Storybook Addon Nextのおかげ。 next/image 動かない問題なども解消してくれるので、Next.jsアプリケーションでStorybookを使う時は必須だと思う、ありがたや。