You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 02:59:56