diff --git a/frontend/src/features/vessel/VesselDetail.tsx b/frontend/src/features/vessel/VesselDetail.tsx
index 22491c5..905d75d 100644
--- a/frontend/src/features/vessel/VesselDetail.tsx
+++ b/frontend/src/features/vessel/VesselDetail.tsx
@@ -201,11 +201,11 @@ export function VesselDetail() {
선박 상세 조회
시작/종료
- setStartDate(e.target.value)}
+ setStartDate(e.target.value)}
className="flex-1 bg-surface-overlay border border-slate-700/50 rounded px-2 py-1 text-[10px] text-label focus:outline-none focus:border-blue-500/50"
placeholder="YYYY-MM-DD HH:mm" />
~
- setEndDate(e.target.value)}
+ setEndDate(e.target.value)}
className="flex-1 bg-surface-overlay border border-slate-700/50 rounded px-2 py-1 text-[10px] text-label focus:outline-none focus:border-blue-500/50"
placeholder="YYYY-MM-DD HH:mm" />
diff --git a/frontend/src/lib/i18n/locales/en/common.json b/frontend/src/lib/i18n/locales/en/common.json
index 3d4d331..090666d 100644
--- a/frontend/src/lib/i18n/locales/en/common.json
+++ b/frontend/src/lib/i18n/locales/en/common.json
@@ -250,5 +250,84 @@
"statistics": "Statistics",
"aiOps": "AI Ops",
"admin": "Admin"
+ },
+ "aria": {
+ "close": "Close",
+ "closeDialog": "Close dialog",
+ "closeNotification": "Close notification",
+ "edit": "Edit",
+ "delete": "Delete",
+ "search": "Search",
+ "clearSearch": "Clear search",
+ "searchInPage": "Search in page",
+ "refresh": "Refresh",
+ "filter": "Filter",
+ "filterToggle": "Toggle filter",
+ "filterReset": "Reset filter",
+ "statusFilter": "Status filter",
+ "scopeFilter": "Scope filter",
+ "groupTypeFilter": "Group type filter",
+ "categoryFilter": "Category filter",
+ "regionFilter": "Region filter",
+ "previous": "Previous",
+ "next": "Next",
+ "send": "Send",
+ "confirmAction": "Confirm",
+ "dateFrom": "Start date",
+ "dateTo": "End date",
+ "queryFrom": "Query start time",
+ "queryTo": "Query end time",
+ "roleCode": "Role code",
+ "roleName": "Role name",
+ "roleDesc": "Role description",
+ "groupKey": "Group key",
+ "subClusterId": "Sub cluster ID",
+ "excludedMmsi": "Excluded MMSI",
+ "exclusionReason": "Exclusion reason",
+ "globalExclusionReason": "Global exclusion reason",
+ "correctParentMmsi": "Correct parent MMSI",
+ "uploadPanelClose": "Close upload panel",
+ "noticeTitle": "Notice title",
+ "noticeContent": "Notice content",
+ "languageToggle": "Language toggle",
+ "searchCode": "Search code",
+ "searchAreaOrZone": "Search area or zone",
+ "areaOfInterestSelect": "Select area of interest",
+ "replayPosition": "Replay position",
+ "replayClose": "Close replay",
+ "miniMapClose": "Close mini map",
+ "memberCountMin": "Min members",
+ "memberCountMax": "Max members",
+ "receiptDate": "Receipt reference date",
+ "copyExampleUrl": "Copy example URL",
+ "vesselDetail": "Vessel detail",
+ "enforcementRegister": "Register enforcement",
+ "falsePositiveProcess": "Mark false positive"
+ },
+ "error": {
+ "operationFailed": "Operation failed: {{msg}}",
+ "createFailed": "Create failed: {{msg}}",
+ "updateFailed": "Update failed: {{msg}}",
+ "deleteFailed": "Delete failed: {{msg}}",
+ "registerFailed": "Register failed: {{msg}}",
+ "processFailed": "Process failed: {{msg}}",
+ "errorPrefix": "Error: {{msg}}"
+ },
+ "dialog": {
+ "cancelSession": "Cancel this session?",
+ "deleteRole": "Delete this role?",
+ "genericDelete": "Delete?",
+ "genericRemove": "Remove?"
+ },
+ "success": {
+ "permissionUpdated": "Permissions updated",
+ "saved": "Saved"
+ },
+ "message": {
+ "noPermission": "No access permission",
+ "loading": "Loading...",
+ "builtinRoleCannotDelete": "Built-in role cannot be deleted",
+ "switchToEnglish": "Switch to English",
+ "switchToKorean": "Switch to Korean"
}
}
diff --git a/frontend/src/lib/i18n/locales/ko/common.json b/frontend/src/lib/i18n/locales/ko/common.json
index c4ee620..1414556 100644
--- a/frontend/src/lib/i18n/locales/ko/common.json
+++ b/frontend/src/lib/i18n/locales/ko/common.json
@@ -250,5 +250,84 @@
"statistics": "통계·보고",
"aiOps": "AI 운영",
"admin": "시스템 관리"
+ },
+ "aria": {
+ "close": "닫기",
+ "closeDialog": "대화상자 닫기",
+ "closeNotification": "알림 닫기",
+ "edit": "편집",
+ "delete": "삭제",
+ "search": "검색",
+ "clearSearch": "검색어 지우기",
+ "searchInPage": "페이지 내 검색",
+ "refresh": "새로고침",
+ "filter": "필터",
+ "filterToggle": "필터 설정",
+ "filterReset": "필터 초기화",
+ "statusFilter": "상태 필터",
+ "scopeFilter": "스코프 필터",
+ "groupTypeFilter": "그룹 유형 필터",
+ "categoryFilter": "대분류 필터",
+ "regionFilter": "해역 필터",
+ "previous": "이전",
+ "next": "다음",
+ "send": "전송",
+ "confirmAction": "확인",
+ "dateFrom": "시작일",
+ "dateTo": "종료일",
+ "queryFrom": "조회 시작 시각",
+ "queryTo": "조회 종료 시각",
+ "roleCode": "역할 코드",
+ "roleName": "역할 이름",
+ "roleDesc": "역할 설명",
+ "groupKey": "그룹 키",
+ "subClusterId": "서브 클러스터 ID",
+ "excludedMmsi": "제외 MMSI",
+ "exclusionReason": "제외 사유",
+ "globalExclusionReason": "전역 제외 사유",
+ "correctParentMmsi": "정답 parent MMSI",
+ "uploadPanelClose": "업로드 패널 닫기",
+ "noticeTitle": "알림 제목",
+ "noticeContent": "알림 내용",
+ "languageToggle": "언어 전환",
+ "searchCode": "코드 검색",
+ "searchAreaOrZone": "해역 또는 해구 번호 검색",
+ "areaOfInterestSelect": "관심영역 선택",
+ "replayPosition": "재생 위치",
+ "replayClose": "재생 닫기",
+ "miniMapClose": "미니맵 닫기",
+ "memberCountMin": "최소 멤버 수",
+ "memberCountMax": "최대 멤버 수",
+ "receiptDate": "수신 현황 기준일",
+ "copyExampleUrl": "예시 URL 복사",
+ "vesselDetail": "선박 상세",
+ "enforcementRegister": "단속 등록",
+ "falsePositiveProcess": "오탐 처리"
+ },
+ "error": {
+ "operationFailed": "작업 실패: {{msg}}",
+ "createFailed": "생성 실패: {{msg}}",
+ "updateFailed": "갱신 실패: {{msg}}",
+ "deleteFailed": "삭제 실패: {{msg}}",
+ "registerFailed": "등록 실패: {{msg}}",
+ "processFailed": "처리 실패: {{msg}}",
+ "errorPrefix": "에러: {{msg}}"
+ },
+ "dialog": {
+ "cancelSession": "세션을 취소하시겠습니까?",
+ "deleteRole": "해당 역할을 삭제하시겠습니까?",
+ "genericDelete": "삭제하시겠습니까?",
+ "genericRemove": "제거하시겠습니까?"
+ },
+ "success": {
+ "permissionUpdated": "권한 갱신",
+ "saved": "저장되었습니다"
+ },
+ "message": {
+ "noPermission": "접근 권한이 없습니다",
+ "loading": "로딩 중...",
+ "builtinRoleCannotDelete": "내장 역할은 삭제할 수 없습니다",
+ "switchToEnglish": "Switch to English",
+ "switchToKorean": "한국어로 전환"
}
}
diff --git a/frontend/src/shared/components/common/NotificationBanner.tsx b/frontend/src/shared/components/common/NotificationBanner.tsx
index 9fcf6f8..94d4686 100644
--- a/frontend/src/shared/components/common/NotificationBanner.tsx
+++ b/frontend/src/shared/components/common/NotificationBanner.tsx
@@ -1,5 +1,6 @@
import { useState, useEffect } from 'react';
import { X, AlertTriangle, Info, Bell, Megaphone } from 'lucide-react';
+import { useTranslation } from 'react-i18next';
/*
* SFR-02 공통컴포넌트: 알림 배너/팝업
@@ -36,6 +37,7 @@ interface NotificationBannerProps {
}
export function NotificationBanner({ notices, userRole }: NotificationBannerProps) {
+ const { t } = useTranslation('common');
const [dismissed, setDismissed] = useState
>(() => {
const stored = sessionStorage.getItem('dismissed_notices');
return new Set(stored ? JSON.parse(stored) : []);
@@ -80,7 +82,7 @@ export function NotificationBanner({ notices, userRole }: NotificationBannerProp
{notice.dismissible && (