国際化 (i18n) ルーティング
Next.jsはv10.0.0
から国際化 (i18n) ルーティングを組み込みでサポートしています。ロケールのリスト、デフォルトロケール、ドメイン固有のロケールを指定することで、Next.jsがルーティングを自動的に処理します。
i18nルーティングのサポートは、現在、既存のi18nライブラリソリューション(例:react-intl
、react-i18next
、lingui
、rosetta
、next-intl
、next-translate
、next-multilingual
、tolgee
、paraglide-next
、next-intlayer
などを、ルーティングとロケール解析を効率化することで補完するものです。
始める
始めるには、i18n
設定をnext.config.js
ファイルに追加します。
ロケールは、ロケールを定義するための標準化された形式であるUTSロケール識別子です。
一般的に、ロケール識別子は、言語、地域、スクリプトをハイフンで区切った形式(language-region-script
)で構成されます。地域とスクリプトはオプションです。例:
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とMiddlewareを使用すると、回避策を使用してデフォルトロケールにプレフィックスを追加できます。
例えば、いくつかの言語をサポートするnext.config.js
ファイルは次のとおりです。"default"
ロケールが意図的に追加されていることに注意してください。
module.exports = {
i18n: {
locales: ['default', 'en', 'de', 'fr'],
defaultLocale: 'default',
localeDetection: false,
},
trailingSlash: true,
}
次に、Middlewareを使用してカスタムルーティングルールを追加できます。
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)
)
}
}
このMiddlewareは、API Routesやフォント、画像などのpublicファイルへのデフォルトプレフィックスの追加をスキップします。デフォルトロケールへのリクエストが行われた場合、プレフィックス/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
クッキーの活用
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 Webmaster向けドキュメントで詳しく学ぶことができます。
これは静的生成とどのように連携しますか?
国際化ルーティングは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を使用してカスタムルーティングを行うことで、これらの制限を回避できます。
お役に立ちましたか?