🏃‍♂️

Next.jsで言語別にHTML構造を分けるベストプラクティス

に公開

多言語対応サイトで、<html lang="..."> を正しく制御したい人向けの実践ガイド。

https://www.think-smart.tools/ja/tools


🧩 背景

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