Next.js+Sanity项目:将默认语言路由改为根域名路径
实现默认语言(英语)根路径访问的配置方案
一、调整项目路由结构
把默认语言(英语)的页面移到根路由下,非默认语言(德语)保留带前缀的路由,适配AppRouter的路由规则:
- 创建
app/page.tsx:作为英语首页(对应根路径/) - 保留
app/de/page.tsx:作为德语首页(对应路径/de) - 其他页面同理:英语关于页放在
app/about/page.tsx,德语关于页放在app/de/about/page.tsx
二、保留国际化配置文件(i18n.config.ts)
原有配置无需修改,后续逻辑会基于默认语言标识做判断:
// i18n.config.ts const languages = [ { id: 'de', title: 'German' }, { id: 'en', title: 'English', isDefault: true }, ]; const i18n = { languages, base: languages.find((item) => item.isDefault)?.id, }; export { i18n };
三、重写中间件(middleware.ts)
核心逻辑:拦截原 /en 路径并重定向到根路径、根据用户语言偏好处理无前缀路径的跳转、确保德语路径正常访问:
// middleware.ts import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; import { i18n } from "@/i18n.config"; import { match as matchLocale } from "@formatjs/intl-localematcher"; import Negotiator from "negotiator"; function getLocale(request: NextRequest): string | undefined { const negotiatorHeaders: Record<string, string> = {}; request.headers.forEach((value, key) => (negotiatorHeaders[key] = value)); const locales: string[] = i18n.languages.map(lang => lang.id); const languages = new Negotiator({ headers: negotiatorHeaders }).languages(); return matchLocale(languages, locales, i18n.base || "en"); } export function middleware(request: NextRequest) { const pathname = request.nextUrl.pathname; const defaultLocale = i18n.base; // 1. 重定向原/en路径到根路径,避免SEO重复内容 if (pathname.startsWith(`/${defaultLocale}/`) || pathname === `/${defaultLocale}`) { const newPathname = pathname.replace(`/${defaultLocale}`, "") || "/"; return NextResponse.redirect(new URL(newPathname, request.url)); } // 2. 检查路径是否是非默认语言前缀 const nonDefaultLocales = i18n.languages.filter(lang => lang.id !== defaultLocale).map(lang => lang.id); const pathnameHasNonDefaultLocale = nonDefaultLocales.some( locale => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}` ); // 3. 非默认语言路径直接放行 if (pathnameHasNonDefaultLocale) { return NextResponse.next(); } // 4. 无前缀路径根据用户偏好跳转:偏好非默认语言则重定向,否则放行访问根路径 const locale = getLocale(request); if (locale !== defaultLocale) { return NextResponse.redirect( new URL(`/${locale}${pathname.startsWith("/") ? "" : "/"}${pathname}`, request.url) ); } // 5. 默认语言直接放行 return NextResponse.next(); } export const config = { matcher: [ "/((?!api|_next/static|admin|structure|robots|sitemap|_next/image|favicon.ico).*)" ] };
四、页面中获取当前Locale
- 根路径页面(如
app/page.tsx):直接默认使用en作为locale - 德语路径页面(如
app/de/page.tsx):通过路由参数获取locale:// app/de/page.tsx type Props = { params: { lang: string }; }; export default function DeHomePage({ params }: Props) { const locale = params.lang; // 此处为'de' // 基于locale从Sanity拉取对应语言的内容 return <div>德语首页</div>; } - 公共组件中获取locale:可在middleware中把locale写入请求头,页面读取:
// 中间件中添加(NextResponse.next()前) const response = NextResponse.next(); response.headers.set('x-locale', locale || defaultLocale); return response; // 页面中读取 import { headers } from 'next/headers'; const locale = headers().get('x-locale') || 'en';
五、Sanity内容适配
获取内容时根据当前locale筛选对应语言字段:
// 示例:获取首页内容 import { createClient } from '@sanity/client'; const client = createClient({ // 填入你的Sanity配置 }); export async function getHomeContent(locale: string) { return client.fetch(` *[_type == "homePage"][0]{ title, description, "content": content.${locale} } `); }
内容的提问来源于stack exchange,提问作者bandziuk
相关产品推荐
相关产品推荐

