react-big-calendar で日本語対応をしたい

[react-big-calendar](https://github.com/jquense/react-big-calendar) は、react専用のカレンダーライブラリであるが、セットアップで必ず言語設定を行う必要がある。
公式には、言語対応のために使う日付フォーマットについて、
```
You can use either the Moment.js, Globalize.js, date-fns, Day.js localizers.
```
と記述しているが、なかなか上手く日本語化することができず、`date-fns` を使ってやっとのこと日本語か対応することが出来た。
この記事ではその手法について記述する。

# 完成形
![スクリーンショット 2024-06-10 22.13.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374872/3e851861-288f-2072-a392-1cad6b38dab1.png)

これを作っていく。

:::note warn
注意書き
日本語対応の箇所以外のコードや説明は省きます。
:::

:::note info
実行環境
React v18
Next.js v13
react-big-calendar v1.8
@mui/material v5.6.4
:::


# 1. 日本語対応
## もろもろインポート
まず、 `react-big-calendar` 関連から必要なものを引っ張ってくる。
`dateFnsLocalizer` が必要になるので、import。
以下を最初の状態とする。

```react
import 'react-big-calendar/lib/css/react-big-calendar.css';
import { Calendar, dateFnsLocalizer } from 'react-big-calendar'

export const MyCalendar = () => {
    return (
        <>
          <Calendar />
        </>
    );
}
```

## `date-fns` からもろもろインポート
日本語対応のため、`date-fns` をフル活用する。
```js
import format from "date-fns/format";
import getDay from "date-fns/getDay";
import parse  from "date-fns/parse";
import { ja } from "date-fns/locale";
import startOfWeek from "date-fns/startOfWeek";
```

## localize 用の設定を追加
何気に最初の `locales` の設定が沼った。
```js
const locales = {
  "ja": ja
};

const localizer = dateFnsLocalizer({
  format,
  parse,
  startOfWeek,
  getDay,
  locales
});
```

`localizer` を、`Calendar` の `localizer` props にセット。

```tsx
<Calendar
    localizer={localizer}
/>
```

## 盛り付け
```tsx
import 'react-big-calendar/lib/css/react-big-calendar.css';
import { Calendar, dateFnsLocalizer } from 'react-big-calendar'

import format from "date-fns/format";
import getDay from "date-fns/getDay";
import parse  from "date-fns/parse";
import { ja } from "date-fns/locale";
import startOfWeek from "date-fns/startOfWeek";

const locales = {
  "ja": ja
};

const localizer = dateFnsLocalizer({
  format,
  parse,
  startOfWeek,
  getDay,
  locales
});

export const MyCalendar = () => {
    return (
        <>
          <Calendar
            localizer={localizer}
            // .... その他のパラメタ
          />
        </>
    );
}
```

これで以下のものが出来上がる。

![スクリーンショット 2024-06-10 22.30.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374872/4f34196e-da28-9ef7-7959-20817281404e.png)

ここまではおそらく公式の情報でできる。

# 2. ツールバーの日本語対応
ツールバーを以下のように追加する。 `any` を使っているのは見逃してほしい。
`toolbar.label` は、カレンダーの現在日付を表示するパラメタであるので、それを日本語表示したい。

```tsx
const SchedulerToolbarWrapper = styled("div")({
  display: "flex",
  width: "80%",
  marginBottom: "8px",
  flexDirection: "row",
  alignItems: "center"
});

export interface ICustomToolbarProps {
  view: string;
  label: any;
  localizer: any;
  onNavigate: (action: any) => void;
  onView: (view: any) => void;
}

const SchedulerToolbar = (toolbar: ICustomToolbarProps) => {
  // 設定している日付を取得する
  // gotoNextとかで日付が変わったら変更する

  const goToBack = () => { toolbar.onNavigate('PREV');};
  const goToNext = () => { toolbar.onNavigate('NEXT');};
  const goToCurrent = () => { toolbar.onNavigate('TODAY');};

  return (
    <SchedulerToolbarWrapper>
      { /* 日付を出力  */ }
      <div>{toolbar.label}</div>
      <Button variant="contained" size="small" color="primary" sx={{ mx: "8px;" }} onClick={goToBack}>前日</Button>
      <Button variant="contained" size="small" color="primary" onClick={goToNext}>翌日</Button>
    </SchedulerToolbarWrapper>
  );
}

```
これをそのまま `Calendar` の　`components` props に追加する。

```tsx
export const MyCalendar = () => {
    return (
        <>
          <Calendar
            localizer={localizer}
            components={{ toolbar: props => ( <SchedulerToolbar {...props} /> ) }}
          />
        </>
    );
}
```

すると結果は以下。

![techblog eyecatch (19).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374872/87b70695-43d8-1165-4436-264069c43c32.png)

日本語になっていない。
なので `culture` props を設定する。
```tsx
export const MyCalendar = () => {
    return (
        <>
          <Calendar
            localizer={localizer}
            culture={"ja"}
            components={{ toolbar: props => ( <SchedulerToolbar {...props} /> ) }}
          />
        </>
    );
}
```

すると今度はこうなる。

![techblog eyecatch (20).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374872/acf9eb40-5919-bbaf-d36a-c125f972c030.png)

う〜〜〜ん、なんか惜しい。「xx年〇〇月▲▲日◎曜日」みたいにならないのか。
そこで `format` props を使って、日付のフォーマットをしよう。

```tsx
const formats = useMemo(() => ({
    dayHeaderFormat: 'yyyy年MM月dd日(EEEE)',
}), [])

export const MyCalendar = () => {
    return (
        <>
          <Calendar
            localizer={localizer}
            formats={formats}
            culture={"ja"}
            components={{ toolbar: props => ( <SchedulerToolbar {...props} /> ) }}
          />
        </>
    );
}
```

結果はついに...！！

![techblog eyecatch (21).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374872/b7ac6770-afae-5d39-d65e-cb2c07d311b5.png)

日本語表示することが出来ました！！👏

こうして5時間ほどかけて、日本語対応することが出来ました。
めでたしめでたし。