diff --git a/.cli/docs/architecture.md b/.cli/docs/architecture.md index 5a6c633..97b102b 100644 --- a/.cli/docs/architecture.md +++ b/.cli/docs/architecture.md @@ -71,6 +71,18 @@ - `/boarding` 라우트: 딥링크 호환을 위해 동일 form/model 재사용 - 메모/노트 입력은 탑승 생성 경로에서 제거됨 +## I18n 소유권 (1단계) + +- 지원 언어/기본값/카피 상수: `shared/config/i18n.ts` +- 초기 언어 결정/수동 고정 저장: `features/i18n/model/resolveInitialLocale.ts` +- 런타임 번역 접근(context/hook): `features/i18n/model/useI18n.tsx` +- 앱 초기 bootstrap + 수동 변경 UI(헤더 select): `features/i18n/ui/I18nLayoutShell.tsx` +- `app/layout.tsx`는 i18n shell을 마운트해 단일 URL에서 언어 상태만 관리한다 +- 우선순위: `수동 저장값(localStorage) > 브라우저 언어 > en` +- 지원 외 언어는 `en`으로 폴백한다 +- 페이지/UI 문구는 key(`lobby.*`, `flight.*`, `debrief.*`, `log.*`, `settings.*`, `routes.*`)로 관리한다 +- 항로 메타(`shared/config/routes.ts`)는 사용자 노출 문자열 대신 i18n key를 소유한다 + ## 변경 정책 - 구조 리팩토링은 명시적으로 요청되지 않는 한 동작을 바꾸면 안 된다 diff --git a/src/app/boarding/page.tsx b/src/app/boarding/page.tsx index 1cd2305..ef28467 100644 --- a/src/app/boarding/page.tsx +++ b/src/app/boarding/page.tsx @@ -4,15 +4,18 @@ import { Suspense } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { ROUTES } from '@/shared/config/routes'; import { BoardingMissionForm, startVoyage } from '@/features/boarding'; +import { useI18n } from '@/features/i18n/model/useI18n'; function BoardingContent() { + const { t } = useI18n(); const router = useRouter(); const searchParams = useSearchParams(); const routeId = searchParams.get('routeId'); const route = ROUTES.find(r => r.id === routeId) || ROUTES[0]; + const routeName = t(route.nameKey, undefined, route.id); const handleDocking = (mission: string) => { - const started = startVoyage({ route, mission }); + const started = startVoyage({ route, mission, routeName }); if (!started) return; router.push('/flight'); }; @@ -20,8 +23,12 @@ function BoardingContent() { return (
이번 항해를 짧게 기록하고 마무리하세요.
+{t('debrief.page.description')}