i18next + i18next-browser-languagedetectorでの開発時には、localStorageに注意する

ちょっとハマりそうになったので覚書。

起きたこと

  • i18next + i18next-browser-languagedetector + react-i18nextで多言語化
  • 言語切り替えスイッチを実装
  • 「ブラウザの設定言語」を変えても、言語が変わらない

原因

言語切り替え(i18n.changeLanguage)を行うと、localStorageに選択した言語が書き込まれます。

そのため、i18next-browser-languagedetectorがlocalStorageの値を優先して翻訳するようになっていました。

対策案1: 都度localStorageを消す

ブラウザの設定言語を読んだ時の挙動を確認したい場合のみ、localStorageの値を消しましょう。

特に設定を変えていない場合、i18nextLngで保存されていますので、ブラウザの開発ツールを使って必要になったら消しましょう。

対策案2: localStorageの優先度を下げる

どうしてもブラウザの設定を優先したい場合、優先順位を下げると良さそうです。

import LanguageDetector from 'i18next-browser-languagedetector';

const detector = new LanguageDetector(null, {
  order: ['querystring', 'cookie',  'navigator', 'localStorage', 'htmlTag'],
  htmlTag: document.documentElement,
});

navigatorがブラウザの言語設定ですので、localStorageより前に出してやるとよいでしょう。

上のサンプルコードでは、Cookieやクエリストリングでの指定には負けることに注意です。

余談: i18next-browser-languagedetectorを使うなら、lngは指定しない

i18nextを使う場合、以下のように設定を書きます。

import i18next from 'i18next';
 
i18next.init({
  lng: 'en', 
  debug: false,
  resources: {
    en: {
      translation: {
        "key": "hello world"
      }
    }
  }
});

i18next-browser-languagedetectorを使いたくなると、直感的にはこう書くのが良さそうです。

import i18next from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
 
i18next
  .use(LanguageDetector)
  .init({
  lng: 'en', 
  debug: false,
  resources: {
    en: {
      translation: {
        "key": "hello world"
      }
    }
  }
});

ですが、ここにはちょっとした罠があります。それは、「intlngを消す必要がある」ことです。

Detectorよりもint()lngが優先されますので、このままでは常に英語(en)が表示されます。

なにかしらのdetectorを使う場合は、lngを消すようにしましょう。

import i18next from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
 
i18next
  .use(LanguageDetector)
  .init({
  debug: false,
  resources: {
    en: {
      translation: {
        "key": "hello world"
      }
    }
  }
});

Comment