i18n
규칙
- Next.js App Router:
next-intl 사용 — useTranslations() 훅, NextIntlClientProvider, 로케일 감지를 위한 미들웨어
- React SPA:
react-i18next 사용 — useTranslation() 훅, 지연 로딩을 위한 i18next-http-backend를 포함한 i18n.init()
- 로케일 인식 라우팅:
/en/about, /fr/about — Accept-Language 헤더를 감지하고 리디렉션하는 미들웨어 사용
- 번역 파일: 로케일 및 네임스페이스별 JSON 파일 —
messages/en/common.json, messages/fr/common.json
- 네임스페이스 분할: 기능/페이지당 하나의 네임스페이스 —
auth.json, dashboard.json, settings.json — 페이지에 필요한 것만 로드
- 복수형 처리: ICU 메시지 형식 사용 —
{count, plural, one {# 개 항목} other {# 개 항목}}
- 보간:
t('greeting', { name }) — 번역된 문자열을 절대 연결하지 않음
- 날짜/숫자/통화:
Intl.DateTimeFormat, Intl.NumberFormat 사용 — 포맷을 하드코딩하지 않음
- RTL 지원:
<html>에 dir="rtl" 사용, CSS 논리 속성(margin-left 대신 margin-inline-start) 사용, 아랍어/히브리어로 테스트
패턴
import createMiddleware from "next-intl/middleware";
export default createMiddleware({
locales: ["en", "fr", "de", "ar"],
defaultLocale: "en",
});
import { useTranslations } from "next-intl";
function ProductCard({ price, date }: { price: number; date: Date }) {
const t = useTranslations("products");
const format = useFormatter();
return (
<div>
<h2>{t("title")}</h2>
<p>{format.number(price, { style: "currency", currency: "USD" })}</p>
<p>{format.dateTime(date, { dateStyle: "medium" })}</p>
</div>
);
}
피해야 할 것
- 사용자 대상 문자열 하드코딩 — 모든 문자열은 반드시
t()를 통해 처리
- 번역된 텍스트의 문자열 연결 — 보간 또는 ICU 형식 사용
- 모든 로케일을 미리 로드 — 로케일 및 네임스페이스별로 지연 로딩
- 레이아웃에 CSS
left/right 사용 — RTL 호환성을 위해 논리 속성 사용
- 로케일을 localStorage에만 저장 — SEO 및 공유 가능성을 위해 URL 기반 로케일 사용