Next.js 14.1.0+next-intl实现动态国家前缀路由及首页双视图求助
国家选择功能开发问题
我正在开发国家选择功能,需求如下:
- 新用户访问首页时,需展示国家选择视图
- 已选择过国家的用户,直接跳转至带
/us或对应国家代码前缀路径的首页
技术栈:Next.js 14.1.0 + next-intl,已设置localePrefix: 'never'避免显示本地化前缀。尝试过以下方案但效果不佳:
- 用并行路由实现视图切换
- 修改middleware逻辑
- 修改
next.config.js的rewrites配置,但无法读取cookie中的已选国家值
求更优实现方案。
文件夹结构

Locale Layout 代码
import { Viewport } from 'next'; import '@/styles/globals.css'; import IntlProvider from '@/contexts/intl.provider'; import { cookies } from 'next/headers'; import { COUNTRY_COOKIE } from '@/i18n/routing'; export const viewport: Viewport = { themeColor: "#fff" } export default async function RootLayout({ params, home, country, }: { params: { locale: string }; home: React.ReactNode; country: React.ReactNode; }) { const cookieStore = cookies() return ( <html lang={params.locale}> <body> <IntlProvider> {cookieStore.get(COUNTRY_COOKIE) ? ( home ) : ( country )} </IntlProvider> </body> </html> ); }
middleware.ts 代码
export default async function middleware(req: NextRequest) { const publicPathnameRegex = RegExp( `^(/(${locales.join('|')}))?(${publicPages .flatMap((p) => (p === '/' ? ['', '/'] : p)) .join( '|' )}|\/(product|category|supplier|brand|collection|auth\/forget-password)?\/[^\/]+)?$`, 'i' ); const isPublicPage = publicPathnameRegex.test( req.nextUrl.pathname.split(countryPrefix[0])[1] ?? req.nextUrl.pathname.split(countryPrefix[0])[0] ); const selectedCountry = req.cookies.get(COUNTRY_COOKIE); if (selectedCountry) { if (isPublicPage) { return NextResponse.rewrite(new URL(req.nextUrl.pathname, req.url)); } else { return (authMiddleware as any)(req); } } else { return intlMiddleware(req); } } export const config = { // Match only internationalized pathnames matcher: ['/((?!api|_next|.*\\..*).*)', '/', '/:path*'], };
intl-config 代码
export const routing = defineRouting({ // A list of all locales that are supported locales: ['en', 'fr'], // Used when no locale matches defaultLocale: 'en', localePrefix: 'never', });
next.config.js 代码
const nextConfig = { async rewrites() { return [ { source: '/:path*', destination: '/should-read-from-cookie/:path*' } ] }, }
优化方案
1. 调整 Middleware 逻辑,实现路径重定向与视图控制
放弃并行路由的条件渲染,改用 Middleware 根据 cookie 直接处理路由跳转,更符合 Next.js 14 的 App Router 逻辑:
import { NextRequest, NextResponse } from 'next/server'; import { COUNTRY_COOKIE } from '@/i18n/routing'; export default async function middleware(req: NextRequest) { const url = req.nextUrl; const selectedCountry = req.cookies.get(COUNTRY_COOKIE); const isCountrySelectPage = url.pathname === '/country-select'; // 已选国家,且当前路径无国家前缀时,重定向到带国家前缀的首页 if (selectedCountry && !url.pathname.startsWith(`/${selectedCountry.value}`) && !isCountrySelectPage) { return NextResponse.redirect(new URL(`/${selectedCountry.value}`, req.url)); } // 未选国家,且当前不是国家选择页时,重定向到国家选择页 if (!selectedCountry && !isCountrySelectPage) { return NextResponse.redirect(new URL('/country-select', req.url)); } // 正常放行 return NextResponse.next(); } export const config = { matcher: ['/((?!api|_next|.*\\..*|country-select).*)'], };
2. 重构页面结构,分离国家选择页与带前缀的首页
- 创建
app/country-select/page.tsx:专门用于新用户的国家选择界面,选择后设置COUNTRY_COOKIE并跳转到对应国家前缀的首页。 - 创建
app/[country]/page.tsx:作为已选国家用户的首页,通过params.country获取当前国家代码,配合 next-intl 做本地化处理。
3. 调整 next-intl 配置,适配国家前缀路由
修改intl-config.ts,保留localePrefix: 'never',新增国家与locale的映射:
export const routing = defineRouting({ locales: ['en', 'fr'], defaultLocale: 'en', localePrefix: 'never', }); // 国家与locale的映射关系 export const countryToLocale: Record<string, string> = { us: 'en', fr: 'fr', // 可扩展其他国家映射 };
在app/[country]/layout.tsx中动态设置locale:
import { getMessages } from 'next-intl/server'; import { countryToLocale } from '@/i18n/routing'; import IntlProvider from '@/contexts/intl.provider'; export default async function CountryLayout({ children, params: { country }, }: { children: React.ReactNode; params: { country: string }; }) { const locale = countryToLocale[country] || 'en'; const messages = await getMessages({ locale }); return ( <html lang={locale}> <body> <IntlProvider locale={locale} messages={messages}> {children} </IntlProvider> </body> </html> ); }
4. 移除 next.config.js 中的无效 rewrites
rewrites 在构建阶段执行,无法读取请求时的 cookie,直接删除该配置,改用 Middleware 处理动态路由逻辑。
5. 国家选择页核心逻辑示例
'use client'; import { useRouter } from 'next/navigation'; import { COUNTRY_COOKIE } from '@/i18n/routing'; export default function CountrySelectPage() { const router = useRouter(); const handleSelectCountry = (countryCode: string) => { // 设置cookie,有效期按需调整 document.cookie = `${COUNTRY_COOKIE}=${countryCode}; path=/; max-age=31536000`; router.push(`/${countryCode}`); }; return ( <div> <h1>选择您的国家</h1> <button onClick={() => handleSelectCountry('us')}>美国</button> <button onClick={() => handleSelectCountry('fr')}>法国</button> </div> ); }
内容的提问来源于stack exchange,提问作者Sunchhay
相关产品推荐
相关产品推荐

