如何在 Next.js(Pages Router)v16 的导航链接中维护语言环境

在内部导航中维护语言环境

问题

当一个 Web 应用程序在 URL 路径中编码语言偏好时,每个内部链接必须在用户会话期间保持该语言上下文。如果没有明确的语言环境处理,以裸路径编写的链接可能会无意中丢失语言前缀,导致用户在导航过程中丢失所选语言。这会破坏本地化体验,并迫使用户反复选择其首选语言。

解决方案

通过从路由器上下文中读取当前语言环境,确保每个内部导航链接自动包含当前语言环境。Next.js Pages Router 通过其路由系统提供内置的语言环境支持,其中活动语言环境可通过 useRouter 钩子获取。默认情况下,Link 组件在客户端转换期间会保留当前语言环境,但理解此行为并在整个应用程序中一致地应用它,可以确保无缝的语言环境感知导航。

步骤

1. 从路由器中获取当前语言环境

useRouter 钩子提供了 locale(当前活动的语言环境)、locales(所有配置的语言环境)和 defaultLocale(配置的默认语言环境)。

import { useRouter } from "next/router";

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

  return (
    <nav>
      <p>当前语言环境:{currentLocale}</p>
    </nav>
  );
}

此组件从路由器中读取活动语言环境,使其可用于导航逻辑。

Link 没有提供语言环境属性时,当前活动的语言环境会在客户端转换期间使用。

import Link from "next/link";

export default function Navigation() {
  return (
    <nav>
      <Link href="/about">关于</Link>
      <Link href="/products">产品</Link>
      <Link href="/contact">联系</Link>
    </nav>
  );
}

这些链接会自动维护当前语言环境。如果用户正在查看 /fr/products,点击“关于”会导航到 /fr/about

3. 创建一个支持区域设置的链接助手以实现显式控制

在需要显式控制或希望使区域设置处理更加明显的情况下,可以创建一个包装组件,显式传递当前的区域设置。

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>
  );
}

此组件使区域设置的保留显式化,并且可以根据需要扩展为包含额外的区域设置特定逻辑。

4. 使用区域设置保留处理编程导航

在直接使用路由器方法时,可以通过过渡选项指定区域设置,或者通过将 href 参数作为对象传递来保留所有路由信息,包括区域设置。

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}>前往仪表板</button>;
}

此模式确保编程导航保留当前的区域设置以及任何现有的查询参数。

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

在整个应用程序中使用标准的 Link 组件,依赖其内置的区域设置保留行为。

import Link from "next/link";

export default function ProductCard({ productId }: { productId: string }) {
  return (
    <article>
      <h2>产品 {productId}</h2>
      <Link href={`/products/${productId}`}>查看详情</Link>
      <Link href="/products">返回产品列表</Link>
    </article>
  );
}

静态和动态路由都会自动包含当前的区域设置前缀,确保用户在应用程序中导航时保持其选择的语言。