KAEDE Hack blog

JavaScript 中心に ライブラリなどの使い方を解説する技術ブログ。

Next.js react-intl FormattedMessage で window.navigator からとったきた言語を適用できなかった

why

これまでこの技術ブログを Next で作り直していない。

それは必要性を感じていないから。

しかしゲームブログなら自分の臨むリンクの出し方やヘッダーフッターでの誘導が妄想できる。

やりたいことこそやる気が出るのだと信じて始める

Ark に絞って作成する。

要件と URL

kaede-ark-blog.vercel.com

あたりにする。ホームページ兼ブログ

直下に

posts/en/dinos/raptor

のようなページを持ってくるようにする

index は Header でのブログ概要と最新記事を並べるページにする

about (profile) 、それから contact に Twitter, skype, discode, などのリンクを貼る

質問集?によくある質問をまとめる、就活で聞かれるのがだるいから?公開したいから?

できれば google domain の取得してあるものを使う

TOP

f:id:kei_s_lifehack:20210301060353p:plain

top は

ヘッダーと

カエデArk攻略へようこそ!

このサイトは kaede0902 の個人的なゲーム攻略記事です

主に Ark を攻略しております

の説明と

ark の 始め方、恐竜、マップの特徴、洞窟とボス、

のリンクを貼る

ここも英語と日本語の切り分けをしないといけない

トップを多言語対応する

記事を入れる前にまずはトップを多言語対応する

locale とってこないと

locale/en.js

locale/ja.js

を作成する

en.js の中身は

export default msg = {
  title: 'kaede-ark-blog',
  desc: 'This is kaede0902 game blog of Ark',
}

ja.js の中身は

export default msg = {
  title: 'かえでArkブログ',
  desc: 'これは kaede0902 の Ark のゲームブログです',
}

とした

そのためには

pages/[lang]/index.js

とする変数 URL が必要なことに気づいた!

しかもこれは context にしないといけない、第一関門だ..

_app で react-intl から intlProvider import して default locale 定義して

nextjs.org

getInitProps で ctx の req/res を

301 に飛ばして

developer.mozilla.org

react-intl を試す

qiita.com

ググったら出てきたこの記事を参考にする

window.nav から言語情報をとる

const language = window.navigator.language.substring(0, 2) === 'ja' ? 'ja' : 'en';

これで window から取れるらしい

何も入れないでこのコードだけ試してみる

ReferenceError: window is not defined

This error happened while generating the page. Any console logs will be displayed in the terminal window.

window ないって出た

dev.to

node にはないらしい

node は普通の js と違って サーバーで動かす専用言語だから。

if (typeof window !== "undefined") {
  // browser code
}

これによると、 window が 未定義でない条件で作動する browser code を書くべきとある。

  if (typeof window !== "undefined") {
    const lang = window.navigator.language.substring(0, 2) === 'ja' ? 'ja' : 'en';
    console.log(lang)
  }

実行してみる

en

うまく行った

if がないと、サーバーサイド で html を作っている 段階で実行されてしまい、その段階では ブラウザでの処理ではないので window など存在しないのでエラーになる。しかし window が未定義でない段階での条件をつけると、SSR が終わった後に実行されるので無事に window.nav の言語情報が取れるということになる。

なお、これを jsx にも組み込めるように 三項演算子で書くと

    (typeof window !== "undefined")
    ?
    (window.navigator.language.substring(0, 2) === 'ja' ? 'ja' : 'en';)
    :
    false

になる


各言語のテキストのファイルを作る

記事に合わせて

msg.js

を作成

const messages_ja = {
  title: 'かえでArkブログ',
  desc: 'これは kaede0902 の Ark のゲームブログです',
}
const message_en = {
  title: 'kaede-ark-blog',
  desc: 'This is kaede0902 game blog of Ark',
}
export default {ja: messages_ja, en: message_en};

message_ja と _en で 各言語のタイトルと説明を定義

ja と en として export する

トップメッセージを2種類並べる

import {FormattedMessage} from "react-intl";

FormatMsg を import する。これが id による切り替えをする。

これを先ほどの window がある場合って処理を加えて

      <IntlProvider locale={(typeof window !== "undefined")?(window.navigator.language.substring(0, 2) === 'ja' ? 'ja' : 'en';):false} 
        messages={messages[lang]}>
        <FormattedMessage id="title"/>
      </IntlProvider>

変数でクッションを置く方法はできないので locale の lang の中に直接書かれる。なんてこった

window はフロントのものだから サーバーサイドで作る Next ではできなさそう。

window からとってくるのは厳しいので、Next.js のアプデで適用された i18n のライブラリを使うことにする

kei-s-lifehack.hatenablog.com