静的エクスポートでの手動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が不要です。