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(`Could not determine direction for locale: ${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 속성 설정
루트 라우트에서 현재 로케일을 가져와 문서의 <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>
);
}
'right' 대신 textAlign: 'end'를 사용하면 텍스트가 읽기 방향의 끝에 정렬됩니다. justifyContent 및 alignItems와 같은 Flexbox 속성은 dir 속성으로 설정된 방향을 자동으로 준수합니다.