From 8af693a2dfebaed21723091551408f72e7db882e Mon Sep 17 00:00:00 2001 From: htlee Date: Thu, 16 Apr 2026 16:32:37 +0900 Subject: [PATCH] =?UTF-8?q?refactor(i18n):=20alert/confirm/aria-label=20?= =?UTF-8?q?=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20=ED=95=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 공통 번역 리소스 확장: - common.json 에 aria / error / dialog / success / message 네임스페이스 추가 - ko/en 양쪽 동일 구조 유지 (aria 36 키 + error 7 키 + dialog 4 키 + message 5 키) alert/confirm 11건 → t() 치환: - parent-inference: ParentReview / LabelSession / ParentExclusion - admin: PermissionsPanel / UserRoleAssignDialog / AccessControl aria-label 한글 40+건 → t() 치환: - parent-inference (group_key/sub_cluster/정답 parent MMSI/스코프 필터 등) - admin (역할 코드/이름, 알림 제목/내용, 시작일/종료일, 코드 검색, 대분류 필터, 수신 현황 기준일) - detection (그룹 유형/해역 필터, 관심영역, 필터 설정/초기화, 멤버 수, 미니맵/재생 닫기) - enforcement (확인/선박 상세/단속 등록/오탐 처리) - vessel/statistics/ai-operations (조회 시작/종료 시각, 업로드 패널 닫기, 전송, 예시 URL 복사) - 공통 컴포넌트 (SearchInput, NotificationBanner) MainLayout 언어 토글: - title 삼항분기 → t('message.switchToEnglish'/'switchToKorean') - aria-label="페이지 내 검색" → t('aria.searchInPage') - 토글 버튼 자체에 aria-label={t('aria.languageToggle')} 추가 --- frontend/src/app/layout/MainLayout.tsx | 5 +- frontend/src/features/admin/AccessControl.tsx | 4 +- frontend/src/features/admin/DataHub.tsx | 3 +- .../src/features/admin/NoticeManagement.tsx | 11 +-- .../src/features/admin/PermissionsPanel.tsx | 22 +++--- frontend/src/features/admin/SystemConfig.tsx | 5 +- .../features/admin/UserRoleAssignDialog.tsx | 6 +- .../features/ai-operations/AIAssistant.tsx | 3 +- .../ai-operations/AIModelManagement.tsx | 2 +- .../src/features/ai-operations/MLOpsPage.tsx | 3 +- .../src/features/detection/ChinaFishing.tsx | 8 +- .../src/features/detection/GearDetection.tsx | 10 +-- .../src/features/detection/RealGearGroups.tsx | 2 +- .../features/detection/RealVesselAnalysis.tsx | 2 +- .../detection/components/DarkDetailPanel.tsx | 4 +- .../detection/components/GearDetailPanel.tsx | 3 +- .../components/GearReplayController.tsx | 6 +- .../detection/components/VesselMiniMap.tsx | 4 +- .../src/features/enforcement/EventList.tsx | 8 +- .../parent-inference/LabelSession.tsx | 16 ++-- .../parent-inference/ParentExclusion.tsx | 24 +++--- .../parent-inference/ParentReview.tsx | 10 +-- .../features/statistics/ReportManagement.tsx | 3 +- frontend/src/features/vessel/VesselDetail.tsx | 4 +- frontend/src/lib/i18n/locales/en/common.json | 79 +++++++++++++++++++ frontend/src/lib/i18n/locales/ko/common.json | 79 +++++++++++++++++++ .../components/common/NotificationBanner.tsx | 4 +- .../shared/components/common/SearchInput.tsx | 11 ++- 28 files changed, 262 insertions(+), 79 deletions(-) diff --git a/frontend/src/app/layout/MainLayout.tsx b/frontend/src/app/layout/MainLayout.tsx index 115a90e..2ce6dcb 100644 --- a/frontend/src/app/layout/MainLayout.tsx +++ b/frontend/src/app/layout/MainLayout.tsx @@ -282,8 +282,9 @@ export function MainLayout() { {/* 언어 토글 */} @@ -338,7 +339,7 @@ export function MainLayout() {
setPageSearch(e.target.value)} onKeyDown={(e) => { diff --git a/frontend/src/features/admin/AccessControl.tsx b/frontend/src/features/admin/AccessControl.tsx index a8308dc..c9fd72e 100644 --- a/frontend/src/features/admin/AccessControl.tsx +++ b/frontend/src/features/admin/AccessControl.tsx @@ -94,12 +94,12 @@ export function AccessControl() { }, [tab, loadUsers, loadAudit]); const handleUnlock = async (userId: string, acnt: string) => { - if (!confirm(`계정 ${acnt} 잠금을 해제하시겠습니까?`)) return; + if (!confirm(`${acnt} ${tc('dialog.genericRemove')}`)) return; try { await unlockUser(userId); await loadUsers(); } catch (e: unknown) { - alert('실패: ' + (e instanceof Error ? e.message : 'unknown')); + alert(tc('error.operationFailed', { msg: e instanceof Error ? e.message : 'unknown' })); } }; diff --git a/frontend/src/features/admin/DataHub.tsx b/frontend/src/features/admin/DataHub.tsx index 38a57a4..5b3ba0b 100644 --- a/frontend/src/features/admin/DataHub.tsx +++ b/frontend/src/features/admin/DataHub.tsx @@ -341,6 +341,7 @@ type Tab = 'signal' | 'monitor' | 'collect' | 'load' | 'agents'; export function DataHub() { const { t } = useTranslation('admin'); + const { t: tc } = useTranslation('common'); const [tab, setTab] = useState('signal'); const [selectedDate, setSelectedDate] = useState('2026-04-02'); const [statusFilter, setStatusFilter] = useState<'' | 'ON' | 'OFF'>(''); @@ -442,7 +443,7 @@ export function DataHub() {
setSelectedDate(e.target.value)} diff --git a/frontend/src/features/admin/NoticeManagement.tsx b/frontend/src/features/admin/NoticeManagement.tsx index 8d1a5b0..3017241 100644 --- a/frontend/src/features/admin/NoticeManagement.tsx +++ b/frontend/src/features/admin/NoticeManagement.tsx @@ -74,6 +74,7 @@ const ROLE_OPTIONS = ['ADMIN', 'OPERATOR', 'ANALYST', 'FIELD', 'VIEWER']; export function NoticeManagement() { const { t } = useTranslation('admin'); + const { t: tc } = useTranslation('common'); const { hasPermission } = useAuth(); const canCreate = hasPermission('admin:notices', 'CREATE'); const canUpdate = hasPermission('admin:notices', 'UPDATE'); @@ -265,7 +266,7 @@ export function NoticeManagement() { {editingId ? '알림 수정' : '새 알림 등록'} -
@@ -275,7 +276,7 @@ export function NoticeManagement() {
setForm({ ...form, title: e.target.value })} className="w-full bg-surface-overlay border border-slate-700/50 rounded-lg px-3 py-2 text-[11px] text-heading placeholder:text-hint focus:outline-none focus:border-blue-500/50" @@ -287,7 +288,7 @@ export function NoticeManagement() {