如何在 TanStack Start v1 中支持从右到左 (RTL) 的语言
为阿拉伯语和希伯来语镜像布局
问题
大多数网页布局假设文本是从左到右流动的。导航菜单固定在左侧,侧边栏出现在左侧,内容从左到右阅读。对于像阿拉伯语和希伯来语这样从右到左阅读的语言,这会造成一种视觉流向与阅读方向相矛盾的迷惑体验。用户会看到导航在错误的一侧,图标位置显得别扭,布局看起来反向。如果没有适当的 RTL(从右到左)支持,界面对 RTL 语言的使用者来说会变得难以导航和理解。
解决方案
根据当前的语言环境动态设置文档的文本方向,允许浏览器自动为 RTL 语言镜像布局。使用 CSS 逻辑属性而不是物理方向属性,这样间距、定位和对齐可以根据文本方向自动适应,无需额外的代码。这种方法使布局保持方向无关性:在英语中出现在内容“开始”的部分会正确地出现在阿拉伯语中的“开始”(右侧),由浏览器处理转换。
步骤
1. 根据语言环境确定文本方向
创建一个辅助函数,使用浏览器内置的国际化 API,根据给定的语言环境返回文本方向。
export function getTextDirection(locale: string): "ltr" | "rtl" {
try {
const localeObj = new Intl.Locale(locale);
if (
"getTextInfo" in localeObj &&
typeof localeObj.getTextInfo === "function"
) {
return localeObj.getTextInfo().direction;
}
} catch (e) {
console.warn(`无法确定语言环境的方向:${locale}`);
}
const rtlLocales = ["ar", "he", "fa", "ur"];
const lang = locale.split("-")[0];
return rtlLocales.includes(lang) ? "rtl" : "ltr";
}
此函数在可用时使用 Intl.Locale.getTextInfo(),并回退到已知的 RTL 语言列表。它根据语言环境返回 'ltr' 或 'rtl'。
2. 在 html 元素上设置 dir 属性
在根路由中,获取当前的语言环境(locale),并将相应的文本方向应用到文档的 <html> 元素。
import {
createRootRoute,
Outlet,
Scripts,
HeadContent,
} from "@tanstack/react-router";
import { useIntl } from "react-intl";
import { getTextDirection } from "~/utils/text-direction";
export const Route = createRootRoute({
component: RootComponent,
});
function RootComponent() {
return (
<RootDocument>
<Outlet />
</RootDocument>
);
}
function RootDocument({ children }: { children: React.ReactNode }) {
const intl = useIntl();
const dir = getTextDirection(intl.locale);
return (
<html lang={intl.locale} dir={dir}>
<head>
<HeadContent />
</head>
<body>
{children}
<Scripts />
</body>
</html>
);
}
<html> 元素上的 dir 属性告诉浏览器为 RTL(从右到左)语言反转布局。Flexbox、网格和内联内容会自动镜像。
3. 用逻辑属性替换物理 CSS 属性
更新样式表,使用响应文本方向的逻辑属性,而不是固定的物理方向。
.sidebar {
padding-inline-start: 1rem;
margin-inline-end: 2rem;
border-inline-start: 1px solid #ccc;
}
.icon {
margin-inline-end: 0.5rem;
}
.card {
inset-inline-start: 0;
text-align: start;
}
像 padding-inline-start 这样的逻辑属性在 LTR(从左到右)中映射为 padding-left,在 RTL 中映射为 padding-right。浏览器根据 dir 属性应用正确的物理属性,因此您的样式可以在两种方向中正常工作,无需重复。
4. 使用方向无关的对齐值
在 CSS 和内联样式中,用逻辑对齐关键字替换物理对齐关键字。
export function Header() {
return (
<header
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<nav style={{ display: "flex", gap: "1rem" }}>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<div style={{ textAlign: "end" }}>
<button>Menu</button>
</div>
</header>
);
}
使用 textAlign: 'end' 而不是 'right' 确保文本对齐到阅读方向的末端。像 justifyContent 和 alignItems 这样的 Flexbox 属性会自动遵循由 dir 属性设置的方向。