2025-12-02 06:27:21 +00:00

236 lines
5.3 KiB
Markdown

# 다국어 지원 (i18n) 가이드
라온누리 프로젝트의 다국어 지원 시스템 가이드입니다.
---
## 필수 적용 규칙
**모든 새로운 UI 및 페이지는 다국어 지원이 필수입니다.**
---
## 기본 규칙
1. **하드코딩 텍스트 금지**: 모든 사용자 대면 텍스트는 번역 파일(`messages/ko.json`, `messages/en.json`, `messages/ja.json`)에 저장
2. **번역 키 사용**: `useTranslations('namespace')` 훅으로 번역 텍스트 사용
3. **타입 안전 Link**: `import {Link} from '@/i18n/routing'` 사용 (next/link 대신)
4. **타입 안전 Router**: `import {useRouter} from '@/i18n/routing'` 사용 (next/navigation 대신)
---
## 페이지 생성 시
```typescript
// ❌ 잘못된 방식
"use client";
import {useRouter} from "next/navigation";
export default function NewPage() {
return <h1> 페이지</h1>; // 하드코딩 금지!
}
// ✅ 올바른 방식
"use client";
import {useRouter} from "@/i18n/routing"; // next-intl router
import {useTranslations} from "next-intl";
export default function NewPage() {
const t = useTranslations('newPage');
return <h1>{t('title')}</h1>;
}
// messages/ko.json에 추가:
// "newPage": { "title": "새 페이지" }
// messages/en.json에 추가:
// "newPage": { "title": "New Page" }
// messages/ja.json에 추가:
// "newPage": { "title": "新しいページ" }
```
---
## 컴포넌트 생성 시
```typescript
// 공통 컴포넌트는 namespace를 props로 받거나 고정
"use client";
import {useTranslations} from "next-intl";
export function MyComponent() {
const t = useTranslations('components.myComponent');
return (
<Button>{t('submit')}</Button>
);
}
```
---
## Server Component에서 번역 사용
Server Component에서는 `getTranslations()` 함수를 사용합니다:
```typescript
// ✅ Server Component
import {getTranslations} from "next-intl/server";
export default async function WritingDetailPage({
params,
}: {
params: Promise<{locale: string; writingId: string}>;
}) {
const {writingId} = await params;
const t = await getTranslations('interaction');
return (
<Container>
<BackButton label={t('back')} />
<Heading>{writing.title}</Heading>
</Container>
);
}
```
---
## 서비스 레이어에서 번역 사용
React 훅을 사용할 수 없는 곳에서는 `src/utils/i18n.ts``t()` 함수를 사용합니다:
```typescript
// src/services/firebaseAuth.ts
import { t } from "@/utils/i18n";
export function getErrorMessage(code: string): string {
switch (code) {
case "auth/invalid-email":
return t("errors.auth.invalidEmail");
case "auth/weak-password":
return t("errors.auth.weakPassword", { min: 8 });
default:
return t("errors.auth.unknown");
}
}
```
**파일 위치**: `src/utils/i18n.ts`
- `detectLocale()`: URL path 우선 → navigator.language fallback
- `t()`: nested key 지원, 파라미터 치환
---
## 체크리스트 (페이지/컴포넌트 생성 시)
- [ ] 모든 사용자 대면 텍스트를 번역 키로 추출
- [ ] `messages/ko.json`, `messages/en.json`, `messages/ja.json`에 번역 추가
- [ ] `useTranslations` 훅 사용 (Client Component)
- [ ] `getTranslations` 함수 사용 (Server Component)
- [ ] next-intl의 Link/Router 사용
- [ ] 파라미터가 있는 경우 `{name}` 플레이스홀더 사용
- [ ] 일본어는 어린이 친화적 표현 (한자 최소화, ひらがな 우선)
---
## 일본어 번역 주의사항
- **한자 최소화**: 초등학생 대상이므로 가능한 한 히라가나 사용
- **정중한 표현**: です/ます 체 사용
- **예시**:
```json
// ❌ Bad
"login": "ログイン"
// ✅ Good
"login": "ログインする"
```
---
## 언어별 파일
| 언어 | 파일 | 라인 수 | 키 개수 |
|------|------|--------|--------|
| 한국어 | `messages/ko.json` | 407줄 | 220+ 키 |
| 영어 | `messages/en.json` | 407줄 | 220+ 키 |
| 일본어 | `messages/ja.json` | 407줄 | 220+ 키 |
---
## 언어 전환 UI
LocaleSwitcher 컴포넌트 (`src/components/layout/LocaleSwitcher.tsx`):
- 국기 이모지 (🇰🇷 🇺🇸 🇯🇵)
- 현재 언어 체크 표시
- Portal 사용 (z-index 이슈 방지)
---
## 설정 파일
### middleware.ts
```typescript
import createMiddleware from "next-intl/middleware";
import { routing } from "./i18n/routing";
export default createMiddleware(routing);
export const config = {
matcher: ["/", "/(ko|en|ja)/:path*"],
};
```
### i18n/routing.ts
```typescript
import { defineRouting } from "next-intl/routing";
export const routing = defineRouting({
locales: ["ko", "en", "ja"],
defaultLocale: "ko",
localePrefix: "always",
});
```
### next.config.ts
```typescript
import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin();
export default withNextIntl({
// ... other config
});
```
---
## 라우팅 구조
```
/ko/* - 한국어 페이지
/en/* - 영어 페이지
/ja/* - 일본어 페이지
```
- 브라우저 언어 자동 감지 (Accept-Language 헤더)
- NEXT_LOCALE 쿠키 저장
- localeDetection: true 설정
---
## 관련 문서
- [next-intl Documentation](https://next-intl-docs.vercel.app/)
- [CLAUDE.md](./CLAUDE.md) - 개발 가이드
- [TECH_STACK.md](./TECH_STACK.md) - 기술 스택
---
© 2024 BlueNovaLab. All rights reserved.