如何在 Next.js(Pages Router)v16 的导航链接中维护 locale

在内部导航中保持 locale 一致

问题

当 Web 应用将语言偏好编码在 URL 路径中时,每一个内部链接都必须在用户会话期间持续保留该语言上下文。如果没有显式处理 locale,直接使用裸路径的链接可能会丢失语言前缀,导致用户在导航过程中失去已选语言。这会破坏本地化体验,并迫使用户反复选择自己的首选语言。

解决方案

确保每个内部导航链接都能自动包含当前 locale,可以通过从路由器上下文中读取 locale 实现。Next.js Pages Router 通过其路由系统内置了 locale 支持,当前激活的 locale 可通过 useRouter hook 获取。默认情况下,Link 组件在客户端跳转时会保留当前 locale,但理解这一行为并在全应用中一致应用,才能确保无缝的 locale 感知导航。

步骤

1. 从路由器获取当前 locale

useRouter hook 提供 locale(当前激活的 locale)、locales(所有已配置的 locale)以及 defaultLocale(已配置的默认 locale)。

import { useRouter } from "next/router";

export default function Navigation() {
  const router = useRouter();
  const currentLocale = router.locale;

  return (
    <nav>
      <p>Current locale: {currentLocale}</p>
    </nav>
  );
}

该组件从路由器读取当前激活的 locale,使其可用于导航逻辑。

Link 没有传递 locale 属性时,客户端跳转会自动使用当前激活的 locale。

import Link from "next/link";

export default function Navigation() {
  return (
    <nav>
      <Link href="/about">About</Link>
      <Link href="/products">Products</Link>
      <Link href="/contact">Contact</Link>
    </nav>
  );
}

这些链接会自动保持当前 locale。如果用户正在访问 /fr/products,点击“About”会跳转到 /fr/about

3. 创建支持多语言的链接辅助工具以实现显式控制

在需要显式控制或希望让语言环境处理更加可见的情况下,可以创建一个包装组件,明确传递当前的 locale。

import Link from "next/link";
import { useRouter } from "next/router";
import { ReactNode } from "react";

interface LocaleLinkProps {
  href: string;
  children: ReactNode;
}

export function LocaleLink({ href, children }: LocaleLinkProps) {
  const { locale } = useRouter();

  return (
    <Link href={href} locale={locale}>
      {children}
    </Link>
  );
}

该组件使 locale 保持变得显式,并且可以根据需要扩展更多与 locale 相关的逻辑。

4. 以保留 locale 的方式处理编程式导航

当直接使用路由方法时,可以通过跳转选项指定 locale,或者通过将 href 参数作为对象传递,保留包括 locale 在内的所有路由信息。

import { useRouter } from "next/router";

export default function NavigationButton() {
  const router = useRouter();
  const { pathname, asPath, query, locale } = router;

  const handleNavigate = () => {
    router.push({ pathname: "/dashboard", query }, asPath, { locale });
  };

  return <button onClick={handleNavigate}>Go to Dashboard</button>;
}

这种模式确保编程式导航时能够保留当前的 locale 以及所有现有的查询参数。

5. 在整个应用中应用一致的链接模式

在应用中统一使用标准的 Link 组件,利用其内置的 locale 保持机制。

import Link from "next/link";

export default function ProductCard({ productId }: { productId: string }) {
  return (
    <article>
      <h2>Product {productId}</h2>
      <Link href={`/products/${productId}`}>View Details</Link>
      <Link href="/products">Back to Products</Link>
    </article>
  );
}

静态路由和动态路由都会自动包含当前的 locale 前缀,确保用户在应用内导航时始终保持所选语言。