概要
React.js の話をしようぜ!
いやいや、そりゃあ勿論、 Python こそが母国語であり、至高だよ? (再び)
でも前回 React.js をセットアップしてて楽しくなってきちゃったので、前回のスターターキットに i18n (多言語対応) を追加しようぜ!
今回は、
- 翻訳拡張
i18next
react-i18next
を導入、 - 翻訳ファイル作成作業効率化のための
i18next-parser
を導入、
ってところまでを揃えるぜ。
翻訳拡張を導入
自分のノートだけで作業が完結するように、今回も、以下に設定ファイルを書く……けれど、ちゃんとやりたいときはこちら↓の公式ドキュメントの Quick start 通りにやるといいぜ。
# i18next: 国際化ライブラリ。エンジン側。ふつうの JavaScript でも使える。
# react-i18next: これ↑を React へ統合するためのライブラリ。
yarn add i18next react-i18next
翻訳 json ファイルを用意しておく。
mkdir -p ./src/locales/en
mkdir -p ./src/locales/ja
echo '{}' > ./src/locales/en/translation.json
echo '{}' > ./src/locales/ja/translation.json
翻訳 json ファイルを読み込んで、翻訳の設定をするファイルを用意しておく。
mkdir -p ./src/i18n
echo "
import EN_TRANSLATION from '@/locales/en/translation.json'
import JA_TRANSLATION from '@/locales/ja/translation.json'
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
const resources = {
ja: {
translation: JA_TRANSLATION,
},
en: {
translation: EN_TRANSLATION,
},
}
i18n
.use(initReactI18next)
.init({
resources,
lng: 'en',
interpolation: {
escapeValue: false
}
})
export default i18n
" > ./src/i18n/index.ts
React アプリのエントリーポイントである main.tsx
で、設定ファイルを読み込む。
echo "
import App from '@/App'
import '@/i18n'
import '@/index.css'
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<BrowserRouter basename='/my-react'>
<App />
</BrowserRouter>
</React.StrictMode>
)
" > ./src/main.tsx
翻訳拡張を使う
こんな風に useTranslation
と t
を使う。まだ翻訳 json ファイルは空っぽだけれど、そのときはキーがそのまま表示される。問題なし。なんか、参考サイトではよく一意のキー文字列が使われているよな。でも、 json ファイルでは日本語をキーに持てるから、べつに日本語でもいいんじゃないか? って思うよ。そのほうがコンポーネントが読みやすいからさ。
echo "
import Button from '@/components/Button'
import formatDate from '@/utils/formatDate'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
function HomePage() {
const { t } = useTranslation()
const [formattedDate, setFormattedDate] = useState<string>('')
useEffect(() => {
const currentDate = new Date()
const dateStr = formatDate(currentDate)
setFormattedDate(dateStr)
}, [])
const handleClick = () => {
alert(t('Button がクリックされた!'))
}
return (
<div>
<h1>{t('Welcome to the Home Page')} - {formattedDate}</h1>
<Button label={t('Click Me')} onClick={handleClick} />
</div>
)
}
export default HomePage
" > ./src/pages/HomePage.tsx
翻訳 json ファイルを自動で埋めるツールを導入
このツールは、コンポーネントの t
をスキャンして、翻訳 json ファイルを自動で埋めてくれる効率化ツールだ。これを使えば、こんな風↓に作業できるってわけだ。
- コンポーネントに文字列を書くときは
t
で片っ端から実装する - ツールを使う
翻訳すべき文章: 初期値
の組み合わせで json ファイルが埋まる- json ファイルを開いて、 “翻訳すべき文章” を片っ端から翻訳すればよい
ラクでいいね。
yarn add --dev i18next-parser
設定ファイルを追加↓する。公式 README に詳しい設定があるから、それを貼り付けたほうが後々よいかも。
echo "
export default {
contextSeparator: '_',
createOldCatalogs: true,
defaultNamespace: 'translation',
defaultValue: (locale, namespace, key) => {
return \`\${key}\` // 規定と変更したもの。
},
indentation: 2,
keepRemoved: false,
keySeparator: '.',
lexers: {
hbs: ['HandlebarsLexer'],
handlebars: ['HandlebarsLexer'],
htm: ['HTMLLexer'],
html: ['HTMLLexer'],
mjs: ['JavascriptLexer'],
js: ['JavascriptLexer'],
ts: ['JavascriptLexer'],
jsx: ['JsxLexer'],
tsx: ['JsxLexer'],
default: ['JavascriptLexer'],
},
lineEnding: 'auto',
locales: ['ja', 'en'], // 規定と変更したもの。
namespaceSeparator: ':',
output: 'src/locales/\$LOCALE/\$NAMESPACE.json', // 規定と変更したもの。
pluralSeparator: '_',
input: undefined,
sort: false,
verbose: false,
failOnWarnings: false,
failOnUpdate: false,
customValueTemplate: null,
resetDefaultValueLocale: null,
i18nextOptions: null,
yamlOptions: null,
}
" > ./i18next-parser.config.js
こちらのコマンドで実行する。
yarn run i18next "./src/App.tsx" "./src/**/*.tsx"
# config が読み込まれているかどうかが心配だったらこう↓
yarn run i18next "./src/App.tsx" "./src/**/*.tsx" --config "./i18next-parser.config.js"
そうすると、こんな風にモリモリと翻訳 json ファイルが埋まっていくわけだぜ。ハァー、効率的!
{
"Welcome to the Home Page": "Welcome to the Home Page",
"Click Me": "Click Me",
"Button がクリックされた!": "Button がクリックされた!"
}