如何在Next.js 14中不使用中间件实现i18n?或降低Vercel成本
无需中间件实现i18n的方案
1. 动态路由+静态预生成
在App Router中创建app/[lang]目录,将所有页面组件放在这个动态路由下:
- 在
app/page.js(根路径)添加客户端重定向逻辑,读取用户浏览器语言或本地存储的偏好,自动跳转到/en或/fr(可将英文设为默认,根页面直接渲染英文内容,或让[lang]的默认值为en)。 - 用
generateStaticParams预生成en和fr的所有静态页面,让大部分请求直接命中静态资源,完全绕过中间件。
示例代码(app/[lang]/page.js):
import { useTranslation } from 'next-i18next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; export async function generateStaticParams() { return [{ lang: 'en' }, { lang: 'fr' }]; } export async function getStaticProps({ params }) { return { props: { ...await serverSideTranslations(params.lang, ['common']), }, }; } export default function Home() { const { t } = useTranslation('common'); return <h1>{t('welcome')}</h1>; }
2. 纯客户端语言切换逻辑
完全依赖客户端处理路由和语言同步:
- 在根布局初始化
next-i18next,通过useEffect读取本地存储或浏览器语言,设置初始语言。 - 语言切换按钮直接调用
useRouter修改路由(比如从/跳转到/fr),同时更新i18n实例的语言。 - 这种方式不需要服务器中间件介入,缺点是首次加载可能有短暂语言不匹配闪屏,可通过
next/dynamic添加loading状态优化。
降低中间件成本的方案
1. 缩小中间件匹配范围
修改middleware.js的config.matcher,只拦截页面相关请求,排除API、静态资源、图片等无需处理的路径:
export const config = { matcher: [ '/', '/fr/:path*', '/((?!api|_next/static|_next/image|favicon.ico|assets).*)', ], };
这样中间件只会处理页面路由请求,大幅减少调用次数。
2. 简化中间件逻辑
- 优先读取用户的语言cookie,避免每次都解析
Accept-Language请求头,减少计算量。 - 只处理必要重定向:仅当请求路径不符合语言路由规则时触发跳转,已有对应语言cookie的请求直接放行。
示例简化后的中间件:
import { i18nRouter } from 'next-i18n-router'; import i18nConfig from './i18nConfig'; import { NextResponse } from 'next/server'; export async function middleware(request) { const cookieLang = request.cookies.get('NEXT_LOCALE')?.value; if (cookieLang && (cookieLang === 'en' || cookieLang === 'fr')) { return NextResponse.next(); } return i18nRouter(request, i18nConfig); }
3. 结合静态生成减少动态请求
对所有静态页面预生成多语言版本,用户访问预生成路径时直接返回静态资源,仅动态路由或未预生成页面才触发中间件。
内容的提问来源于stack exchange,提问作者Sri Charan
相关产品推荐
相关产品推荐

