
Next.js 国際化完全ガイド
App Router で next-intl を導入し、ロケールルーティングを設定して、AI による翻訳を自動化する方法を解説します。
next-intl をインストール
next-intl は、Next.js App Router のロケールルーティング、メッセージの読み込み、翻訳フックを 1 つで処理するパッケージです。
npm install next-intli18n リクエスト設定を作成
メッセージを読み込む src/i18n/request.ts と、ロケールを定義する src/i18n/routing.ts の 2 ファイルを作成します。これらのファイルで、next-intl がメッセージとルートを解決する方法を設定します。
// src/i18n/routing.ts
import { defineRouting } from 'next-intl/routing';
import { createNavigation } from 'next-intl/navigation';
export const routing = defineRouting({
locales: ['en', 'de', 'ja', 'es'],
defaultLocale: 'en',
localePrefix: 'as-needed', // /about for en, /de/about for de
});
export const { Link, redirect, usePathname, useRouter } =
createNavigation(routing);ミドルウェアを設定
ロケール検出、URL の書き換え、リダイレクトを処理する middleware.ts を追加します。ミドルウェアはすべてのリクエストを仲介し、適切なロケールが適用されるようにします。
// middleware.ts <- Must be in project ROOT, not src/
import createMiddleware from 'next-intl/middleware';
import { routing } from './src/i18n/routing';
export default createMiddleware(routing);
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)'],
};[locale] フォルダー構成を設定
アプリのルートを app/[locale]/ 内へ移動します。generateStaticParams を追加し、ビルド時にロケールごとのページを生成します。これにより、/en/about、/de/about などの URL 構造が作成されます。
// app/[locale]/layout.tsx
import { routing } from '@/i18n/routing';
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}ルートレイアウトを更新
getMessages() でメッセージを読み込み、ロケールのルートレイアウトにある NextIntlClientProvider へ渡します。html の lang 属性にはロケールパラメーターを設定してください。
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { routing } from '@/i18n/routing';
import { notFound } from 'next/navigation';
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: { locale: string };
}) {
const { locale } = await params;
if (!routing.locales.includes(locale as any)) notFound();
setRequestLocale(locale);
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}コンポーネントで翻訳を使用
サーバーコンポーネントでは getTranslations(非同期、await)を、クライアントコンポーネントでは useTranslations(フック)を使用します。コンポーネントのレンダリング場所に応じて選択してください。サーバーコンポーネントなら、翻訳を JavaScript バンドルから完全に除外できます。
// Server Component (default)
import { getTranslations, setRequestLocale } from 'next-intl/server';
export default async function AboutPage({
params,
}: { params: { locale: string } }) {
const { locale } = await params;
setRequestLocale(locale);
const t = await getTranslations('AboutPage');
return <h1>{t('title')}</h1>;
}
// Client Component ('use client')
'use client';
import { useTranslations } from 'next-intl';
export default function SearchBar() {
const t = useTranslations('SearchBar');
return <input placeholder={t('placeholder')} />;
}SEO を追加:メタデータと hreflang
generateMetadata を使用し、ロケール別のページタイトルと説明を生成します。hreflang タグ用に alternates.languages を追加し、検索エンジンが各ページのすべての言語版を検出できるようにします。
// app/[locale]/layout.tsx or any page.tsx
import { getTranslations } from 'next-intl/server';
import { routing } from '@/i18n/routing';
export async function generateMetadata({
params,
}: { params: { locale: string } }) {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'Metadata' });
return {
title: t('title'),
description: t('description'),
alternates: {
languages: Object.fromEntries(
routing.locales.map((l) => [l, `/${l}`])
),
},
};
}エラーページと Not Found ページを処理
error.tsx と not-found.tsx は通常のロケールレイアウト外でレンダリングされる可能性があるため、特別な処理が必要です。ルートの not-found.tsx でローカライズ済みエラーメッセージを表示するには、独自の i18n プロバイダー設定が必要です。
// app/[locale]/error.tsx
'use client';
import { useTranslations } from 'next-intl';
export default function Error() {
const t = useTranslations('Error');
return (
<div>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
</div>
);
}
// app/not-found.tsx (root level -- needs own provider)
import { routing } from '@/i18n/routing';
export default async function GlobalNotFound() {
return (
<html lang={routing.defaultLocale}>
<body>
<h1>404 - Page Not Found</h1>
</body>
</html>
);
}翻訳を自動化
i18n の設定が完了したら、IDE から直接 AI を使用してメッセージファイルを翻訳するか、CI/CD パイプラインで i18n Agent CLI を使用し、デプロイのたびに翻訳を自動化します。
# In your IDE, ask your AI assistant:
> Translate messages/en.json to German, Japanese, and Spanish
✓ messages/de.json created (1.1s)
✓ messages/ja.json created (1.4s)
✓ messages/es.json created (1.0s)翻訳品質を自動管理
Next.js i18n 向けオープンソースツール
これらのオープンソースパッケージは、Next.js の国際化ワークフローでよくある問題を解決します。
next-intl-localechain
標準の next-intl は、翻訳がない場合にデフォルトロケールへ直接フォールバックします。そのため、適切な pt-PT の翻訳があっても、ブラジルポルトガル語のユーザーには英語が表示されます。next-intl-localechain はインテリジェントなフォールバックチェーンを追加し、関連するロケールの翻訳をディープマージするため、地域ロケールのユーザーには常に最も近い翻訳が表示されます。
import { getRequestConfig } from 'next-intl/server';
import { withLocaleChain } from 'next-intl-localechain';
export default getRequestConfig(withLocaleChain({
loadMessages: (locale) =>
import(`../../messages/${locale}.json`).then(m => m.default),
defaultLocale: 'en'
}));@i18n-agent/cli
ターミナルを離れずに Next.js のメッセージファイルを翻訳できるコマンドラインツールです。ファイルの直接翻訳、ジョブ状態の確認、結果のダウンロードが可能です。API キー認証を使用して CI/CD パイプラインでも動作し、ローカリゼーションのワークフローを完全に自動化できます。
# Install the CLI
npm install -g @i18n-agent/cli
# Authenticate
i18nagent login
# Translate your message files
i18nagent translate ./messages/en.json --lang de,ja,es
# Or use in CI/CD with an API key
export I18N_AGENT_API_KEY=your-key-here
i18nagent translate ./messages/en.json --lang de,ja,esよくある落とし穴
"Unable to find next-intl locale"
ミドルウェアがリクエストに一致していません。middleware.ts がプロジェクトルートにあるか、matcher パターンが静的ファイルを正しく除外しているか、ロケールがルーティング設定に含まれているかを確認してください。
意図しない動的レンダリング
ページまたはレイアウトに setRequestLocale(locale) がありません。この呼び出しがない場合、next-intl はヘッダーまたは Cookie からロケールを検出するため、動的レンダリングが強制され、静的生成ができなくなります。
i18n により並列ルートが機能しない
並列ルート(@modal)とルートのインターセプト((.)photo)には、[locale] 動的セグメントとの既知の非互換性があります。こうした高度なルーティングパターンでは、回避策としてミドルウェアベースのルーティングを使用してください。
言語を切り替えると現在のルートが失われる
ロケールを切り替える際は、usePathname() を使用して現在のパス名を保持し、ロケールセグメントだけを置き換えます。動的ルートのパラメーターは、新しいロケール向けに再解決する必要があるため注意してください。
推奨ファイル構成
my-nextjs-app/
├── middleware.ts # Locale routing (project root!)
├── next.config.mjs
├── messages/
│ ├── en.json # Source messages
│ ├── de.json
│ └── ja.json
├── src/
│ ├── i18n/
│ │ ├── request.ts # Message loading config
│ │ └── routing.ts # Locale definitions
│ └── app/
│ └── [locale]/
│ ├── layout.tsx # Root locale layout
│ ├── page.tsx # Home page
│ ├── error.tsx # Localized error page
│ ├── not-found.tsx # Localized 404
│ └── about/
│ └── page.tsx
└── package.jsoni18n Agent を今すぐ試す
翻訳ファイルをここにドロップ
JSON, YAML, PO, XML, CSV, Markdown, Properties
またはクリックしてファイルを選択
翻訳先言語
next-intl-localechain によるロケールフォールバック
pt-BR のような地域ロケールで翻訳キーが不足している場合、next-intl は最初に親ロケールの pt を確認せず、デフォルトロケールへ直接移ります。
npm install next-intl-localechainimport { withLocaleChain } from 'next-intl-localechain';
export default withLocaleChain({
fallbacks: {
'pt-BR': ['pt', 'en'],
'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
},
defaultLocale: 'en',
loadMessages: (locale) => import(`./messages/${locale}.json`),
});対応フレームワークと 75 種類の組み込みチェーンの完全な一覧については、ロケールフォールバックガイドをご覧ください。 Learn more →