【Next.js和訳】Advanced Features/Internationalized Routing
この記事について
この記事は、Advanced Features/Internationalized Routingの記事を和訳したものです。
記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。
Internationalized Routing
例 | Examples
Next.js はv10.0.0
以降、国際化(i18n)ルーティングをビルトインでサポートしています。
ロケールのリスト、デフォルトロケール、ドメイン固有のロケールを指定すると、Next.js が自動的にルーティングを処理してくれます。
i18n ルーティングのサポートは、ルートとロケールの解析を合理化することで、react-intl
、react-i18next
、lingui
、rosetta
、next-intl
などの既存の国際化ライブラリソリューションを補完することを目的としています。
はじめに | Getting started
まずは、next.config.js
ファイルにi18n
コンフィグを追加してみましょう。
ロケールは、ロケールを定義するために標準化されたフォーマットであるUTS Locale Identifiersです。
一般的にロケール識別子は、言語、地域、スクリプトをダッシュで区切ったもので、language-region-script
となります。
地域とスクリプトはオプションです。
例を挙げます。
-
en-US
- 米国で話されている英語 -
nl-NL
- オランダで話されているオランダ語 -
nl
- オランダ語、特定の地域なし
module.exports = {
i18n: {
// アプリケーションでサポートしたいすべてのロケールです
locales: ['en-US', 'fr', 'nl-NL'],
// 非ロケールの接頭辞を持つパス(例:`/hello`)を訪れたときに使用したいデフォルトのロケールです
defaultLocale: 'en-US',
// ロケールドメインと、そのドメインが扱うべきデフォルトロケールのリストです
//(これらは、ドメインルーティングを設定するときにのみ必要です
// **注**:サブドメインは、一致するドメイン値に含まれている必要があります(例:「fr.example.com」)
domains: [
{
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
// オプションのhttpフィールドを使用して、ローカルでロケールドメインをhttpsではなくhttpでテストすることもできます
http: true,
},
],
},
}
ロケール戦略 | Locale Strategies
ロケールの取り扱いには 2 つの方法があります。「サブパスルーティング」と「ドメインルーティング」です。
サブパスルーティング | Sub-path Routing
サブパスルーティングでは、ロケールを URL パスに入れます。
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL'],
defaultLocale: 'en-US',
},
}
上記の設定では、en-US
, fr
, nl-NL
がルーティングされるようになり、en-US がデフォルトのロケールとなります。もし、pages/blog.js
があれば、以下の URL が利用可能になります。
/blog
/fr/blog
/nl-nl/blog
デフォルトのロケールにはプレフィックスがありません。
ドメインルーティング | Domain Routing
ドメインルーティングを使用すると、異なるドメインから提供されるロケールを設定できます。
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL', 'nl-BE'],
defaultLocale: 'en-US',
domains: [
{
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
// specify other locales that should be redirected
// to this domain
locales: ['nl-BE'],
},
],
},
}
例えば、pages/blog.js
があれば、以下のような URL が利用できます。
example.com/blog
example.fr/blog
-
example.com/blog
example.fr/blog
example.nl/blog
example.nl/nl-BE/blog
ロケールの自動検出 | Automatic Locale Detection
Next.js は、ユーザーがアプリケーションのルート(通常は/
)を訪れた際に、Accept-Language
ヘッダーと現在のドメインをもとに、ユーザーが好むロケールを自動的に検出しようとします。
デフォルトのロケール以外のロケールが検出された場合、ユーザーはどちらかにリダイレクトされます。
- サブパスルーティングを使用している場合 : ロケール付きのパス
- ドメインルーティングを使用している場合 : そのロケールがデフォルトで指定されているドメイン
ドメインルーティングを使用している場合、Accept-Language
ヘッダーが fr;q=0.9
のユーザーが example.com
にアクセスすると、example.fr
のドメインはデフォルトで fr
ロケールを扱うため、example.fr
にリダイレクトされます。
サブパスルーティングを使用している場合、ユーザーは /fr
にリダイレクトされます。
ロケールの自動検出を無効にする | Disabling Automatic Locale Detection
ロケールの自動検出を無効にするには
module.exports = {
i18n: {
localeDetection: false,
},
}
localeDetection
をfalse
に設定すると、Next.js はユーザーの好みのロケールに基づいて自動的にリダイレクトしなくなり、上記のようにロケールベースのドメインやロケールパスから検出されたロケール情報のみを提供するようになります。
ロケール情報へのアクセス | Accessing the locale information
ロケール情報には、Next.js のルーターを介してアクセスできます。例えば、useRouter()
フックを使うと、以下のプロパティが利用できます。
-
locale
には、現在アクティブなロケールが入ります。 -
locale
には、現在有効なロケールが入ります。 -
defaultLocale
は、設定されたデフォルトのロケールを含みます。
getStaticProps
や getServerSideProps
を使ってページをプリレンダリングする場合、ロケール情報はその関数に提供されるコンテキストの中で提供されます。
getStaticPaths
を利用する場合、設定されたロケールは、関数のコンテキストパラメータの locales
に、設定された defaultLocale は defaultLocale
に提供されます。
ロケール間の移行 | Transition between locales
ロケール間の移行には、next/link
または next/router
を使用できます。
next/link
では、現在アクティブなロケールとは異なるロケールに移行するために、locale
のプロップを提供することができます。
local
prop が提供されない場合、クライアントの移行時には、現在アクティブな locale
が使用されます。例えば、以下のようになります。
import Link from "next/link"
export default function IndexPage(props) {
return (
<Link href="/another" locale="fr">
<a>To /fr/another</a>
</Link>
)
}
next/router
メソッドを直接使用する場合は、遷移オプションで使用するlocale
を指定することができます。たとえば、次のようになります。
import { useRouter } from "next/router"
export default function IndexPage(props) {
const router = useRouter()
return (
<div
onClick={() => {
router.push("/another", "/another", { locale: "fr" })
}}
>
to /fr/another
</div>
)
}
すでにロケールを含むhref
がある場合は、ロケールのプレフィックスを自動的に処理しないようにすることができます。
import Link from "next/link"
export default function IndexPage(props) {
return (
<Link href="/fr/another" locale={false}>
<a>To /fr/another</a>
</Link>
)
}
NEXT_LOCALE クッキーの活用 | Leveraging the NEXT_LOCALE cookie
Next.js は、accept-language ヘッダーを NEXT_LOCALE=the-locale
クッキーで上書きすることをサポートしています。
このクッキーは、言語切り替え機能を使って設定することができ、ユーザーがサイトに戻ってきたときに、クッキーで指定されたロケールを利用して、/
から正しいロケールの場所にリダイレクトすることができます。
例えば、ユーザーが accept-language ヘッダーでロケール fr
を希望しているのに、NEXT_LOCALE=en
クッキーで en
ロケールが設定されている場合、/
にアクセスすると、クッキーが削除されるか期限切れになるまで、ユーザーは en
ロケールのロケーションにリダイレクトされます。
検索エンジン最適化 | Search Engine Optimization
Next.js はユーザーがどの言語でアクセスしているかを知っているので、自動的に <html>
タグに lang
属性を追加します。
Next.js はページのバリエーションについては知らないので、next/head
を使ってhreflang
メタタグを追加するのはあなた次第です。
hreflang
については、Google Webmasters のドキュメントで詳しく説明されています。
静的生成との相性は? | How does this work with Static Generation?
getStaticProps
ページ | Dynamic Routes and getStaticProps
Pages
ダイナミックルートとダイナミックルートで getStaticProps
を使用しているページでは、プリレンダリングを行いたいページのすべてのロケールのバリエーションを getStaticPaths
から返す必要があります。
paths
で返される params
オブジェクトと一緒に、レンダリングしたいロケールを指定する locale
フィールドを返すこともできます。例えば、以下のようになります。
// pages/blog/[slug].js
export const getStaticPaths = ({ locales }) => {
return {
paths: [
// `locale`が指定されていない場合は、defaultLocaleのみが生成されます。
{ params: { slug: 'post-1' }, locale: 'en-US' },
{ params: { slug: 'post-1' }, locale: 'fr' },
],
fallback: true,
}
}
Automatically Statically Optimized および非ダイナミックな getStaticProps ページ
では、ロケールごとにページのバージョンが生成されます。
これは、getStaticProps
内で設定されているロケールの数に応じて、ビルド時間が長くなる可能性があるため、考慮する必要があります。
例えば、50 個のロケールを構成して、10 個の非動的なページをgetStaticProps
を使って作成した場合、getStaticProps
が 500 回呼ばれることになります。1 回のビルドで 10 ページの 50 バージョンが生成されます。
getStaticProps
を使った動的ページのビルド時間を短縮するには、fallback
モードを使用します。これにより、getStaticPaths
から最も人気のあるパスやロケールのみを返して、ビルド中にプリレンダリングを行うことができます。そして、残りのページは Next.js がリクエストに応じてランタイムにビルドします。
自動的かつ静的に最適化されたページ | Automatically Statically Optimized Pages
自動的に静的に最適化されたページでは、各ロケール用のバージョンが生成されます。
非道的な getStaticProps ページ | Non-dynamic getStaticProps Pages
非動的な getStaticProps
ページでは、上記のようにロケールごとにバージョンが生成されます。
getStaticProps
はレンダリングされる各 locale
で呼び出されます。特定のロケールがプリレンダリングされないようにしたい場合は、getStaticProps
から notFound: true
を返せば、そのバージョンのページは生成されません。
export async function getStaticProps({ locale }) {
// 外部のAPIエンドポイントを呼び出して投稿を取得します。
// 任意のデータフェッチライブラリを使用することができます。
const res = await fetch(`https://.../posts?locale=${locale}`)
const posts = await res.json()
if (posts.length === 0) {
return {
notFound: true,
}
}
// { props: posts }を返すことで、Blogコンポーネントはビルド時に `posts` をプロップとして受け取ります。
return {
props: {
posts,
},
}
}
国際化設定の制限 | Limits for the i18n config
-
locales
:総ロケール数 100 -
domains
: 総ロケールドメイン数 100
Discussion