Reactで国際化対応しつつ、言語ごとにCSSを切り替えたい

## はじめに

Reactで国際化対応する場合は、[react-intl](https://github.com/formatjs/react-intl)が有名です。

react-intlで国際化対応しつつ、言語ごとにCSSをカスタマイズする必要があったので、

現状どうやっているかをメモとして残します。

## react-intlの基本的な使い方

日本語と英語に対応する場合の、react-intlの基本的な使い方です。

まず、日本語と英語のメッセージをオブジェクトとして定義しておきます。

```js:messages.js
const messages_ja = {
    "app.input.username.label": "ユーザ名",
    "app.input.username.description": "10文字以内で、半角文字の数字、大文字英字、またはアンダースコアで入力してください。",

};

const messages_en = {
    "app.input.username.label": "Username",
    "app.input.username.description": "Username must be within 10 characters and can only include numbers, capital letters or underscores.",
};

export default {ja: messages_ja, en: messages_en};

```

アプリ初期化時に、`IntlProvider`にブラウザの言語設定と言語に対応するメッセージオブジェクトを渡して、トップレベルのコンポーネントを包みます。

```react:index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {IntlProvider} from 'react-intl';
import messages from './i18n/messages';

const rootElement = document.getElementById('root');

// 言語設定が日本語ならjaを、それ以外ならenを使う
const language = window.navigator.language.substring(0, 2) === 'ja' ? 'ja' : 'en';

ReactDOM.render(
    <IntlProvider locale={language} messages={messages[language]}>
        <App/>
    </IntlProvider>,
    rootElement,
);

```

コンポーネント側では、`FormattedMessage`や`FormattedHTMLMessage`コンポーネントを使って、

メッセージオブジェクトのキー名を`id`として指定します。

```react:App.js
import React from 'react';
import {FormattedMessage} from "react-intl";
import './App.css';

function App() {
    return (
        <div className="App">
            <label>
                <FormattedMessage id="app.input.username.label"/>
                <input type="text"/>
            </label>
            <div className="description"><FormattedMessage id="app.input.username.description"/></div>
        </div>
    );
}

export default App;
```

<img width="1000" alt="スクリーンショット 2019-09-28 23.06.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16039/cb4fd4c9-f63d-9f55-8cb0-2c6a3e9dd1bb.png">


以上が、基本的なreact-intlの使い方です。

## 言語ごとにCSSを切り替える

ReactをrenderするDOM要素に対して、[lang属性](https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/lang)を指定してあげます。

```react:index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {IntlProvider} from 'react-intl';
import messages from './i18n/messages';

const rootElement = document.getElementById('root');

// 言語設定が日本語ならjaを、それ以外ならenを使う
const language = window.navigator.language.substring(0, 2) === 'ja' ? 'ja' : 'en';

// rootのDOM要素にlang属性を指定する。
rootElement.setAttribute('lang', language);

ReactDOM.render(
    <IntlProvider locale={language} messages={messages[language]}>
        <App/>
    </IntlProvider>,
    rootElement,
);

```

CSS側では、[lang擬似クラス](https://developer.mozilla.org/ja/docs/Web/CSS/:lang)を使って言語固有のCSSを定義します。

```css
/* root要素には、言語によらないか、大多数の言語で必要になるCSSを定義する */
#root {
    word-break: normal;
}

/* 言語ごとに個別に指定したいCSSがある場合は、lang擬似クラスを使って定義する */
#root:lang(ja) {
    word-break: break-word;
}
```

コンポーネント側で細かく言語ごとにCSSを切り替えたい場合も、同じようにlang擬似クラスを使用します。

```css
.App .description {
    font-size: 14px;
    color: #777;
}

/* 言語が日本語の場合だけ効く */
.App .description:lang(ja) {
    color: #dc7a00;
}
```

このようにlang属性、lang擬似クラスを使うことで、CSSを切り替えられます。

<img width="1000" alt="スクリーンショット 2019-09-28 23.19.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16039/cd2f166c-27d2-2c64-7607-460c778ddeed.png">