React react-i18next での言語切り替えを試した
why
Next.js と react-intl での言語切り替えがうまくいかなかった、react-18next があると聞いた
t, translate 関数での二言語の切り替えが react-intl より簡単そうに見えた
結果
Next.js ではこのコードは使えなかった
React.js 単体では動いた
実装
とりあえず1 からトップだけ作ってみることにする。
ボタンでの言語切り替え。
この「素振り」を参考にする
問題点
TS の React.FC の型がどうして参考記事で使われているのか理解できていない
() => setLang(lang === 'en' ? 'ja' : 'en')
のロジックは理解できたが、これを自分で思いつける自信がない
公式の GitHub の サンプルを見たが、どうして class component も使うのか理解できない
install
npm i i18next react-i18next
いつも通り npm i
t('trans_key')と setLang でのトグル切り替えを仕込む
<p>{t('welcome')}</p> <div> <button onClick={ () => setLang(lang === 'en' ? 'ja' : 'en') }> {t('changeLang')} </button> </div>
最初に jsx に
{ t('translation_key') }
と t 関数と引数の key となる string で t 関数を用いた変換された key を書く
これはあくまで 変換の際に辞書ファイルを検索するための key であり、実際のメッセージではない。
次に btn で クリックされたときに
() => setLang(lang === 'en' ? 'ja' : 'en')
setLang
が即時関数で発動し、
引数には lang
という変数の中身が 初期値の ja から en になっていた場合であれば
en からの変更なので ja に
en じゃない場合は ja になるので、ja からの変更なので en に
変更する。
i18n の import と辞書の配列の作成
先ほどの index.js の前半 で i18n の import と 変換用の辞書のリソースを入れる
先ほど作った t(welcome), t(changLang)
はここからとってくる。
json だし その技術があれば CMS で外部からも持って来れそうだな...
import i18n from 'i18next' import { initReactI18next } from 'react-i18next'
i18n と initReactI18next を import して初期値を入れる。
i18n.use(initReactI18next).init({ resources: { en: { translation: { 'welcome': 'Welcom to i18next', 'changeLang': 'Change Language', }, }, ja: { translation: { 'welcome': 'i18next にようこそ。' 'changeLang': '言語を切り替える', }, }, }, lng: 'en', fallback: 'en', interpolation: {escapeValue: false}, });
検索先のリソースとして
welcome, changeLang をそれぞれの言語で入れる。
lng で最初の言語、fallback が何かあったときの言語だろう
inter polation と escape value は不明
Hook を使って言語の切り替え関数を作る
index のさらに上部に 本命の useTranslation
での 作成した辞書から引っ張ってくるライブラリの import と、react-hooks での state と副作用での切り替え機能を作る
記事では ts のため React.FC を使っているが、function のみで実装できた。
import { useTranslation } from 'react-i18next' import React, { useState, useEffect } from 'react';
useTranslation と useState, useEffect を import
function App() { const [t, i18n] = useTranslation(); const [lang, setLang] = useState('en');
traslate, i18n, lang, setLang の hook を作成
useEffect( () => { i18n.changeLanguage(lang) } ,[lang, i18n]);
lang か i18n が変化したときに、 i18n の changeLanguage を使って 現状の lang の値にする。
JS で type を使っていてエラーが出る
key を間違えていたが、React.FC がないと思って js に React.FC を使ったところ
react_devtools_backend.js:2430 ./pages/index.js:27:10 Syntax error: Const declarations require an initialization value 25 | }); 26 | > 27 | const Home: React.FC = () => { | ^ 28 | const [t, i18n] = useTranslation(); 29 | const [lang, setLang] = useState('en'); 30 |
const Home: React.FC だと初期値がない?からだめとエラーが出た
react_devtools_backend.js:2430 ./pages/index.js:27:8 Syntax error: Unexpected token, expected ";" 25 | }); 26 | > 27 | let Home: React.FC = () => { | ^ 28 | const [t, i18n] = useTranslation(); 29 | const [lang, setLang] = useState('en'); 30 |
let にしても : React.FC が受け入れられない
Next との食い合わせが悪いのか...???
Syntax error: Const declarations require an initialization value 25 | }); 26 | > 27 | const Home:React.FC = (lang) => { | ^ 28 | const [t, i18n] = useTranslation(); 29 | const [lang, setLang] = useState('en');
中身を入れてもダメ、どうすればいいのか詰まったが、
js なのに tsの記述があるのは不自然
とご指摘をいただいた。
確かに元のコードは tsx だ。
調べなおしたらそもそも React.FC は React の type だった。
React で無事に動かす
key を統一して 無事にトグルすることができた。
次やるべきこと
これを Next.js でも結局できるのか試す。
React.js のみでは 複数ページのルーティングが手間だったり meta 周りの実装に苦労するのでやはり最終的には Next で動かさなければしっかりとしたものはつくれないだろう
TS の型を入れると何が嬉しいのかわかるようにする。
ここからやりたいこと
レスポンシブにして json ファイルにデータを分けて、かねてより作りたかった Ark Aberration 生物図鑑のサイトを公開する
json ファイルに辞書配列を分ける
i18n.use(initReactI18next).init({ resources: { en: { translation: { "welcome": "Welcom to i18next", "changeLang': "Change Language" }, }, ja: { translation: { "welcome": "i18next にようこそ。", "changeLang": "言語を切り替える" }, }, }, lng: 'en', fallback: 'en', interpolation: {escapeValue: false}, });
この App.js に書いている resources の鍵と翻訳を別のファイルに分ける。
src/locales/ を作成
en.json を作って...
json は single quote がダメらしい。Shift 押したくないんだがな...
これでよし
{ "welcome": "i18next にようこそ。", "changeLang": "言語を切り替える" }
ja.json も作成。
json ファイルを読み込む
import enJson from './locales/en.json' import jaJson from './locales/ja.json'
enJson, jaJson, という形で App.js で読み込み
resources: { en: { translation: enJson, }, ja: { translation: jaJson, }, },
初期化のリソースの英語の訳を enJson, 日本語を jaJson, に当てる
これで無事動いた。
あとは key で t() ちゃんが検索してくれるので react-intl みたいに id をつける必要もなし!!!やったね!t ちゃん!!!
これで攻略ブログ作るぞ〜〜〜!!