클라이언트 앱 다국어(i18n) 가이드
작성일: 2026-04-06 Last Updated: 2026-04-06 대상: Browser Extension, Tauri Desktop App, Flutter Mobile App
1. 다국어 아키텍처 원칙
핵심 원칙
| 원칙 | 설명 |
|---|---|
| 키 기반 번역 | UI에 직접 문자열 삽입 금지, 반드시 t('key') 형태 사용 |
| ICU MessageFormat | 복수형, 성별, 선택 등 복잡한 패턴 처리의 표준 |
| 기본 언어 fallback | 번역 누락 시 기본 언어(en) 표시, 빈 문자열 금지 |
| 컴파일 타임 검증 | 타입 안전한 번역 키 사용 (자동 완성 지원) |
| 지연 로딩 | 사용 중인 언어만 로드, 전체 언어 번들 금지 |
ICU MessageFormat 예시
# 복수형
items_count = "{count, plural, =0 {항목 없음} one {# 항목} other {# 항목}}"
# 성별
greeting = "{gender, select, male {그가} female {그녀가} other {그 사람이}} 로그인했습니다"
# 중첩 (복수형 + 성별)
notification = "{gender, select,
male {{count, plural, one {그가 # 개를 추가했습니다} other {그가 # 개를 추가했습니다}}}
female {{count, plural, one {그녀가 # 개를 추가했습니다} other {그녀가 # 개를 추가했습니다}}}
other {{count, plural, one {# 개가 추가되었습니다} other {# 개가 추가되었습니다}}}
}"
2. 번역 파일 관리
파일 형식
| 플랫폼 | 파일 형식 | 위치 |
|---|---|---|
| Browser Extension | JSON (messages.json) | public/_locales/{locale}/messages.json |
| Tauri (프론트엔드) | JSON (네임스페이스별) | src/shared/i18n/locales/{locale}/ |
| Flutter | ARB (Application Resource Bundle) | lib/l10n/app_{locale}.arb |
폴더 구조
# Browser Extension (chrome.i18n 표준)
public/_locales/
+-- en/messages.json
+-- ko/messages.json
+-- ja/messages.json
# 프론트엔드 공통 (네임스페이스 분리)
src/shared/i18n/
+-- locales/
| +-- en/
| | +-- common.json # 공통 (버튼, 라벨)
| | +-- auth.json # 인증 관련
| | +-- dashboard.json # 대시보드
| | +-- errors.json # 에러 메시지
| +-- ko/
| | +-- common.json
| | +-- auth.json
| | +-- dashboard.json
| | +-- errors.json
+-- index.ts # i18n 초기화
+-- types.ts # 타입 정의
# Flutter (ARB)
lib/l10n/
+-- app_en.arb # 기본 언어 (모든 키 포함)
+-- app_ko.arb
+-- app_ja.arb
번역 키 네이밍 컨벤션
| 패턴 | 예시 | 설명 |
|---|---|---|
{기능}.{컴포넌트}.{동작} | auth.login.submit | 기능별 분류 |
{기능}.{상태}.{설명} | auth.error.invalidEmail | 상태별 분류 |
common.{카테고리}.{이름} | common.button.save | 공통 요소 |
error.{코드} | error.networkTimeout | 에러 메시지 |
번역 파일 JSON 예시
{
"auth": {
"login": {
"title": "로그인",
"email": "이메일",
"password": "비밀번호",
"submit": "로그인",
"forgotPassword": "비밀번호 찾기",
"noAccount": "계정이 없으신가요? {signUpLink}에서 가입하세요"
},
"error": {
"invalidEmail": "올바른 이메일 형식이 아닙니다",
"wrongPassword": "비밀번호가 일치하지 않습니다",
"tooManyAttempts": "{minutes}분 후 다 시 시도하세요"
}
}
}
Flutter ARB 예시
{
"@@locale": "ko",
"loginTitle": "로그인",
"@loginTitle": {
"description": "로그인 페이지 제목"
},
"itemCount": "{count, plural, =0{항목 없음} =1{1개 항목} other{{count}개 항목}}",
"@itemCount": {
"description": "아이템 개수 표시",
"placeholders": {
"count": {
"type": "int"
}
}
}
}
3. RTL(Right-to-Left) 지원
RTL 언어 목록
| 언어 | 코드 | 사용 인구 |
|---|---|---|
| 아랍어 | ar | ~4억 |
| 히브리어 | he | ~900만 |
| 페르시아어 | fa | ~1.1억 |
| 우르두어 | ur | ~2.3억 |
RTL 구현 체크리스트
| 항목 | 구현 방법 | 적용 대상 |
|---|---|---|
| HTML dir 속성 | <html dir="rtl"> 또는 dir="auto" | Browser Ext, Tauri |
| CSS 논리적 속성 | margin-inline-start 대신 margin-left 사용 금지 | Browser Ext, Tauri |
| Flexbox 방향 | direction: rtl 시 자동 반전 | Browser Ext, Tauri |