Nuxt.js & nuxt-i18n root以外のlocaleリダイレクト

nuxt-i18nを利用した国際化対応はとても便利ですが、1つ痒いところに手が届かないことがありました。

rootパス / へのアクセスの場合にdefaultのlocaleへリダイレクトさせる方法は以下の設定で実現ができます。
(以下は過去のブログ Nuxt.js: i18nで多言語化をやってみよう! の構成を元にしています。)

nuxt-i18n.config.js

import messages from './locales/message'

export default {
  strategy: 'prefix',
  locales: [
    {
      code: 'en',
      iso: 'en_US'
    },
    {
      code: 'ja',
      iso: 'ja_JP'
    }
  ],
  defaultLocale: 'en',
  vueI18n: {
    messages
  },
  rootRedirect: 'en',
  detectBrowserLanguage: {
    useCookie: true,
    cookieKey: 'i18n_locale'
  }
}

rootRedirect: 'en' により、rootパスへのアクセスは自動的に /en/ にリダイレクトされます。
ここまでは想定通りでなんの問題もありません。
しかし、root以外のアクセスでかつlocale情報がないURLの場合はlocale情報が付与されずに、エラーとなってしまいます。
もちろんこれは、 strategy: 'no-prefix' strategy: 'prefix_and_default' とすればいいのですが、今回はどうしてもlocaleコードをURLにつけた状態でリダイレクトしたいというのが要件となります。

ルート以外のパスでアクセスした場合にもlocaleコードをURLに付与したい

nuxt-i18nの設定だけでこれが実現できるはずだと思っていろいろ調べたのですが、実現方法が見つかりませんでした。detectBrowserLanguage.fallbackLocale がそれなのかと思ったのですが、機能せず仕方なくカスタムで実装することにしました。

今回は、middlewareを作成して対応しました。

/middleware/i18n.js

export default function({ route, app, redirect }) {
  const arr = app.i18n.locales.filter((item) => {
    return route.fullPath.indexOf(`/${item.code}`) === 0
  })

  if (!arr.length) {
    redirect(`/${app.i18n.locale}${route.fullPath}`)
  }
}

nuxt-i18n.config.js の設定が context.app.i18n で参照できますので、アクセスしたURLの頭にここで設定した locales が存在するかをチェックします。
存在しないばあい、つまりアクセスしたURLにlocaleコードがない場合は、defaultLocaleである en を付与してリダイレクトさせます。

このmiddlewareをroutingが発生する度に呼び出したいので nuxt.config.js に以下のように追加します。

export default {
  ...
  router: {
    middleware: 'i18n'
  },
  ...
}

これでOK!