如何在 TanStack Start v1 中构建语言切换组件
在同一页面上切换语言
问题
当用户在多语言应用程序中切换语言时,他们期望能够停留在同一页面并以新语言查看相同的内容。一个实现不佳的语言切换器会将语言选择视为导航到不同的目的地,通常会将用户重定向到主页,从而完全丢失他们的位置。这会破坏用户流程并引发挫败感,尤其是当用户正在深入执行某个工作流程或查看特定内容时。挑战在于构建一个切换器,该切换器仅更改 URL 的语言段,同时保留路径、查询参数和哈希的其余部分。
解决方案
构建一个语言切换器组件,该组件读取当前 URL 的路径名,并通过替换路径中的语言区域段来为每种可用语言构建链接。从 URL 结构中提取当前语言区域,然后通过替换语言区域部分并保留所有其他 URL 段来生成其他支持语言的新路径。使用这些路径渲染链接,使用户能够在不丢失当前页面上下文的情况下切换语言。
步骤
1. 定义支持的语言区域
创建一个配置文件,列出您的应用程序支持的所有语言,并标识默认语言区域。
export const locales = ["en", "fr", "es", "de"] as const;
export type Locale = (typeof locales)[number];
export const defaultLocale: Locale = "en";
此配置作为可用语言的单一事实来源,并将用于生成切换器链接。
2. 创建一个助手函数以从路径名中提取当前语言区域
编写一个实用函数,用于解析路径名并提取其中的语言区域段(如果存在)。
import { defaultLocale, locales, type Locale } from "./locales";
export function getLocaleFromPathname(pathname: string): Locale {
const segments = pathname.split("/").filter(Boolean);
const firstSegment = segments[0];
if (firstSegment && locales.includes(firstSegment as Locale)) {
return firstSegment as Locale;
}
return defaultLocale;
}
此函数检查路径的第一个段落,如果它匹配支持的语言区域,则返回该段,否则返回默认语言区域。
3. 创建一个辅助函数以构建本地化路径
编写一个函数,该函数接收当前路径名和目标语言区域,然后构造一个新路径,将语言区域段替换掉。
import { defaultLocale, locales, type Locale } from "./locales";
export function getLocalizedPath(
pathname: string,
targetLocale: Locale,
): string {
const segments = pathname.split("/").filter(Boolean);
const firstSegment = segments[0];
const hasLocalePrefix =
firstSegment && locales.includes(firstSegment as Locale);
if (hasLocalePrefix) {
segments[0] = targetLocale;
} else {
segments.unshift(targetLocale);
}
return "/" + segments.join("/");
}
此函数会替换现有的语言区域段,或者将目标语言区域添加到路径的开头,确保新 URL 指向同一页面的不同语言版本。
4. 构建语言切换器组件
创建一个组件,该组件使用当前位置生成所有支持语言的链接。
import { Link } from "@tanstack/react-router";
import { useLocation } from "@tanstack/react-router";
import { locales, type Locale } from "./locales";
import { getLocaleFromPathname, getLocalizedPath } from "./locale-helpers";
export function LanguageSwitcher() {
const location = useLocation();
const currentLocale = getLocaleFromPathname(location.pathname);
return (
<nav>
<ul>
{locales.map((locale) => {
const isActive = locale === currentLocale;
const localizedPath = getLocalizedPath(location.pathname, locale);
return (
<li key={locale}>
<Link
to={localizedPath}
search={location.search}
hash={location.hash}
aria-current={isActive ? "page" : undefined}
>
{locale.toUpperCase()}
</Link>
</li>
);
})}
</ul>
</nav>
);
}
该组件读取当前路径名,确定活动语言区域,并为每种支持的语言渲染一个链接,同时保留当前页面结构、查询参数和哈希片段。用户可以在保持相同逻辑页面的情况下切换语言。