国際化 (i18n) ルーティング
Next.js は v10.0.0
以降、国際化 (i18n) ルーティングを組み込みでサポートしています。ロケール、デフォルトロケール、ドメイン固有のロケールの一覧を指定すると、Next.js がルーティングを自動的に処理します。
i18nルーティングのサポートは現在、react-intl
、react-i18next
、lingui
、rosetta
、next-intl
、next-translate
、next-multilingual
、tolgee
、paraglide-next
などの既存のi18nライブラリソリューションを補完し、ルートとロケールの解析を効率化することを目的としています。
はじめに
まず、i18n
設定をnext.config.js
ファイルに追加します。
ロケールは、UTSロケール識別子であり、ロケールを定義するための標準化された形式です。
一般的にロケール識別子は、言語、地域、スクリプトをダッシュで区切った言語-地域-スクリプト
で構成されます。地域とスクリプトはオプションです。例:
en-US
- アメリカ合衆国で話される英語nl-NL
- オランダで話されるオランダ語nl
- 特定の地域のないオランダ語
ユーザーのロケールがnl-BE
で、設定にリストされていない場合、利用可能な場合はnl
に、それ以外の場合はデフォルトのロケールにリダイレクトされます。したがって、ある国のすべての地域をサポートする予定がない場合は、フォールバックとして機能する国のロケールを含めることをお勧めします。
module.exports = {
i18n: {
// These are all the locales you want to support in
// your application
locales: ['en-US', 'fr', 'nl-NL'],
// This is the default locale you want to be used when visiting
// a non-locale prefixed path e.g. `/hello`
defaultLocale: 'en-US',
// This is a list of locale domains and the default locale they
// should handle (these are only required when setting up domain routing)
// Note: subdomains must be included in the domain value to be matched e.g. "fr.example.com".
domains: [
{
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
// an optional http field can also be used to test
// locale domains locally with http instead of https
http: true,
},
],
},
}
ロケール戦略
ロケール処理には、サブパスルーティングとドメインルーティングの2つの戦略があります。
サブパスルーティング
サブパスルーティングは、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
デフォルトのロケールにはプレフィックスが付きません。
ドメインルーティング
ドメインルーティングを使用すると、異なるドメインから提供されるロケールを設定できます。
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL', 'nl-BE'],
defaultLocale: 'en-US',
domains: [
{
// Note: subdomains must be included in the domain value to be matched
// e.g. www.example.com should be used if that is the expected hostname
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
www.example.com/blog
example.fr/blog
example.nl/blog
example.nl/nl-BE/blog
自動ロケール検出
ユーザーがアプリケーションルート(通常は/
)にアクセスすると、Next.jsはAccept-Language
ヘッダーと現在のドメインに基づいて、ユーザーが優先するロケールを自動的に検出しようとします。
デフォルトのロケール以外のロケールが検出された場合、ユーザーは次のいずれかにリダイレクトされます。
- サブパスルーティングを使用する場合:ロケールがプレフィックスとして付加されたパス
- ドメインルーティングを使用する場合:そのロケールがデフォルトとして指定されているドメイン
ドメインルーティングを使用している場合、Accept-Language
ヘッダーfr;q=0.9
を持つユーザーがexample.com
にアクセスすると、そのドメインがデフォルトでfr
ロケールを処理するため、example.fr
にリダイレクトされます。
サブパスルーティングを使用している場合、ユーザーは/fr
にリダイレクトされます。
デフォルトロケールにプレフィックスを付ける
Next.js 12とミドルウェアを使用すると、回避策を使用して、デフォルトのロケールにプレフィックスを追加できます。
たとえば、いくつかの言語をサポートするnext.config.js
ファイルがここにあります。"default"
ロケールは意図的に追加されていることに注意してください。
module.exports = {
i18n: {
locales: ['default', 'en', 'de', 'fr'],
defaultLocale: 'default',
localeDetection: false,
},
trailingSlash: true,
}
次に、ミドルウェアを使用してカスタムルーティングルールを追加できます。
import { NextRequest, NextResponse } from 'next/server'
const PUBLIC_FILE = /\.(.*)$/
export async function middleware(req: NextRequest) {
if (
req.nextUrl.pathname.startsWith('/_next') ||
req.nextUrl.pathname.includes('/api/') ||
PUBLIC_FILE.test(req.nextUrl.pathname)
) {
return
}
if (req.nextUrl.locale === 'default') {
const locale = req.cookies.get('NEXT_LOCALE')?.value || 'en'
return NextResponse.redirect(
new URL(`/${locale}${req.nextUrl.pathname}${req.nextUrl.search}`, req.url)
)
}
}
このミドルウェアは、APIルートと、フォントや画像などのパブリックファイルにデフォルトのプレフィックスを追加するのをスキップします。デフォルトロケールへのリクエストが行われた場合、プレフィックス/en
にリダイレクトします。
自動ロケール検出の無効化
自動ロケール検出は、以下で無効にできます。
module.exports = {
i18n: {
localeDetection: false,
},
}
localeDetection
がfalse
に設定されている場合、Next.jsはユーザーの優先ロケールに基づいて自動的にリダイレクトすることはなくなり、上記のように、ロケールベースのドメインまたはロケールパスから検出されたロケール情報のみを提供します。
ロケール情報へのアクセス
Next.jsルーターを介してロケール情報にアクセスできます。たとえば、useRouter()
フックを使用すると、次のプロパティが利用可能になります。
locale
には、現在アクティブなロケールが含まれます。locales
には、構成されたすべてのロケールが含まれます。defaultLocale
には、構成されたデフォルトのロケールが含まれます。
getStaticProps
またはgetServerSideProps
を使ってページをプリレンダリングする場合、ロケール情報は関数に提供されるコンテキストの中で提供されます。
getStaticPaths
を活用する場合、設定されたロケールは、関数のコンテキストパラメーター内のlocales
の下と、設定されたデフォルトロケールはdefaultLocale
の下で提供されます。
ロケール間の遷移
ロケール間を遷移するには、next/link
またはnext/router
を使用できます。
next/link
の場合、現在アクティブなロケールとは異なるロケールに遷移するために、locale
プロパティを指定できます。locale
プロパティが指定されていない場合、クライアント遷移中は現在アクティブなlocale
が使用されます。例:
import Link from 'next/link'
export default function IndexPage(props) {
return (
<Link href="/another" locale="fr">
To /fr/another
</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クエリ値など、すべてのルーティング情報を保持しながらlocale
のみを切り替えるには、href
パラメーターをオブジェクトとして提供できます。
import { useRouter } from 'next/router'
const router = useRouter()
const { pathname, asPath, query } = router
// change just the locale and maintain all other route information including href's query
router.push({ pathname, query }, asPath, { locale: nextLocale })
router.push
のオブジェクト構造の詳細については、こちらを参照してください。
既にロケールを含むhref
がある場合は、ロケールプレフィックスの自動処理をオプトアウトできます。
import Link from 'next/link'
export default function IndexPage(props) {
return (
<Link href="/fr/another" locale={false}>
To /fr/another
</Link>
)
}
NEXT_LOCALE
Cookieの活用
Next.jsでは、NEXT_LOCALE=the-locale
クッキーを設定することができ、これはaccept-languageヘッダーよりも優先されます。このクッキーは言語スイッチャーを使用して設定でき、ユーザーがサイトに戻ってきたときに/
から正しいロケールロケーションにリダイレクトする際に、クッキーで指定されたロケールが活用されます。
たとえば、ユーザーのaccept-languageヘッダーでロケールfr
が優先されるが、NEXT_LOCALE=en
クッキーが設定されている場合、/
にアクセスすると、クッキーが削除または期限切れになるまで、ユーザーはen
ロケールの場所にリダイレクトされます。
検索エンジン最適化
Next.jsはユーザーがどの言語でアクセスしているかを知っているため、<html>
タグにlang
属性を自動的に追加します。
Next.jsはページのバリアントについて認識していないため、next/head
を使用してhreflang
メタタグを追加するのはあなた次第です。hreflang
の詳細については、Googleウェブマスターのドキュメントを参照してください。
これは静的生成でどのように機能しますか?
国際化ルーティングは、Next.jsルーティングレイヤーを利用しないため、
output: 'export'
と統合されないことに注意してください。output: 'export'
を使用しないハイブリッドNext.jsアプリケーションは完全にサポートされています。
動的ルートとgetStaticProps
ページ
動的ルートでgetStaticProps
を使用するページの場合、プリレンダリングしたいページのすべてのロケールバリアントは、getStaticPaths
から返される必要があります。paths
に対して返されるparams
オブジェクトとともに、レンダリングするロケールを指定するlocale
フィールドを返すこともできます。例:
export const getStaticPaths = ({ locales }) => {
return {
paths: [
// if no `locale` is provided only the defaultLocale will be generated
{ params: { slug: 'post-1' }, locale: 'en-US' },
{ params: { slug: 'post-1' }, locale: 'fr' },
],
fallback: true,
}
}
自動的に静的最適化されたページおよび非動的なgetStaticProps
ページの場合、ページのバージョンは各ロケールに対して生成されます。これは、getStaticProps
内で構成されたロケールの数によっては、ビルド時間が増加する可能性があるため、考慮することが重要です。
たとえば、getStaticProps
を使用する10個の非動的なページで50個のロケールが構成されている場合、これはgetStaticProps
が500回呼び出されることを意味します。各ビルド中に10ページの50個のバージョンが生成されます。
getStaticProps
を使用した動的ページのビルド時間を短縮するには、fallback
モードを使用します。これにより、ビルド中にプリレンダリングするために、getStaticPaths
から最も人気のあるパスとロケールのみを返すことができます。その後、Next.jsはリクエストに応じて残りのページを実行時にビルドします。
自動的に静的最適化されたページ
自動的に静的に最適化されたページの場合、ページのバージョンは各ロケールに対して生成されます。
非動的なgetStaticPropsページ
非動的なgetStaticProps
ページの場合、上記のように各ロケールに対してバージョンが生成されます。getStaticProps
は、レンダリングされる各locale
で呼び出されます。特定のロケールがプリレンダリングされないようにオプトアウトしたい場合は、getStaticProps
からnotFound: true
を返すことができます。これにより、このページのバリアントは生成されません。
export async function getStaticProps({ locale }) {
// Call an external API endpoint to get posts.
// You can use any data fetching library
const res = await fetch(`https://.../posts?locale=${locale}`)
const posts = await res.json()
if (posts.length === 0) {
return {
notFound: true,
}
}
// By returning { props: posts }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
i18n構成の制限
locales
:合計100個のロケールdomains
:合計100個のロケールドメインアイテム
知っておくと良いこと:これらの制限は、潜在的なビルド時のパフォーマンス問題を防ぐために最初に追加されました。Next.js 12では、Middlewareを使用したカスタムルーティングでこれらの制限を回避できます。
これは役立ちましたか?