🏃♂️
Next.jsで言語別にHTML構造を分けるベストプラクティス
多言語対応サイトで、<html lang="..."> を正しく制御したい人向けの実践ガイド。
🧩 背景
Next.js App Router では、
app/layout.tsx が必須で、全ページを <html> と <body> で包む。
しかし、lang 属性を URL ごとに動的に変えたい場合、
/layout.tsx に <html> を書くと多重ラップになり、柔軟な制御が難しい。
💡 解決策:ルートグループで分ける
Next.js の「ルートグループ」を活用し、
URLには影響を与えずに構造を分割する。
ディレクトリ構成例
app/
(locale)/
[locale]/
layout.tsx // <html lang="en">
page.tsx // /en, /ja
hoge/
page.tsx // /en/hoge, /ja/hoge
(default)/
layout.tsx // <html lang="en">
page.tsx // /
-
(locale)と(default)は URLに出ない。 - 両方のグループに
layout.tsxを置くことで、独立した root layout になる。 - これにより
app/layout.tsxは不要。
🧠 コード例
(locale)/[locale]/layout.tsx
export default function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: { locale: string };
}) {
return (
<html lang={params.locale}>
<body>{children}</body>
</html>
);
}
(default)/layout.tsx
export default function DefaultLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
⚙️ 動作のポイント
-
(locale)・(default)のlayout.tsxがそれぞれ root layout として扱われる。 - どちらのグループにも
<html>を記述可能。 - グループ間(例
/→/en)の遷移時は フルリロード になる(Next.jsの仕様)。 - それぞれのルートで
generateStaticParamsによる静的生成も利用できる。
✅ メリットまとめ
-
<html lang>を完全に分離できる -
/をx-default用ページとして独立可能 - URL が
/enや/jaのままシンプル - SEO・hreflang 構成とも整合性が取れる
🚀 まとめ
多言語サイトで <html lang> を正しく管理するには、
「複数ルートレイアウト+ルートグループ」構成が最も自然で安全。
Next.js 14以降ではこれが公式に許可された構成であり、
x-default を含む国際化サイトのベース設計として推奨できる。
Author: Think Smart Tools
Tech Stack: Next.js 14 / App Router / TypeScript / Tailwind CSS
Discussion