Refactor selected-room dashboard activity fetching, split Rooms i18n, and tighten mobile usage layout.
1330 lines
33 KiB
TypeScript
1330 lines
33 KiB
TypeScript
import { roomMessages, type RoomMessages } from './i18n/rooms';
|
|
|
|
export const LOCALES = ['ko', 'en', 'zh', 'ja'] as const;
|
|
|
|
export type Locale = (typeof LOCALES)[number];
|
|
|
|
export interface Messages {
|
|
app: {
|
|
loading: string;
|
|
};
|
|
actions: {
|
|
close: string;
|
|
refresh: string;
|
|
refreshing: string;
|
|
retry: string;
|
|
};
|
|
nav: {
|
|
aria: string;
|
|
drawerAria: string;
|
|
drawerNavAria: string;
|
|
menuOpen: string;
|
|
menuClose: string;
|
|
operations: string;
|
|
updated: string;
|
|
health: string;
|
|
inbox: string;
|
|
usage: string;
|
|
rooms: string;
|
|
scheduled: string;
|
|
settings: string;
|
|
};
|
|
language: {
|
|
label: string;
|
|
};
|
|
settings: {
|
|
title: string;
|
|
nicknameLabel: string;
|
|
nicknamePlaceholder: string;
|
|
nicknameHelp: string;
|
|
languageLabel: string;
|
|
};
|
|
error: {
|
|
api: string;
|
|
network: string;
|
|
timeout: string;
|
|
server: string;
|
|
notFound: string;
|
|
auth: string;
|
|
unknown: string;
|
|
};
|
|
control: {
|
|
aria: string;
|
|
queue: string;
|
|
activeRooms: string;
|
|
pendingRooms: string;
|
|
};
|
|
pwa: {
|
|
app: string;
|
|
install: string;
|
|
installed: string;
|
|
ready: string;
|
|
cached: string;
|
|
online: string;
|
|
offline: string;
|
|
fresh: string;
|
|
stale: string;
|
|
secureRequired: string;
|
|
updated: string;
|
|
};
|
|
metrics: {
|
|
agents: string;
|
|
rooms: string;
|
|
ciWatchers: string;
|
|
};
|
|
panels: {
|
|
health: string;
|
|
heartbeat: string;
|
|
healthSignals: string;
|
|
inbox: string;
|
|
inboxQueue: string;
|
|
usage: string;
|
|
usageWindow: string;
|
|
rooms: string;
|
|
queue: string;
|
|
scheduled: string;
|
|
promptPreviews: string;
|
|
};
|
|
service: {
|
|
empty: string;
|
|
heartbeat: string;
|
|
service: string;
|
|
rooms: string;
|
|
updated: string;
|
|
};
|
|
health: {
|
|
system: string;
|
|
signals: string;
|
|
services: string;
|
|
fresh: string;
|
|
stale: string;
|
|
queue: string;
|
|
ciFailures: string;
|
|
affectedServices: string;
|
|
restart: string;
|
|
restartStack: string;
|
|
restarting: string;
|
|
restartHint: string;
|
|
confirmRestart: string;
|
|
restartLog: string;
|
|
restartTarget: string;
|
|
restartStatus: string;
|
|
restartRequested: string;
|
|
restartServices: string;
|
|
levels: {
|
|
ok: string;
|
|
stale: string;
|
|
down: string;
|
|
};
|
|
};
|
|
inbox: {
|
|
empty: string;
|
|
cardsAria: string;
|
|
summary: string;
|
|
total: string;
|
|
filters: string;
|
|
all: string;
|
|
noSummary: string;
|
|
occurred: string;
|
|
source: string;
|
|
target: string;
|
|
openTask: string;
|
|
openRoom: string;
|
|
kinds: {
|
|
'pending-room': string;
|
|
'reviewer-request': string;
|
|
approval: string;
|
|
'arbiter-request': string;
|
|
'ci-failure': string;
|
|
mention: string;
|
|
};
|
|
severity: {
|
|
info: string;
|
|
warn: string;
|
|
error: string;
|
|
};
|
|
actions: {
|
|
run: string;
|
|
busy: string;
|
|
runReview: string;
|
|
finalize: string;
|
|
runArbiter: string;
|
|
decline: string;
|
|
dismiss: string;
|
|
confirmDecline: string;
|
|
};
|
|
};
|
|
rooms: RoomMessages;
|
|
usage: {
|
|
empty: string;
|
|
current: string;
|
|
tightest: string;
|
|
watch: string;
|
|
remaining: string;
|
|
speed: string;
|
|
inUse: string;
|
|
reset: string;
|
|
noReset: string;
|
|
limitBasis: {
|
|
h5: string;
|
|
d7: string;
|
|
};
|
|
quota: {
|
|
h5: string;
|
|
d7: string;
|
|
};
|
|
usage: string;
|
|
groupPrimary: string;
|
|
groupCodex: string;
|
|
risk: {
|
|
ok: string;
|
|
warn: string;
|
|
critical: string;
|
|
};
|
|
speedLabel: {
|
|
ok: string;
|
|
warn: string;
|
|
critical: string;
|
|
};
|
|
};
|
|
tasks: {
|
|
empty: string;
|
|
cardsAria: string;
|
|
groups: {
|
|
watchers: string;
|
|
scheduled: string;
|
|
paused: string;
|
|
completed: string;
|
|
};
|
|
count: string;
|
|
groupEmpty: string;
|
|
task: string;
|
|
status: string;
|
|
schedule: string;
|
|
next: string;
|
|
last: string;
|
|
context: string;
|
|
ciWatch: string;
|
|
emptyPrompt: string;
|
|
prompt: string;
|
|
until: string;
|
|
suspendedUntil: string;
|
|
lastResult: string;
|
|
result: string;
|
|
resultOk: string;
|
|
resultFail: string;
|
|
noResult: string;
|
|
noTime: string;
|
|
now: string;
|
|
createTitle: string;
|
|
createSubtitle: string;
|
|
room: string;
|
|
selectRoom: string;
|
|
scheduleType: string;
|
|
scheduleValue: string;
|
|
scheduleValueHint: string;
|
|
promptPlaceholder: string;
|
|
editPromptPlaceholder: string;
|
|
scheduleTypes: {
|
|
once: string;
|
|
interval: string;
|
|
cron: string;
|
|
};
|
|
contextModes: {
|
|
isolated: string;
|
|
group: string;
|
|
};
|
|
actions: {
|
|
create: string;
|
|
edit: string;
|
|
save: string;
|
|
pause: string;
|
|
resume: string;
|
|
cancel: string;
|
|
busy: string;
|
|
confirmCancel: string;
|
|
};
|
|
};
|
|
status: {
|
|
processing: string;
|
|
waiting: string;
|
|
inactive: string;
|
|
active: string;
|
|
paused: string;
|
|
completed: string;
|
|
};
|
|
units: {
|
|
second: string;
|
|
minute: string;
|
|
hour: string;
|
|
task: string;
|
|
messageShort: string;
|
|
chars: string;
|
|
};
|
|
}
|
|
|
|
export const languageNames: Record<Locale, string> = {
|
|
ko: '한국어',
|
|
en: 'English',
|
|
zh: '简体中文',
|
|
ja: '日本語',
|
|
};
|
|
|
|
export const localeTags: Record<Locale, string> = {
|
|
ko: 'ko-KR',
|
|
en: 'en-US',
|
|
zh: 'zh-CN',
|
|
ja: 'ja-JP',
|
|
};
|
|
|
|
export const messages = {
|
|
ko: {
|
|
app: {
|
|
loading: '대시보드 로딩 중',
|
|
},
|
|
actions: {
|
|
close: '닫기',
|
|
refresh: '새로고침',
|
|
refreshing: '새로고침 중',
|
|
retry: '다시 시도',
|
|
},
|
|
nav: {
|
|
aria: '대시보드 섹션',
|
|
drawerAria: '대시보드 메뉴',
|
|
drawerNavAria: '대시보드 메뉴 섹션',
|
|
menuOpen: '메뉴 열기',
|
|
menuClose: '메뉴 닫기',
|
|
operations: '운영',
|
|
updated: '갱신',
|
|
health: '상태',
|
|
inbox: 'Inbox',
|
|
usage: '사용량',
|
|
rooms: '룸',
|
|
scheduled: '예약',
|
|
settings: '설정',
|
|
},
|
|
language: {
|
|
label: '언어',
|
|
},
|
|
settings: {
|
|
title: '설정',
|
|
nicknameLabel: '닉네임',
|
|
nicknamePlaceholder: 'Web Dashboard',
|
|
nicknameHelp: '룸에서 메시지 보낼 때 표시될 이름',
|
|
languageLabel: '언어',
|
|
},
|
|
error: {
|
|
api: '문제 발생',
|
|
network: '네트워크 연결 확인 후 다시 시도해주세요.',
|
|
timeout: '응답 시간이 초과됐어요. 잠시 후 다시 시도해주세요.',
|
|
server: '서버에 일시적인 문제가 있어요. 잠시 후 다시 시도해주세요.',
|
|
notFound: '요청한 정보를 찾을 수 없어요.',
|
|
auth: '권한이 없어요. 다시 로그인해주세요.',
|
|
unknown: '알 수 없는 오류가 발생했어요.',
|
|
},
|
|
control: {
|
|
aria: '컨트롤 플레인 요약',
|
|
queue: '작업 큐',
|
|
activeRooms: '처리 + 대기 룸',
|
|
pendingRooms: '메시지 대기 룸',
|
|
},
|
|
pwa: {
|
|
app: 'PWA',
|
|
install: '설치',
|
|
installed: '설치됨',
|
|
ready: '오프라인 준비',
|
|
cached: '캐시됨',
|
|
online: '온라인',
|
|
offline: '오프라인',
|
|
fresh: '최신',
|
|
stale: '지연',
|
|
secureRequired: 'HTTPS 필요',
|
|
updated: '갱신',
|
|
},
|
|
metrics: {
|
|
agents: '에이전트',
|
|
rooms: '룸',
|
|
ciWatchers: 'CI 감시',
|
|
},
|
|
panels: {
|
|
health: '상태',
|
|
heartbeat: '하트비트',
|
|
healthSignals: '운영 신호',
|
|
inbox: 'Inbox',
|
|
inboxQueue: 'Queue',
|
|
usage: '사용량',
|
|
usageWindow: '남음 / 속도',
|
|
rooms: '룸',
|
|
queue: '큐',
|
|
scheduled: '예약',
|
|
promptPreviews: '프롬프트 미리보기',
|
|
},
|
|
service: {
|
|
empty: '하트비트 없음. 서비스 로그 확인.',
|
|
heartbeat: '하트비트',
|
|
service: '서비스',
|
|
rooms: '룸',
|
|
updated: '갱신',
|
|
},
|
|
health: {
|
|
system: '시스템',
|
|
signals: '헬스 신호',
|
|
services: '서비스',
|
|
fresh: '정상',
|
|
stale: '지연',
|
|
queue: '큐',
|
|
ciFailures: 'CI 실패',
|
|
affectedServices: '이상 서비스',
|
|
restart: '재시작',
|
|
restartStack: '스택 재시작',
|
|
restarting: '재시작 중...',
|
|
restartHint: '서비스 전체 재시작',
|
|
confirmRestart: 'Restart stack now?',
|
|
restartLog: 'Restart log',
|
|
restartTarget: 'Target',
|
|
restartStatus: 'Status',
|
|
restartRequested: 'Requested',
|
|
restartServices: 'Services',
|
|
levels: {
|
|
ok: '정상',
|
|
stale: '주의',
|
|
down: '중단',
|
|
},
|
|
},
|
|
inbox: {
|
|
empty: 'Inbox 없음.',
|
|
cardsAria: 'Inbox 항목',
|
|
summary: 'Inbox 요약',
|
|
total: '전체',
|
|
filters: 'Inbox 필터',
|
|
all: '전체',
|
|
noSummary: '요약 없음',
|
|
occurred: '발생',
|
|
source: '소스',
|
|
target: '대상',
|
|
openTask: '예약 보기',
|
|
openRoom: '룸 보기',
|
|
kinds: {
|
|
'pending-room': '대기 룸',
|
|
'reviewer-request': '리뷰 요청',
|
|
approval: '승인',
|
|
'arbiter-request': '중재 요청',
|
|
'ci-failure': 'CI 실패',
|
|
mention: '멘션',
|
|
},
|
|
severity: {
|
|
info: '정보',
|
|
warn: '주의',
|
|
error: '위험',
|
|
},
|
|
actions: {
|
|
run: 'Run',
|
|
busy: 'Running...',
|
|
runReview: 'Run review',
|
|
finalize: 'Finalize',
|
|
runArbiter: 'Run arbiter',
|
|
decline: 'Decline',
|
|
dismiss: 'Dismiss',
|
|
confirmDecline: 'Decline this item?',
|
|
},
|
|
},
|
|
rooms: roomMessages.ko,
|
|
usage: {
|
|
empty: '사용량 스냅샷 없음. 수집기 확인.',
|
|
current: '사용중',
|
|
tightest: '가장 적음',
|
|
watch: '주의',
|
|
remaining: '남음',
|
|
speed: '속도',
|
|
inUse: '사용중',
|
|
reset: '리셋',
|
|
noReset: '리셋 없음',
|
|
limitBasis: {
|
|
h5: '5시간 기준',
|
|
d7: '7일 기준',
|
|
},
|
|
quota: {
|
|
h5: '5시간',
|
|
d7: '7일',
|
|
},
|
|
usage: '사용량',
|
|
groupPrimary: 'Claude / Kimi',
|
|
groupCodex: 'Codex',
|
|
risk: {
|
|
ok: '여유',
|
|
warn: '주의',
|
|
critical: '위험',
|
|
},
|
|
speedLabel: {
|
|
ok: '보통',
|
|
warn: '빠름',
|
|
critical: '너무 빠름',
|
|
},
|
|
},
|
|
tasks: {
|
|
empty: '예약 작업 없음.',
|
|
cardsAria: '예약 작업 카드',
|
|
groups: {
|
|
watchers: 'CI 감시',
|
|
scheduled: '예약',
|
|
paused: '일시정지',
|
|
completed: '완료',
|
|
},
|
|
count: '개',
|
|
groupEmpty: '해당 없음',
|
|
task: '작업',
|
|
status: '상태',
|
|
schedule: '스케줄',
|
|
next: '다음',
|
|
last: '최근',
|
|
context: '컨텍스트',
|
|
ciWatch: 'CI 감시',
|
|
emptyPrompt: '(빈 미리보기)',
|
|
prompt: '프롬프트',
|
|
until: '까지',
|
|
suspendedUntil: '정지 해제',
|
|
lastResult: '최근 결과',
|
|
result: '결과 없음',
|
|
resultOk: '정상',
|
|
resultFail: '실패',
|
|
noResult: '결과 없음',
|
|
noTime: '-',
|
|
now: '지금',
|
|
createTitle: 'Create task',
|
|
createSubtitle: 'Schedule work from web',
|
|
room: 'Room',
|
|
selectRoom: 'Select room',
|
|
scheduleType: 'Type',
|
|
scheduleValue: 'Value',
|
|
scheduleValueHint: 'ISO time, ms, or cron',
|
|
promptPlaceholder: 'What should the agent do?',
|
|
editPromptPlaceholder: 'Leave blank to keep prompt',
|
|
scheduleTypes: {
|
|
once: 'Once',
|
|
interval: 'Interval',
|
|
cron: 'Cron',
|
|
},
|
|
contextModes: {
|
|
isolated: 'Isolated',
|
|
group: 'Group',
|
|
},
|
|
actions: {
|
|
create: 'Create',
|
|
edit: 'Edit',
|
|
save: 'Save',
|
|
pause: 'Pause',
|
|
resume: 'Resume',
|
|
cancel: 'Cancel',
|
|
busy: 'Working',
|
|
confirmCancel: 'Cancel this scheduled work?',
|
|
},
|
|
},
|
|
status: {
|
|
processing: '처리중',
|
|
waiting: '대기',
|
|
inactive: '휴면',
|
|
active: '활성',
|
|
paused: '일시정지',
|
|
completed: '완료',
|
|
},
|
|
units: {
|
|
second: '초',
|
|
minute: '분',
|
|
hour: '시간',
|
|
task: '작업',
|
|
messageShort: '메시지',
|
|
chars: '자',
|
|
},
|
|
},
|
|
en: {
|
|
app: {
|
|
loading: 'Loading dashboard',
|
|
},
|
|
actions: {
|
|
close: 'Close',
|
|
refresh: 'Refresh',
|
|
refreshing: 'Refreshing',
|
|
retry: 'Retry',
|
|
},
|
|
nav: {
|
|
aria: 'Dashboard sections',
|
|
drawerAria: 'Dashboard menu',
|
|
drawerNavAria: 'Dashboard menu sections',
|
|
menuOpen: 'Open menu',
|
|
menuClose: 'Close menu',
|
|
operations: 'Ops',
|
|
updated: 'Updated',
|
|
health: 'Health',
|
|
inbox: 'Inbox',
|
|
usage: 'Usage',
|
|
rooms: 'Rooms',
|
|
scheduled: 'Scheduled',
|
|
settings: 'Settings',
|
|
},
|
|
language: {
|
|
label: 'Language',
|
|
},
|
|
settings: {
|
|
title: 'Settings',
|
|
nicknameLabel: 'Nickname',
|
|
nicknamePlaceholder: 'Web Dashboard',
|
|
nicknameHelp: 'Name shown when sending messages from this dashboard',
|
|
languageLabel: 'Language',
|
|
},
|
|
error: {
|
|
api: 'Something went wrong',
|
|
network: 'Check your network connection and try again.',
|
|
timeout: 'The request timed out. Try again in a moment.',
|
|
server: 'Server hiccup. Try again in a bit.',
|
|
notFound: "We couldn't find what you asked for.",
|
|
auth: 'Sign in again to continue.',
|
|
unknown: 'An unexpected error occurred.',
|
|
},
|
|
control: {
|
|
aria: 'Control plane summary',
|
|
queue: 'Work queue',
|
|
activeRooms: 'processing + waiting rooms',
|
|
pendingRooms: 'rooms with pending messages',
|
|
},
|
|
pwa: {
|
|
app: 'PWA',
|
|
install: 'Install',
|
|
installed: 'Installed',
|
|
ready: 'Offline ready',
|
|
cached: 'Cached',
|
|
online: 'Online',
|
|
offline: 'Offline',
|
|
fresh: 'Fresh',
|
|
stale: 'Stale',
|
|
secureRequired: 'HTTPS required',
|
|
updated: 'Updated',
|
|
},
|
|
metrics: {
|
|
agents: 'agents',
|
|
rooms: 'rooms',
|
|
ciWatchers: 'CI watchers',
|
|
},
|
|
panels: {
|
|
health: 'Health',
|
|
heartbeat: 'Heartbeat',
|
|
healthSignals: 'Signals',
|
|
inbox: 'Inbox',
|
|
inboxQueue: 'Queue',
|
|
usage: 'Usage',
|
|
usageWindow: 'Remaining / speed',
|
|
rooms: 'Rooms',
|
|
queue: 'Queue',
|
|
scheduled: 'Scheduled',
|
|
promptPreviews: 'Prompt previews',
|
|
},
|
|
service: {
|
|
empty: 'No heartbeat yet. Check service logs.',
|
|
heartbeat: 'heartbeat',
|
|
service: 'service',
|
|
rooms: 'rooms',
|
|
updated: 'updated',
|
|
},
|
|
health: {
|
|
system: 'System',
|
|
signals: 'Health signals',
|
|
services: 'Services',
|
|
fresh: 'Fresh',
|
|
stale: 'stale',
|
|
queue: 'Queue',
|
|
ciFailures: 'CI failures',
|
|
affectedServices: 'Affected services',
|
|
restart: 'Restart',
|
|
restartStack: 'Restart stack',
|
|
restarting: 'Restarting...',
|
|
restartHint: 'Restart all services',
|
|
confirmRestart: 'Restart stack now?',
|
|
restartLog: 'Restart log',
|
|
restartTarget: 'Target',
|
|
restartStatus: 'Status',
|
|
restartRequested: 'Requested',
|
|
restartServices: 'Services',
|
|
levels: {
|
|
ok: 'OK',
|
|
stale: 'Watch',
|
|
down: 'Down',
|
|
},
|
|
},
|
|
inbox: {
|
|
empty: 'No queued work.',
|
|
cardsAria: 'Inbox items',
|
|
summary: 'Inbox summary',
|
|
total: 'Total',
|
|
filters: 'Inbox filters',
|
|
all: 'All',
|
|
noSummary: 'No summary',
|
|
occurred: 'Occurred',
|
|
source: 'Source',
|
|
target: 'Target',
|
|
openTask: 'Open scheduled',
|
|
openRoom: 'Open room',
|
|
kinds: {
|
|
'pending-room': 'Pending room',
|
|
'reviewer-request': 'Review request',
|
|
approval: 'Approval',
|
|
'arbiter-request': 'Arbiter request',
|
|
'ci-failure': 'CI failure',
|
|
mention: 'Mention',
|
|
},
|
|
severity: {
|
|
info: 'Info',
|
|
warn: 'Warn',
|
|
error: 'Risk',
|
|
},
|
|
actions: {
|
|
run: 'Run',
|
|
busy: 'Running...',
|
|
runReview: 'Run review',
|
|
finalize: 'Finalize',
|
|
runArbiter: 'Run arbiter',
|
|
decline: 'Decline',
|
|
dismiss: 'Dismiss',
|
|
confirmDecline: 'Decline this item?',
|
|
},
|
|
},
|
|
rooms: roomMessages.en,
|
|
usage: {
|
|
empty: 'No usage snapshot. Check collector.',
|
|
current: 'Active',
|
|
tightest: 'Tightest',
|
|
watch: 'Watch',
|
|
remaining: 'Left',
|
|
speed: 'Rate',
|
|
inUse: 'active',
|
|
reset: 'reset',
|
|
noReset: 'no reset',
|
|
limitBasis: {
|
|
h5: '5h basis',
|
|
d7: '7d basis',
|
|
},
|
|
quota: {
|
|
h5: '5h',
|
|
d7: '7d',
|
|
},
|
|
usage: 'usage',
|
|
groupPrimary: 'Claude / Kimi',
|
|
groupCodex: 'Codex',
|
|
risk: {
|
|
ok: 'OK',
|
|
warn: 'Watch',
|
|
critical: 'Risk',
|
|
},
|
|
speedLabel: {
|
|
ok: 'OK',
|
|
warn: 'Fast',
|
|
critical: 'Too fast',
|
|
},
|
|
},
|
|
tasks: {
|
|
empty: 'No scheduled work.',
|
|
cardsAria: 'Scheduled task cards',
|
|
groups: {
|
|
watchers: 'CI watch',
|
|
scheduled: 'Scheduled',
|
|
paused: 'Paused',
|
|
completed: 'Completed',
|
|
},
|
|
count: 'items',
|
|
groupEmpty: 'None',
|
|
task: 'task',
|
|
status: 'status',
|
|
schedule: 'schedule',
|
|
next: 'next',
|
|
last: 'last',
|
|
context: 'context',
|
|
ciWatch: 'CI Watch',
|
|
emptyPrompt: '(empty preview)',
|
|
prompt: 'prompt',
|
|
until: 'until',
|
|
suspendedUntil: 'resume',
|
|
lastResult: 'last result',
|
|
result: 'no result',
|
|
resultOk: 'ok',
|
|
resultFail: 'failed',
|
|
noResult: 'no result',
|
|
noTime: '-',
|
|
now: 'now',
|
|
createTitle: 'Create task',
|
|
createSubtitle: 'Schedule work from web',
|
|
room: 'Room',
|
|
selectRoom: 'Select room',
|
|
scheduleType: 'Type',
|
|
scheduleValue: 'Value',
|
|
scheduleValueHint: 'ISO time, ms, or cron',
|
|
promptPlaceholder: 'What should the agent do?',
|
|
editPromptPlaceholder: 'Leave blank to keep prompt',
|
|
scheduleTypes: {
|
|
once: 'Once',
|
|
interval: 'Interval',
|
|
cron: 'Cron',
|
|
},
|
|
contextModes: {
|
|
isolated: 'Isolated',
|
|
group: 'Group',
|
|
},
|
|
actions: {
|
|
create: 'Create',
|
|
edit: 'Edit',
|
|
save: 'Save',
|
|
pause: 'Pause',
|
|
resume: 'Resume',
|
|
cancel: 'Cancel',
|
|
busy: 'Working',
|
|
confirmCancel: 'Cancel this scheduled work?',
|
|
},
|
|
},
|
|
status: {
|
|
processing: 'processing',
|
|
waiting: 'waiting',
|
|
inactive: 'inactive',
|
|
active: 'active',
|
|
paused: 'paused',
|
|
completed: 'completed',
|
|
},
|
|
units: {
|
|
second: 's',
|
|
minute: 'm',
|
|
hour: 'h',
|
|
task: 'task',
|
|
messageShort: 'msg',
|
|
chars: 'chars',
|
|
},
|
|
},
|
|
zh: {
|
|
app: {
|
|
loading: '正在加载仪表盘',
|
|
},
|
|
actions: {
|
|
close: '关闭',
|
|
refresh: '刷新',
|
|
refreshing: '刷新中',
|
|
retry: '重试',
|
|
},
|
|
nav: {
|
|
aria: '仪表盘分区',
|
|
drawerAria: '仪表盘菜单',
|
|
drawerNavAria: '仪表盘菜单分区',
|
|
menuOpen: '打开菜单',
|
|
menuClose: '关闭菜单',
|
|
operations: '运营',
|
|
updated: '更新',
|
|
health: '健康',
|
|
inbox: '收件',
|
|
usage: '用量',
|
|
rooms: '房间',
|
|
scheduled: '计划',
|
|
settings: '设置',
|
|
},
|
|
language: {
|
|
label: '语言',
|
|
},
|
|
settings: {
|
|
title: '设置',
|
|
nicknameLabel: '昵称',
|
|
nicknamePlaceholder: 'Web Dashboard',
|
|
nicknameHelp: '从此面板发送消息时显示的名称',
|
|
languageLabel: '语言',
|
|
},
|
|
error: {
|
|
api: '发生问题',
|
|
network: '请检查网络连接后重试。',
|
|
timeout: '请求超时,请稍后重试。',
|
|
server: '服务器暂时出现问题,请稍后重试。',
|
|
notFound: '找不到所请求的信息。',
|
|
auth: '没有权限,请重新登录。',
|
|
unknown: '发生未知错误。',
|
|
},
|
|
control: {
|
|
aria: '控制平面摘要',
|
|
queue: '任务队列',
|
|
activeRooms: '处理中 + 等待房间',
|
|
pendingRooms: '有待处理消息的房间',
|
|
},
|
|
pwa: {
|
|
app: 'PWA',
|
|
install: '安装',
|
|
installed: '已安装',
|
|
ready: '离线可用',
|
|
cached: '已缓存',
|
|
online: '在线',
|
|
offline: '离线',
|
|
fresh: '最新',
|
|
stale: '延迟',
|
|
secureRequired: '需要 HTTPS',
|
|
updated: '更新',
|
|
},
|
|
metrics: {
|
|
agents: '代理',
|
|
rooms: '房间',
|
|
ciWatchers: 'CI 监控',
|
|
},
|
|
panels: {
|
|
health: '健康',
|
|
heartbeat: '心跳',
|
|
healthSignals: '运行信号',
|
|
inbox: '收件',
|
|
inboxQueue: '待处理',
|
|
usage: '用量',
|
|
usageWindow: '剩余 / 速度',
|
|
rooms: '房间',
|
|
queue: '队列',
|
|
scheduled: '计划',
|
|
promptPreviews: '提示预览',
|
|
},
|
|
service: {
|
|
empty: '暂无心跳。检查服务日志。',
|
|
heartbeat: '心跳',
|
|
service: '服务',
|
|
rooms: '房间',
|
|
updated: '更新',
|
|
},
|
|
health: {
|
|
system: '系统',
|
|
signals: '健康信号',
|
|
services: '服务',
|
|
fresh: '正常',
|
|
stale: '延迟',
|
|
queue: '队列',
|
|
ciFailures: 'CI 失败',
|
|
affectedServices: '异常服务',
|
|
restart: '重启',
|
|
restartStack: '重启 stack',
|
|
restarting: '重启中...',
|
|
restartHint: '重启全部服务',
|
|
confirmRestart: '现在重启 stack?',
|
|
restartLog: '重启记录',
|
|
restartTarget: '目标',
|
|
restartStatus: '状态',
|
|
restartRequested: '请求',
|
|
restartServices: '服务',
|
|
levels: {
|
|
ok: '正常',
|
|
stale: '关注',
|
|
down: '中断',
|
|
},
|
|
},
|
|
inbox: {
|
|
empty: '暂无收件。',
|
|
cardsAria: '收件项',
|
|
summary: '收件摘要',
|
|
total: '全部',
|
|
filters: '收件筛选',
|
|
all: '全部',
|
|
noSummary: '无摘要',
|
|
occurred: '发生',
|
|
source: '来源',
|
|
target: '目标',
|
|
openTask: '查看计划',
|
|
openRoom: '查看房间',
|
|
kinds: {
|
|
'pending-room': '待处理房间',
|
|
'reviewer-request': '评审请求',
|
|
approval: '审批',
|
|
'arbiter-request': '仲裁请求',
|
|
'ci-failure': 'CI 失败',
|
|
mention: '提及',
|
|
},
|
|
severity: {
|
|
info: '信息',
|
|
warn: '关注',
|
|
error: '风险',
|
|
},
|
|
actions: {
|
|
run: '运行',
|
|
busy: '运行中...',
|
|
runReview: '运行评审',
|
|
finalize: '完成',
|
|
runArbiter: '运行仲裁',
|
|
decline: '拒绝',
|
|
dismiss: '忽略',
|
|
confirmDecline: '确认拒绝此项?',
|
|
},
|
|
},
|
|
rooms: roomMessages.zh,
|
|
usage: {
|
|
empty: '暂无用量快照。检查采集器。',
|
|
current: '使用中',
|
|
tightest: '剩余最少',
|
|
watch: '关注',
|
|
remaining: '剩余',
|
|
speed: '速度',
|
|
inUse: '使用中',
|
|
reset: '重置',
|
|
noReset: '无重置',
|
|
limitBasis: {
|
|
h5: '按5小时',
|
|
d7: '按7天',
|
|
},
|
|
quota: {
|
|
h5: '5小时',
|
|
d7: '7天',
|
|
},
|
|
usage: '用量',
|
|
groupPrimary: 'Claude / Kimi',
|
|
groupCodex: 'Codex',
|
|
risk: {
|
|
ok: '充足',
|
|
warn: '关注',
|
|
critical: '接近上限',
|
|
},
|
|
speedLabel: {
|
|
ok: '正常',
|
|
warn: '较快',
|
|
critical: '过快',
|
|
},
|
|
},
|
|
tasks: {
|
|
empty: '暂无计划任务。',
|
|
cardsAria: '计划任务卡片',
|
|
groups: {
|
|
watchers: 'CI 监控',
|
|
scheduled: '计划',
|
|
paused: '暂停',
|
|
completed: '完成',
|
|
},
|
|
count: '项',
|
|
groupEmpty: '无',
|
|
task: '任务',
|
|
status: '状态',
|
|
schedule: '计划',
|
|
next: '下次',
|
|
last: '最近',
|
|
context: '上下文',
|
|
ciWatch: 'CI 监控',
|
|
emptyPrompt: '(空预览)',
|
|
prompt: '提示',
|
|
until: '直到',
|
|
suspendedUntil: '恢复',
|
|
lastResult: '最近结果',
|
|
result: '无结果',
|
|
resultOk: '正常',
|
|
resultFail: '失败',
|
|
noResult: '无结果',
|
|
noTime: '-',
|
|
now: '现在',
|
|
createTitle: 'Create task',
|
|
createSubtitle: 'Schedule work from web',
|
|
room: 'Room',
|
|
selectRoom: 'Select room',
|
|
scheduleType: 'Type',
|
|
scheduleValue: 'Value',
|
|
scheduleValueHint: 'ISO time, ms, or cron',
|
|
promptPlaceholder: 'What should the agent do?',
|
|
editPromptPlaceholder: 'Leave blank to keep prompt',
|
|
scheduleTypes: {
|
|
once: 'Once',
|
|
interval: 'Interval',
|
|
cron: 'Cron',
|
|
},
|
|
contextModes: {
|
|
isolated: 'Isolated',
|
|
group: 'Group',
|
|
},
|
|
actions: {
|
|
create: 'Create',
|
|
edit: 'Edit',
|
|
save: 'Save',
|
|
pause: 'Pause',
|
|
resume: 'Resume',
|
|
cancel: 'Cancel',
|
|
busy: 'Working',
|
|
confirmCancel: 'Cancel this scheduled work?',
|
|
},
|
|
},
|
|
status: {
|
|
processing: '处理中',
|
|
waiting: '等待',
|
|
inactive: '空闲',
|
|
active: '活跃',
|
|
paused: '暂停',
|
|
completed: '完成',
|
|
},
|
|
units: {
|
|
second: '秒',
|
|
minute: '分',
|
|
hour: '小时',
|
|
task: '任务',
|
|
messageShort: '消息',
|
|
chars: '字',
|
|
},
|
|
},
|
|
ja: {
|
|
app: {
|
|
loading: 'ダッシュボードを読み込み中',
|
|
},
|
|
actions: {
|
|
close: '閉じる',
|
|
refresh: '更新',
|
|
refreshing: '更新中',
|
|
retry: '再試行',
|
|
},
|
|
nav: {
|
|
aria: 'ダッシュボードセクション',
|
|
drawerAria: 'ダッシュボードメニュー',
|
|
drawerNavAria: 'ダッシュボードメニューセクション',
|
|
menuOpen: 'メニューを開く',
|
|
menuClose: 'メニューを閉じる',
|
|
operations: '運用',
|
|
updated: '更新',
|
|
health: '状態',
|
|
inbox: '受信',
|
|
usage: '使用量',
|
|
rooms: 'ルーム',
|
|
scheduled: '予定',
|
|
settings: '設定',
|
|
},
|
|
language: {
|
|
label: '言語',
|
|
},
|
|
settings: {
|
|
title: '設定',
|
|
nicknameLabel: 'ニックネーム',
|
|
nicknamePlaceholder: 'Web Dashboard',
|
|
nicknameHelp: 'このダッシュボードからメッセージを送る時に表示される名前',
|
|
languageLabel: '言語',
|
|
},
|
|
error: {
|
|
api: '問題が発生しました',
|
|
network: 'ネットワーク接続を確認してから再試行してください。',
|
|
timeout:
|
|
'リクエストがタイムアウトしました。少し経ってから再試行してください。',
|
|
server:
|
|
'サーバーに一時的な問題があります。少し経ってから再試行してください。',
|
|
notFound: 'お探しの情報が見つかりませんでした。',
|
|
auth: '権限がありません。再ログインしてください。',
|
|
unknown: '不明なエラーが発生しました。',
|
|
},
|
|
control: {
|
|
aria: 'コントロールプレーン概要',
|
|
queue: '作業キュー',
|
|
activeRooms: '処理中 + 待機ルーム',
|
|
pendingRooms: 'メッセージ待ちルーム',
|
|
},
|
|
pwa: {
|
|
app: 'PWA',
|
|
install: 'インストール',
|
|
installed: 'インストール済み',
|
|
ready: 'オフライン可',
|
|
cached: 'キャッシュ済み',
|
|
online: 'オンライン',
|
|
offline: 'オフライン',
|
|
fresh: '最新',
|
|
stale: '遅延',
|
|
secureRequired: 'HTTPS 必須',
|
|
updated: '更新',
|
|
},
|
|
metrics: {
|
|
agents: 'エージェント',
|
|
rooms: 'ルーム',
|
|
ciWatchers: 'CI監視',
|
|
},
|
|
panels: {
|
|
health: '状態',
|
|
heartbeat: 'ハートビート',
|
|
healthSignals: '運用シグナル',
|
|
inbox: '受信',
|
|
inboxQueue: '対応待ち',
|
|
usage: '使用量',
|
|
usageWindow: '残量 / 速度',
|
|
rooms: 'ルーム',
|
|
queue: 'キュー',
|
|
scheduled: '予定',
|
|
promptPreviews: 'プロンプトプレビュー',
|
|
},
|
|
service: {
|
|
empty: 'ハートビートなし。サービスログを確認。',
|
|
heartbeat: 'ハートビート',
|
|
service: 'サービス',
|
|
rooms: 'ルーム',
|
|
updated: '更新',
|
|
},
|
|
health: {
|
|
system: 'システム',
|
|
signals: '状態シグナル',
|
|
services: 'サービス',
|
|
fresh: '正常',
|
|
stale: '遅延',
|
|
queue: 'キュー',
|
|
ciFailures: 'CI失敗',
|
|
affectedServices: '異常サービス',
|
|
restart: '再起動',
|
|
restartStack: 'Stack再起動',
|
|
restarting: '再起動中...',
|
|
restartHint: '全サービス再起動',
|
|
confirmRestart: 'Stackを再起動しますか?',
|
|
restartLog: '再起動ログ',
|
|
restartTarget: '対象',
|
|
restartStatus: '状態',
|
|
restartRequested: '要求',
|
|
restartServices: 'サービス',
|
|
levels: {
|
|
ok: '正常',
|
|
stale: '注意',
|
|
down: '停止',
|
|
},
|
|
},
|
|
inbox: {
|
|
empty: '受信なし。',
|
|
cardsAria: '受信項目',
|
|
summary: '受信サマリー',
|
|
total: '全体',
|
|
filters: '受信フィルター',
|
|
all: '全体',
|
|
noSummary: '概要なし',
|
|
occurred: '発生',
|
|
source: 'ソース',
|
|
target: '対象',
|
|
openTask: '予定を見る',
|
|
openRoom: 'ルームを見る',
|
|
kinds: {
|
|
'pending-room': '待機ルーム',
|
|
'reviewer-request': 'レビュー依頼',
|
|
approval: '承認',
|
|
'arbiter-request': '仲裁依頼',
|
|
'ci-failure': 'CI失敗',
|
|
mention: 'メンション',
|
|
},
|
|
severity: {
|
|
info: '情報',
|
|
warn: '注意',
|
|
error: '危険',
|
|
},
|
|
actions: {
|
|
run: '実行',
|
|
busy: '実行中...',
|
|
runReview: 'レビュー実行',
|
|
finalize: 'Finalize',
|
|
runArbiter: '仲裁実行',
|
|
decline: '拒否',
|
|
dismiss: '非表示',
|
|
confirmDecline: 'この項目を拒否しますか?',
|
|
},
|
|
},
|
|
rooms: roomMessages.ja,
|
|
usage: {
|
|
empty: '使用量スナップショットなし。収集器を確認。',
|
|
current: '使用中',
|
|
tightest: '残量最少',
|
|
watch: '注意',
|
|
remaining: '残量',
|
|
speed: '速度',
|
|
inUse: '使用中',
|
|
reset: 'リセット',
|
|
noReset: 'リセットなし',
|
|
limitBasis: {
|
|
h5: '5時間基準',
|
|
d7: '7日基準',
|
|
},
|
|
quota: {
|
|
h5: '5時間',
|
|
d7: '7日',
|
|
},
|
|
usage: '使用量',
|
|
groupPrimary: 'Claude / Kimi',
|
|
groupCodex: 'Codex',
|
|
risk: {
|
|
ok: '余裕',
|
|
warn: '注意',
|
|
critical: '上限注意',
|
|
},
|
|
speedLabel: {
|
|
ok: '通常',
|
|
warn: '速い',
|
|
critical: '速すぎ',
|
|
},
|
|
},
|
|
tasks: {
|
|
empty: '予定作業なし。',
|
|
cardsAria: '予定作業カード',
|
|
groups: {
|
|
watchers: 'CI監視',
|
|
scheduled: '予定',
|
|
paused: '一時停止',
|
|
completed: '完了',
|
|
},
|
|
count: '件',
|
|
groupEmpty: 'なし',
|
|
task: '作業',
|
|
status: '状態',
|
|
schedule: '予定',
|
|
next: '次回',
|
|
last: '直近',
|
|
context: 'コンテキスト',
|
|
ciWatch: 'CI監視',
|
|
emptyPrompt: '(空のプレビュー)',
|
|
prompt: 'プロンプト',
|
|
until: 'まで',
|
|
suspendedUntil: '再開',
|
|
lastResult: '直近結果',
|
|
result: '結果なし',
|
|
resultOk: '正常',
|
|
resultFail: '失敗',
|
|
noResult: '結果なし',
|
|
noTime: '-',
|
|
now: '今',
|
|
createTitle: 'Create task',
|
|
createSubtitle: 'Schedule work from web',
|
|
room: 'Room',
|
|
selectRoom: 'Select room',
|
|
scheduleType: 'Type',
|
|
scheduleValue: 'Value',
|
|
scheduleValueHint: 'ISO time, ms, or cron',
|
|
promptPlaceholder: 'What should the agent do?',
|
|
editPromptPlaceholder: 'Leave blank to keep prompt',
|
|
scheduleTypes: {
|
|
once: 'Once',
|
|
interval: 'Interval',
|
|
cron: 'Cron',
|
|
},
|
|
contextModes: {
|
|
isolated: 'Isolated',
|
|
group: 'Group',
|
|
},
|
|
actions: {
|
|
create: 'Create',
|
|
edit: 'Edit',
|
|
save: 'Save',
|
|
pause: 'Pause',
|
|
resume: 'Resume',
|
|
cancel: 'Cancel',
|
|
busy: 'Working',
|
|
confirmCancel: 'Cancel this scheduled work?',
|
|
},
|
|
},
|
|
status: {
|
|
processing: '処理中',
|
|
waiting: '待機',
|
|
inactive: '休止',
|
|
active: '有効',
|
|
paused: '一時停止',
|
|
completed: '完了',
|
|
},
|
|
units: {
|
|
second: '秒',
|
|
minute: '分',
|
|
hour: '時間',
|
|
task: '作業',
|
|
messageShort: 'メッセージ',
|
|
chars: '字',
|
|
},
|
|
},
|
|
} satisfies Record<Locale, Messages>;
|
|
|
|
export function isLocale(value: string | null | undefined): value is Locale {
|
|
return LOCALES.includes(value as Locale);
|
|
}
|
|
|
|
export function matchLocale(value: string | null | undefined): Locale | null {
|
|
if (!value) return null;
|
|
const normalized = value.toLowerCase();
|
|
if (normalized.startsWith('ko')) return 'ko';
|
|
if (normalized.startsWith('en')) return 'en';
|
|
if (normalized.startsWith('zh')) return 'zh';
|
|
if (normalized.startsWith('ja')) return 'ja';
|
|
return null;
|
|
}
|