日本語応用ガイド手動i18nセットアップ

静的エクスポートでの手動i18n

Next.js 標準の「Internationalized Routing(i18nルーティング)」は、Cloudflare Pagesのような静的ホスティングで必須となる output: 'export' モードではサポートされていません。

このガイドでは、フォルダ分離による「手動i18n」の実装方法を解説します。

ディレクトリ構成

Next.jsのルーティング機能に頼らず、コンテンツを物理的に言語ごとのフォルダに分けます。

pages/
├── index.mdx       # ルートからのリダイレクト用
├── _meta.js        # ルートのナビゲーション設定
├── en/             # 英語コンテンツのルート
│   ├── index.mdx
│   └── ...
└── ja/             # 日本語コンテンツのルート
    ├── index.mdx
    └── ...

1. ルート設定

ルートリダイレクト (pages/index.mdx)

デフォルト言語(例:英語)へ即座にリダイレクトするページを作成します。

pages/index.mdx
import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
export default function Index() {
  const router = useRouter()
  useEffect(() => {
    router.replace('/en')
  }, [])
  return null
}

ルートメタ (pages/_meta.js)

言語フォルダをトップレベルのページとして定義します。ここで display: 'hidden' を使用しないことが重要です(これを使うとサイドバー自体が消えてしまうことがあります)。

pages/_meta.js
export default {
  "index": {
    "display": "hidden" // リダイレクトページ自体は隠す
  },
  "en": {
    "title": "English",
    "type": "page"
  },
  "ja": {
    "title": "日本語",
    "type": "page"
  }
}

2. 言語切り替えボタン

カスタムパスを使用しているため、theme.config.tsx に独自の切り替えコンポーネントを実装します。

theme.config.tsx
import { useRouter } from 'next/router'
 
const LanguageSwitch = () => {
    const { asPath } = useRouter()
    const isJa = asPath.startsWith('/ja')
    
    // 切り替えロジック: /ja/foo -> /en/foo, /en/foo -> /ja/foo
    // ルートの場合は /en をデフォルトとする
    const currentPath = asPath === '/' ? '/en' : asPath
    const targetPath = isJa 
        ? currentPath.replace('/ja', '/en')
        : currentPath.replace('/en', '/ja')
 
    return (
        <a href={targetPath}>
            {isJa ? 'English' : '日本語'}
        </a>
    )
}
 
const config = {
    // ...
    navbar: {
        extraContent: <LanguageSwitch />
    }
}

メリット

  • 完全静的: Cloudflare Pages (next export) で完璧に動作します。
  • ナビゲーションの分離: 英語を見ているときは英語のメニューのみ、日本語のときは日本語のメニューのみが表示されます。
  • シンプル: 複雑なMiddlewareやEdge Functionsが不要です。