如何在Next.js App Router中配置无URL语言标识的i18n?
解决Next.js App Router下无URL语言标识的国际化方案
核心思路
放弃Pages路由时期的NextResponse.rewrite()方案(App Router根路径重写存在限制),改为在根服务器组件中根据用户语言偏好动态加载对应语言的页面组件,同时结合generateStaticParams预生成所有语言版本的静态页面,既满足URL统一,又保证预渲染性能。
步骤1:搭建基础结构
- 定义支持的语言列表:
// app/utils/i18n.ts export const locales = ['en', 'zh']; export const defaultLocale = 'en'; - 在
app目录下创建语言专属页面目录,比如app/en/page.tsx、app/zh/page.tsx,分别编写对应语言的首页内容(支持服务器/客户端组件)。 - 存放翻译文件(可选,用
next-intl或next-i18next管理):app/locales/en.json、app/locales/zh.json。
步骤2:根页面动态加载对应语言组件
在app/page.tsx(根服务器组件)中读取用户语言偏好(从Cookie/用户资料),加载对应语言的页面:
// app/page.tsx import { cookies } from 'next/headers'; import { locales, defaultLocale } from './utils/i18n'; export default async function RootPage() { // 从Cookie获取用户设置的语言(无则用默认) const cookieStore = cookies(); const userLocale = cookieStore.get('user-locale')?.value || defaultLocale; // 校验语言合法性,防止非法值 const validLocale = locales.includes(userLocale) ? userLocale : defaultLocale; // 动态导入对应语言的页面组件 const LanguageSpecificPage = (await import(`./${validLocale}/page`)).default; // 若需传递翻译函数,可结合国际化库处理(如next-intl) return <LanguageSpecificPage />; }
步骤3:预生成所有语言的静态页面
通过generateStaticParams让Next.js预先生成所有支持语言的静态内容,保证首屏性能:
// app/page.tsx import { locales } from './utils/i18n'; export async function generateStaticParams() { // 为每个语言生成静态参数,Next.js会预渲染对应版本 return locales.map((locale) => ({ locale })); }
步骤4:Middleware处理语言切换
不用重写路径,而是通过Middleware处理语言切换请求,设置Cookie后重定向回根路径(URL保持统一):
// middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { locales, defaultLocale } from './app/utils/i18n'; export function middleware(request: NextRequest) { const { pathname, searchParams } = request.nextUrl; // 处理语言切换接口(比如用户点击语言按钮时调用) if (pathname === '/api/set-locale') { const newLocale = searchParams.get('locale') || defaultLocale; const validLocale = locales.includes(newLocale) ? newLocale : defaultLocale; // 设置Cookie,重定向回根路径 const response = NextResponse.redirect(new URL('/', request.url)); response.cookies.set('user-locale', validLocale, { path: '/', maxAge: 60 * 60 * 24 * 30, // 有效期30天 httpOnly: true, }); return response; } // 其他请求直接放行,由根页面组件处理语言逻辑 return NextResponse.next(); } export const config = { matcher: ['/', '/api/set-locale'], };
步骤5:适配国际化翻译库(以next-intl为例)
如果需要统一管理翻译文本,可集成next-intl:
- 安装依赖:
npm install next-intl - 创建配置文件:
// app/i18n.ts import { createI18nClient } from 'next-intl'; import { locales, defaultLocale } from './utils/i18n'; export default createI18nClient({ locales, defaultLocale, messages: { en: () => import('./locales/en.json').then(res => res.default), zh: () => import('./locales/zh.json').then(res => res.default), }, }); - 在语言页面组件中使用翻译:
// app/en/page.tsx import { useTranslations } from 'next-intl'; export default function EnHomePage() { const t = useTranslations('Home'); return <h1>{t('welcome')}</h1>; }
关键注意事项
- 根页面必须是服务器组件,确保能在服务器端读取Cookie,避免客户端Hydration不匹配。
- 预生成的静态内容会按语言缓存,Next.js会根据用户语言偏好返回对应缓存版本,性能不受影响。
- 客户端导航时,语言切换通过设置Cookie后重定向实现,URL始终保持统一。
内容的提问来源于stack exchange,提问作者Tetiana Hrynko
相关产品推荐
相关产品推荐

