Next.js(Pages Router) v16에서 오른쪽에서 왼쪽(RTL) 언어 지원하는 방법
아랍어와 히브리어를 위한 미러 레이아웃
문제
대부분의 웹 레이아웃은 왼쪽에서 오른쪽으로의 텍스트 흐름을 가정합니다. 내비게이션 메뉴는 왼쪽에 고정되고, 콘텐츠는 왼쪽에서 오른쪽으로 읽히며, 간격은 margin-left나 padding-right와 같은 속성으로 적용됩니다. 애플리케이션이 아랍어나 히브리어로 번역될 때, 이러한 언어들은 오른쪽에서 왼쪽으로 읽히므로 전체 시각적 레이아웃이 이에 맞게 미러링되어야 합니다. 미러링 없이는 사용자들은 시각적 계층 구조가 자연스러운 읽기 방향과 모순되는 혼란스러운 인터페이스를 경험하게 되어 내비게이션이 혼란스럽고 애플리케이션이 완성도가 떨어지는 느낌을 줍니다.
이 문제는 텍스트 정렬을 넘어섭니다. left, right, margin-left, padding-right와 같은 물리적 CSS 속성들은 콘텐츠 흐름보다는 고정된 화면 위치에 연결되어 있습니다. 텍스트 방향이 바뀌어도 이러한 속성들은 동일한 물리적 가장자리에 고정되어 있어 레이아웃이 자연스럽게 적응하지 못합니다.
해결책
문서의 텍스트 방향 속성을 현재 로케일과 일치하도록 설정하여 브라우저가 RTL 언어에 대해 자동으로 레이아웃 흐름을 반전시키도록 합니다. 물리적 CSS 속성을 화면 위치가 아닌 콘텐츠 흐름을 참조하는 논리적 속성으로 대체합니다. margin-inline-start와 padding-inline-end와 같은 논리적 속성은 텍스트 방향에 따라 올바른 물리적 가장자리에 자동으로 매핑되어 추가 코드나 조건부 스타일링 없이도 레이아웃이 자체적으로 미러링될 수 있게 합니다.
이 접근 방식은 스타일을 중복하거나 복잡한 로직을 추가하지 않고도 LTR과 RTL 언어 모두에 대해 올바르게 작동하는 방향에 구애받지 않는 레이아웃을 만듭니다.
단계
1. 로케일에서 텍스트 방향을 결정하는 헬퍼 만들기
논리적 속성은 텍스트 방향에 따라 적응하며, margin-inline-start는 LTR 컨텍스트에서는 margin-left와 동등하고 RTL 컨텍스트에서는 margin-right와 동등합니다. 로케일을 텍스트 방향에 매핑하는 유틸리티 함수를 만듭니다.
export function getDirection(locale: string): "ltr" | "rtl" {
const rtlLocales = ["ar", "he", "fa", "ur"];
return rtlLocales.includes(locale) ? "rtl" : "ltr";
}
이 함수는 RTL 언어를 식별하고 HTML 및 CSS에서 사용할 적절한 방향 값을 반환합니다.
2. 문서 방향 속성 설정하기
커스텀 Document 클래스는 lang 및 dir과 같은 속성으로 HTML 요소를 사용자 정의하기 위해 render 메서드를 오버라이드할 수 있습니다. 현재 로케일을 기반으로 루트 HTML 요소에 dir 속성을 설정하는 커스텀 Document를 생성하세요.
import Document, {
Html,
Head,
Main,
NextScript,
DocumentContext,
} from "next/document";
import { getDirection } from "../utils/direction";
class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const initialProps = await Document.getInitialProps(ctx);
return initialProps;
}
render() {
const locale = this.props.__NEXT_DATA__.locale || "en";
const dir = getDirection(locale);
return (
<Html lang={locale} dir={dir}>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
Next.js 라우터는 locale 속성을 통해 현재 활성화된 로케일을 제공합니다. 문서는 Next.js 라우팅 데이터에서 로케일을 읽고 해당 방향을 HTML 요소에 적용하여 브라우저 수준의 RTL 지원을 활성화합니다.
3. 물리적 CSS 속성을 논리적 등가물로 대체하기
margin-inline-start, padding-inline-start와 같은 논리적 속성과 margin-inline 및 padding-inline과 같은 축약형은 쓰기 모드와 방향에 따라 물리적 속성에 자동으로 매핑됩니다. 컴포넌트 스타일을 흐름 상대적 속성을 사용하도록 업데이트하세요.
export default function Navigation() {
return (
<nav className="nav">
<ul className="nav-list">
<li className="nav-item">Home</li>
<li className="nav-item">About</li>
<li className="nav-item">Contact</li>
</ul>
</nav>
);
}
.nav {
padding-inline: 1rem;
border-inline-start: 4px solid blue;
}
.nav-list {
display: flex;
gap: 1rem;
margin-block: 0;
padding-inline-start: 0;
}
.nav-item {
margin-inline-end: 1.5rem;
}
여백, 패딩 및 삽입에 대한 논리적 속성은 다양한 쓰기 모드에서 요소 위치 지정을 더 쉽고 효율적으로 만듭니다. 이러한 속성은 추가 스타일이나 미디어 쿼리 없이 RTL 컨텍스트에서 자동으로 반전됩니다.
4. 위치 지정에 논리적 속성 사용하기
절대적 또는 상대적으로 위치가 지정된 요소의 경우, left와 right를 inset-inline-start와 inset-inline-end로 대체하세요.
export default function Sidebar() {
return (
<aside className="sidebar">
<button className="close-button">×</button>
<p>Sidebar content</p>
</aside>
);
}
.sidebar {
position: fixed;
inset-inline-start: 0;
inset-block-start: 0;
inline-size: 250px;
block-size: 100vh;
padding-inline: 1rem;
}
.close-button {
position: absolute;
inset-inline-end: 0.5rem;
inset-block-start: 0.5rem;
}
논리적 속성 방법론에서는 width 속성이 inline-size로, height는 block-size로 대체됩니다. 이러한 속성들은 위치가 지정된 요소들이 현재 텍스트 방향에 맞게 올바른 측면에 나타나도록 보장합니다.
5. 논리적 텍스트 정렬 적용하기
텍스트 정렬에서 text-align: left와 text-align: right를 text-align: start와 text-align: end로 대체하세요.
.content {
text-align: start;
}
.metadata {
text-align: end;
margin-inline-start: auto;
}
논리적 속성은 물리적 뷰포트 치수가 아닌 콘텐츠 흐름과 관련된 박스의 가장자리를 참조합니다. start와 end 텍스트 정렬 값은 텍스트 방향에 자동으로 적응하여 LTR과 RTL 언어 모두에 대해 콘텐츠를 적절하게 정렬합니다.