
本文详解如何在 Next.js App Router 中通过动态路由和国际化配置,实现页面路径(如 /privacy-policy → /politique-de-confidentialite)随语言(locale)自动切换,保持页面逻辑复用、URL 语义化且 SEO 友好。
本文详解如何在 next.js app router 中通过动态路由和国际化配置,实现页面路径(如 `/privacy-policy` → `/politique-de-confidentialite`)随语言(locale)自动切换,保持页面逻辑复用、url 语义化且 seo 友好。
要在 Next.js(App Router)中实现 URL 路径随 locale 动态变化(例如 /en/privacy-policy ↔ /fr/politique-de-confidentialite),核心思路是:将语言段([locale])和页面标识段([slug])均设为动态参数,并在服务端根据 locale 查找对应翻译后的路径名,完成路由映射与内容渲染。这不是简单的客户端跳转,而是基于服务端路由能力的结构化多语言支持。
✅ 推荐目录结构(App Router)
app/ ├── [locale]/ # 动态语言段(如 en, fr) │ ├── layout.js # 包含语言切换器、i18n 上下文 Provider │ ├── page.js # 首页(可选) │ └── [slug]/ # 动态页面段(如 privacy-policy / politique-de-confidentialite) │ └── page.js # 统一页面组件,按 locale 渲染不同文案与路径
✅ 关键实现步骤
-
定义路径映射表(推荐 JSON 文件)
在app/[locale]/[slug]/page.js中,根据当前locale和原始英文 slug(如"privacy-policy")查出对应本地化 slug:// lib/i18n/routes.js export const routeMap = { en: { 'privacy-policy': 'privacy-policy', 'about': 'about' }, fr: { 'privacy-policy': 'politique-de-confidentialite', 'about': 'a-propos' }, de: { 'privacy-policy': 'datenschutzrichtlinie', 'about': 'ueber-uns' } }; -
在页面中解析并校验 slug(服务端)
// app/[locale]/[slug]/page.js import { routeMap } from '@/lib/i18n/routes'; import { notFound } from 'next/navigation'; export default async function LocalizedPage({ params }) { const { locale, slug } = await params; const validLocales = Object.keys(routeMap); const validSlugs = routeMap[locale] ? Object.keys(routeMap[locale]) : []; // 若 locale 或 slug 不合法,返回 404 if (!validLocales.includes(locale) || !validSlugs.includes(slug)) { notFound(); } // 获取当前 locale 下的真实页面标识(用于数据获取/文案渲染) const pageKey = slug; // 如 'privacy-policy' return ( <main><h1>{t(pageKey, 'title', locale)}</h1> <p>{t(pageKey, 'content', locale)}</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill2750" title="抖音下载器(Node.js)"><img src="https://img.php.cn/upload/skill/000/000/081/178935487523053.jpg" alt="抖音下载器(Node.js)" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill2750" title="抖音下载器(Node.js)" class="overflowclass">抖音下载器(Node.js)</a> <p class="overflowclass">抖音无水印视频下载和文案提取工具</p> </div> <a rel="nofollow" href="/xiazai/skill2750" title="抖音下载器(Node.js)" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div> {/* 语言切换链接示例 */} <languageswitcher currentlocale="{locale}" pagekey="{pageKey}"></languageswitcher></main> ); } -
语言切换器组件(客户端)
// components/LanguageSwitcher.jsx 'use client'; import { usePathname, useRouter } from 'next/navigation'; import { routeMap } from '@/lib/i18n/routes'; export default function LanguageSwitcher({ currentLocale, pageKey }) { const pathname = usePathname(); const router = useRouter(); const switchLocale = (newLocale) => { const newSlug = routeMap[newLocale]?.[pageKey]; if (!newSlug) return; const [, , ...rest] = pathname.split('/'); const newPath = `/${newLocale}/${newSlug}${rest.length ? `/${rest.join('/')}` : ''}`; router.push(newPath); }; return ( <div classname="flex gap-2"> {Object.keys(routeMap).map((loc) => ( <button key="{loc}" onclick="{()"> switchLocale(loc)} className={loc === currentLocale ? 'font-bold' : ''} > {loc.toUpperCase()} </button> ))} </div> ); }
⚠️ 注意事项
-
避免客户端硬编码路径:所有路由跳转必须通过
routeMap映射,确保一致性; -
SEO 友好性:每个
<link rel="alternate" hreflang="x">标签需在layout.js中动态注入,告知搜索引擎多语言关系; -
静态生成(SSG)支持:若需预渲染,需在
generateStaticParams中返回所有 locale × slug 组合; - 性能优化:路径映射表应轻量,建议使用纯 JSON;高频访问可考虑缓存或构建时内联;
-
不要混用
pages和app路由器:本方案仅适用于 App Router(Next.js 13+)。
通过该架构,你无需为每种语言重复创建页面文件,即可实现真正语义化的多语言 URL,同时保障内容复用、可维护性与国际化最佳实践。










