如何在 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>
);
}
此组件从路由器中读取活动语言环境,使其可用于导航逻辑。
2. 使用不带显式语言环境属性的 Link 组件
当 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>
);
}
静态和动态路由都会自动包含当前的区域设置前缀,确保用户在应用程序中导航时保持其选择的语言。