""" 경량 i18n. `tr('key')` → 현재 언어의 번역 문자열. 키 미존재 시 ko 폴백, ko도 없으면 키 그대로 반환 (미번역도 동작). 점진 도입 가능. 새 언어 추가: 1. _DICT['en'] 옆에 'ja'/'zh' 등 추가 2. 사용자가 설정 → 언어 콤보에서 선택 """ from __future__ import annotations _current_lang = 'ko' _DICT = { 'ko': { # === 메뉴/버튼 === 'menu.stats': '통계', 'menu.calendar': '캘린더', 'menu.daily_report': '일일보고', 'menu.help': '도움말', 'menu.settings': '설정', 'btn.clock_out': '퇴근하기', 'btn.clock_out_cancel': '퇴근 취소', 'btn.lunch_add': '점심시간 추가', 'btn.lunch_applied': '점심시간 (적용됨)', 'btn.dinner_add': '저녁시간 추가', 'btn.dinner_applied': '저녁시간 (적용됨)', 'btn.break_out': '외출 시작', 'btn.break_in': '복귀', 'btn.save': '저장', 'btn.close': '닫기', 'btn.apply': '적용', 'btn.cancel': '취소', 'btn.add': '추가', 'btn.delete': '삭제', 'btn.edit': '편집', 'btn.confirm': '확인', 'btn.ok': '확인', # === 윈도우/다이얼로그 제목 === 'window.main_title': '퇴근시간 계산기', 'window.settings': '설정', 'window.help': '사용 설명서', 'window.stats': '근무 통계', 'window.calendar': '캘린더', 'window.mini_widget': '퇴근시간', 'window.clock_in_dialog': '출근 시간', 'window.break_view': '외출 관리', 'window.overtime_view': '연장근무 관리', 'window.leave_view': '연차 관리', # === 라벨 === 'label.remaining': '남은 시간', 'label.overtime_progress': '추가 근무 중', 'label.expected_clock_out': '예상 퇴근', 'label.clock_in_time': '출근', 'label.current_time': '현재', 'label.clock_out_time': '퇴근 시간', 'label.work_hours_label': '하루 기본 근무:', 'label.lunch_default': '점심시간 기본:', 'label.dinner_default': '저녁시간 기본:', 'label.work_pattern': '근무 패턴:', 'label.time_format': '시간 형식:', 'label.theme': '테마:', 'label.language': '언어 / Language:', 'label.unit_hour': '시간', 'label.unit_minute': '분', 'label.unit_day': '일', 'label.unit_count': '개', 'label.weekday_mon': '월', 'label.weekday_tue': '화', 'label.weekday_wed': '수', 'label.weekday_thu': '목', 'label.weekday_fri': '금', 'label.weekday_sat': '토', 'label.weekday_sun': '일', 'label.am': '오전', 'label.pm': '오후', 'label.recurring_yearly': ' (매년)', # === 알림 === 'notif.clock_out_soon.title': '⏰ 퇴근 시간 임박', 'notif.clock_out_soon.body': '퇴근까지 {minutes}분 남았습니다.\n마무리 준비를 시작하세요!', 'notif.lunch_reminder.title': '🍱 점심시간 등록', 'notif.lunch_reminder.body': '점심시간을 등록하지 않으셨네요.\n점심시간을 추가하시겠어요?', 'notif.dinner_reminder.title': '🍽️ 저녁시간 등록', 'notif.dinner_reminder.body': '저녁시간을 등록하지 않으셨네요.\n저녁시간을 추가하시겠어요?', # === 온보딩 근무 패턴 프리셋 === 'onboarding.preset.standard_8h': '표준 8시간 (점심 60분)', 'onboarding.preset.short_7h30m': '단축근무 7시간 30분 (점심 30분)', 'onboarding.preset.short_7h': '단축근무 7시간 (점심 60분)', 'onboarding.preset.short_6h': '단축근무 6시간 (점심 30분)', 'onboarding.preset.half_4h': '반일 4시간 (점심 0분)', 'onboarding.preset.custom_box': '사용자 정의', 'onboarding.preset.custom_radio': '직접 입력:', 'onboarding.preset.suffix_hours': ' 시간', 'onboarding.preset.suffix_minutes': ' 분', 'onboarding.preset.lunch_prefix': '점심 ', 'onboarding.preset.dinner_prefix': '저녁 ', 'onboarding.preset.dinner_tooltip': '야근으로 저녁 식사가 자주 발생하면 입력 (보통 0~60분)', 'notif.health_break.title': '🌿 휴식 권고', 'notif.health_break.body': '{hours}시간 이상 자리에 계셨습니다.\n잠시 일어나서 스트레칭하세요.', 'notif.overtime_earning.title': '🔥 연장근무 적립 예정', 'notif.overtime_earning.body': '오늘 {time_str}의 연장근무가 적립될 예정입니다!', 'notif.overtime_threshold.title': '💰 연장근무 적립 알림', 'notif.overtime_threshold.body': '적립된 연장근무가 {hours:.1f}시간 입니다.\n사용을 고려해보세요!', 'notif.health.title': '⚠️ 건강 경고', 'notif.health.body': '{days}일 연속 연장근무 중입니다.\n건강을 챙기세요!', 'notif.weekly_52.title': '🚨 주 52시간 초과', 'notif.weekly_52.body': '이번 주 총 근무시간이 {hours:.1f}시간입니다.\n법정 근로시간을 초과했습니다!', 'notif.weekly_report.title': '📊 지난주 요약', 'notif.weekly_report.body': '기간: {start} ~ {end}\n총 근무: {total_h:.1f}시간 ({days}일)\n일 평균: {avg_h:.1f}시간\n연장근무: {ot_h}시간 {ot_m}분\n가장 긴 날: {longest}', 'field.total_work': '총 근무', 'field.avg_daily': '일 평균', 'field.overtime': '연장근무', 'field.longest_day': '가장 긴 날', 'notif.achievement.title': '{icon} 도전과제 달성!', 'notif.achievement.body': '{name}\n{description}', 'discord.achievement.title': '🏆 도전과제 {count}개 달성!', 'discord.achievement.body': '새로 잠금 해제된 도전과제 입니다.{extra}', # === 메시지박스 === 'msg.save_success.title': '저장 완료', 'msg.save_success.body': '설정이 저장되었습니다.', 'msg.input_error.title': '입력 오류', 'msg.work_min_too_small': '하루 기본 근무 시간은 최소 30분 이상이어야 합니다.', 'msg.no_clock_in.title': '외출 불가', 'msg.no_clock_in.body': '출근하지 않은 상태입니다.', 'msg.already_break.body': '이미 외출 중입니다.', 'msg.no_record.title': '기록 없음', 'msg.no_record.body': '오늘 출근 기록이 없습니다.', 'msg.confirm_delete.title': '삭제 확인', 'msg.no_data.title': '데이터 없음', 'msg.manual_added': '수동 추가', # === 트레이 === 'tray.open': '프로그램 열기', 'tray.mini_widget': '미니 위젯', 'tray.toggle_lunch': '점심시간 토글', 'tray.quit': '종료', 'tray.tooltip_remaining': '퇴근까지: {time}', 'tray.tooltip_overtime': '추가 근무 중: {time}', 'tray.background': '프로그램이 트레이에서 실행 중입니다.', # === 그룹 박스 === 'group.work_time': '근무 시간 설정', 'group.notification': '알림 및 표시 설정', 'group.overtime': '연장근무 설정', 'group.leave': '휴가 설정', 'group.holiday': '공휴일 설정', 'group.data': '데이터 관리', # === StatsView === 'stats.title': '근무 통계', 'stats.tab_weekly': '주간', 'stats.tab_monthly': '월간', 'stats.tab_pattern': '패턴 분석', 'stats.weekly_summary': '이번 주 요약', 'stats.monthly_summary': '이번 달 요약', 'stats.total_hours': '총 근무시간:', 'stats.work_days': '근무일수:', 'stats.avg_hours': '평균 근무시간:', 'stats.total_overtime': '총 연장근무:', 'stats.pattern_insights': '근무 패턴 인사이트', 'stats.analyzing': '데이터를 분석 중입니다...', 'stats.no_data': '아직 충분한 데이터가 없습니다.', 'stats.total_work_hours': '총 근무 시간', 'stats.card_work_days': '근무 일수', 'stats.card_avg_hours': '일평균', 'stats.card_overtime': '연장근무', 'stats.this_week': '이번 주', 'stats.this_month': '이번 달', 'stats.daily_work_hours': '일별 근무 시간', 'stats.weekday_avg': '요일별 평균', 'stats.clock_in_distribution': '출근 시각 분포', 'stats.no_pattern_data': '패턴을 분석할 데이터가 부족합니다.', 'stats.value_hours': '{hours}시간', 'stats.value_hours_minutes': '{hours}시간 {minutes}분', 'stats.value_days': '{days}일', 'stats.avg_clock_in': '📌 평균 출근시간: {time}', 'stats.overtime_frequency': '📌 연장근무 빈도: {rate}% ({days}/{total}일)', 'stats.longest_work': '📌 최장 근무: {date} ({hours}시간)', 'stats.consecutive_ot_warning': '⚠️ 최근 {days}일 연속 연장근무 발생!', 'stats.weekly_52_exceeded': '🚨 주 52시간 초과: {hours}시간', 'stats.salary_estimate': '💰 이번 달 추정 급여: {total} (기본 {base} + 연장 {overtime})', # === ChartWidget === 'chart.need_matplotlib': '차트 표시에는 matplotlib가 필요합니다.\npip install matplotlib', 'chart.no_records': '기록 없음', 'chart.label_normal': '정상', 'chart.label_overtime': '연장', 'chart.ylabel_hours': '시간', 'chart.ylabel_days': '일수', 'chart.ylabel_avg_hours': '평균 시간', 'chart.hover_text': '▼ {date}\n근무 {hours}h', 'chart.hover_overtime': '연장 +{hours}h', 'chart.avg_line': '평균 {time}', # === ChartWidget === 'chart.need_matplotlib': 'matplotlib is required to display charts.\npip install matplotlib', 'chart.no_records': 'No records', 'chart.label_normal': 'Normal', 'chart.label_overtime': 'Overtime', 'chart.ylabel_hours': 'Hours', 'chart.ylabel_days': 'Days', 'chart.ylabel_avg_hours': 'Avg hours', 'chart.hover_text': '▼ {date}\nWork {hours}h', 'chart.hover_overtime': 'OT +{hours}h', 'chart.avg_line': 'Avg {time}', # === CalendarView === 'cal.title': '월간 근무 캘린더', 'cal.year_label': '년', 'cal.month_label': '월', 'cal.prev': '◀ 이전', 'cal.next': '다음 ▶', 'cal.today': '오늘', 'cal.no_record': '기록 없음', 'cal.edit_record': '기록 편집', # === HelpView (각 탭의 큰 HTML은 별도 키) === 'help.tab_intro': '시작하기', 'help.tab_work_hours': '근무시간', 'help.tab_overtime': '연장근무', 'help.tab_leave': '연차/휴가', 'help.tab_break': '외출/저녁', 'help.tab_faq': '자주 묻는 질문', # === clock_in_dialog === 'dlg.clock_in.prompt': '오늘의 출근시간을 입력해주세요', 'dlg.clock_in.label': '출근시간:', 'dlg.clock_in.quick': '빠른 선택:', 'dlg.clock_in.btn_now': '현재', # === break_view === 'dlg.break.edit_title': '외출 기록 수정', 'dlg.break.out_label': '외출 시간:', 'dlg.break.in_label': '복귀 시간:', 'dlg.break.reason_label': '사유:', 'view.break.today_title': '오늘의 외출 기록', 'view.break.col_out': '외출 시간', 'view.break.col_in': '복귀 시간', 'view.break.col_duration': '소요 시간', 'view.break.col_reason': '사유', 'view.break.in_progress': '진행중', 'view.break.total_zero': '총 외출 시간: 0분', 'view.break.total_fmt': '총 외출 시간: {h}시간 {m}분', 'view.break.total_min_only': '총 외출 시간: {m}분', 'view.break.duration_fmt': '{h}시간 {m}분', 'view.break.duration_min_only': '{m}분', 'view.break.delete_confirm': '이 외출 기록을 삭제하시겠습니까?', 'btn.refresh': '새로고침', 'btn.edit_short': '수정', 'btn.delete_short': '삭제', # === overtime_view === 'view.overtime.title': '연장근무 내역', 'view.overtime.balance_zero': '잔액: 0분', 'view.overtime.balance_fmt': '현재 잔액: {h}시간 {m}분 ({total}분)', 'view.overtime.earned_group': '적립 내역', 'view.overtime.used_group': '사용 내역', 'view.overtime.col_date': '날짜', 'view.overtime.col_earned': '적립', 'view.overtime.col_used': '사용', 'view.overtime.col_memo': '메모', 'view.overtime.col_reason': '사유', 'view.overtime.btn_add_earned': '수동 적립', 'view.overtime.btn_add_used': '수동 사용', 'view.overtime.menu_delete': '삭제', 'view.overtime.delete_confirm_body': '다음 사용 기록을 삭제하시겠습니까?\n\n날짜: {date}\n시간: {time}\n사유: {reason}', 'view.overtime.delete_earned_confirm_body': '다음 적립 기록을 삭제하시겠습니까?\n\n날짜: {date}\n적립: {time}\n\n삭제 시 잔액에서 차감됩니다.', 'view.overtime.manual_earned_title': '추가근무 수동 적립', 'view.overtime.manual_used_title': '추가근무 수동 사용', 'view.overtime.field_date': '날짜:', 'view.overtime.field_time': '시간:', 'view.overtime.field_memo': '메모:', 'view.overtime.field_reason': '사유:', 'view.overtime.unit_hour_suffix': '시간', 'view.overtime.minute_0': '0분', 'view.overtime.minute_30': '30분', 'view.overtime.placeholder_memo': '선택사항', 'view.overtime.placeholder_reason': '예: 개인 사유', 'view.overtime.zero_add_error': '0분은 추가할 수 없습니다.', 'view.overtime.zero_use_error': '0분은 사용할 수 없습니다.', 'view.overtime.balance_short_title': '잔액 부족', 'view.overtime.balance_short_body': '사용 가능한 시간이 부족합니다.\n\n요청: {req_h}시간 {req_m}분\n잔액: {bal_h}시간 {bal_m}분', 'view.overtime.saved_earned': '{h}시간 {m}분이 적립되었습니다.', 'view.overtime.saved_used': '{h}시간 {m}분이 사용 처리되었습니다.', # === leave_view === 'view.leave.title': '연차 관리', 'view.leave.balance_zero': '잔여: 0일', 'view.leave.balance_fmt': '잔여: {days}일 (총 {hours}시간)', 'view.leave.btn_set_balance': '잔여 설정', 'view.leave.used_group': '사용 내역', 'view.leave.col_date': '날짜', 'view.leave.col_type': '구분', 'view.leave.col_used': '사용', 'view.leave.col_reason': '사유', 'view.leave.btn_add': '연차 사용 추가', 'view.leave.btn_calendar': '캘린더 보기', 'view.leave.delete_confirm_body': '다음 연차 사용 기록을 삭제하시겠습니까?\n\n날짜: {date}\n구분: {type}\n사용: {days}', 'view.leave.set_title': '연차 시간 설정', 'view.leave.set_prompt': '연차 잔여 시간을 입력하세요 (0.5시간 단위):\n예) 8시간 = 1일, 4시간 = 0.5일(반차), 2시간 = 0.25일, 0.5시간 = 30분', 'view.leave.set_done_title': '설정 완료', 'view.leave.set_done_body': '연차 잔여 개수가 {days}일 ({hours}시간)로 설정되었습니다.', 'view.leave.add_title': '연차 사용 기록 추가', 'view.leave.field_date': '날짜:', 'view.leave.field_type': '구분:', 'view.leave.field_hours': '시간:', 'view.leave.field_reason': '사유:', 'view.leave.type_annual': '연차', 'view.leave.type_half': '반차', 'view.leave.type_quarter': '반반차', 'view.leave.type_hourly': '시간', 'view.leave.placeholder_reason': '예) 개인 사유, 병원 방문 등', 'view.leave.note_auto_deduct': '※ 잔여 연차가 자동 차감됩니다.', 'view.leave.short_title': '잔여 연차 부족', 'view.leave.short_body': '잔여 연차가 부족합니다.\n현재 잔여: {balance}일\n사용 요청: {req}일', 'view.leave.confirm_title': '연차 사용 기록 추가', 'view.leave.confirm_body': '날짜: {date}\n구분: {type}\n사용: {days}일 ({hours}시간)\n사유: {reason}\n\n이 기록을 추가하시겠습니까?', 'view.leave.added_title': '추가 완료', 'view.leave.added_body': '{days}일 ({hours}시간)의 연차 사용이 기록되었습니다.', 'view.leave.error_title': '오류', 'view.leave.error_body': '연차 기록 추가 중 오류가 발생했습니다:\n{err}', # === 메인 윈도우 추가 === 'app.title': '퇴근시간 계산기', 'group.today_work': '오늘의 근무', 'group.remaining_time': '남은 시간', 'group.overtime_leave': '연장근무 및 연차 현황', 'tooltip.meal_click': '좌클릭: 토글 / 우클릭: 실제 시간 입력', 'tooltip.clock_in_edit': '클릭하여 출근 시간 수정', 'btn.achievements': '도전과제', 'btn.break_manage': '외출 관리', 'section.overtime_earned': '연장근무 적립', 'section.leave': '연차', 'section.total_time': '총 보유 시간', 'btn.use_30min': '30분', 'btn.use_1hour': '1시간', 'btn.use_2hour': '2시간', 'btn.custom_input': '직접입력', 'btn.detail': '상세', 'btn.half_leave': '반차', 'btn.full_leave': '연차', 'msg.auto_clock_in.title': '자동 출근 감지', 'msg.auto_clock_in.body': '출근 시간이 자동으로 감지되었습니다.\n출근: {time}\n\n잘못된 경우 수정할 수 있습니다.', 'msg.manual_clock_in.title': '출근 시간 입력', 'msg.manual_clock_in.body': '출근 시간을 자동으로 감지하지 못했습니다.\n\n수동으로 입력하시겠습니까?\n(관리자 권한으로 실행하면 자동 감지됩니다)', 'msg.full_day_leave.title': '종일 연차 등록됨', 'msg.full_day_leave.body': '오늘은 종일 연차로 등록되어 있습니다.\n그래도 출근하시겠어요?\n\n(출근 시 모든 시간이 연장근무로 적립됩니다.)', 'label.full_day_leave_override': '연차 override (전체 적립)', 'label.weekend_work': '주말 근무 (전체 적립)', 'label.holiday_work': '공휴일 근무 (전체 적립)', 'label.holiday_work_no_clock_out': '휴일 근무 (정해진 퇴근시각 없음)', 'label.holiday_default': '공휴일', 'label.expected_clock_out_prefix': '예상 퇴근: ', 'label.total_work_hours': '총 근무시간: {hours:.1f}시간', 'label.weekend_work_tag': '[주말 근무]', 'label.holiday_work_tag': '[공휴일 근무 - {name}]', 'label.overtime_earned_msg': '연장근무 적립: {time} (🕐×{tokens})', 'label.full_earned_msg': '전체 적립: {time} (🕐×{tokens})', 'label.full_day_leave_today': '오늘은 휴가', 'label.full_day_leave_in_use': '연차 사용 중', 'label.full_day_leave_format': '{type} — {memo}', 'label.vacation': '🌴 휴가', 'label.time_hours_minutes': '{hours}시간 {minutes}분', 'time_format.12h': '{period} {hour}:{minute}', 'break.status_in_progress': '외출 중 ({time}부터)', 'break.status_total_hours_minutes': '오늘 총 외출: {hours}시간 {minutes}분', 'break.status_total_minutes': '오늘 총 외출: {minutes}분', 'break.reason.lock': '화면 잠금', 'break.cannot_no_clock_in.title': '외출 불가', 'break.cannot_no_clock_in.body': '출근하지 않은 상태입니다.', 'break.cannot_already_on_break.body': '이미 외출 중입니다.', 'break.cannot_no_record.body': '출근 기록을 찾을 수 없습니다.', 'break.started.title': '외출', 'break.started.body': '외출 시간: {time}', 'break.cannot_return_no_active.body': '진행 중인 외출 기록을 찾을 수 없습니다.', 'break.cannot_return_corrupt.body': '외출 시간 기록이 손상되었습니다.', 'break.cannot_return_unusable.body': '외출 시간 기록이 손상되어 복귀 처리를 할 수 없습니다.', 'break.return.title': '복귀', 'break.return.body': '복귀 시간: {time}\n외출 시간: {minutes}분', 'mini.open_main': '메인 창 열기', 'mini.close': '미니 위젯 닫기', 'msg.clock_out_confirm.title': '퇴근 확인', 'msg.clock_out_confirm.body': '퇴근 처리하시겠습니까?\n\n퇴근 시간: {time}', 'msg.auto_overtime_confirm.title': '연장근무 적립 확인', 'msg.auto_overtime_confirm.body': '연장근무 {actual} 발생, {earned} 적립 대상입니다.\n\n적립하시겠습니까?\n(아니오 선택 시 이번 퇴근분은 적립되지 않습니다)', 'msg.clock_out_done.title': '퇴근 완료', 'msg.clock_out_done.body': '퇴근 처리되었습니다!\n\n{type_info}{total_work}\n{overtime_info}', 'msg.cancel_clock_out_confirm.body': '퇴근을 취소하시겠습니까?\n\n퇴근 시간과 연장근무 적립 내역이 삭제됩니다.', 'msg.cancel_clock_out_done.title': '퇴근 취소 완료', 'msg.cancel_clock_out_done.body': '퇴근이 취소되었습니다.\n다시 근무 중 상태로 전환되었습니다.', 'msg.cancel_clock_out_fail.title': '취소 실패', 'msg.cancel_clock_out_fail.body': '퇴근 기록을 찾을 수 없습니다.', 'msg.error.title': '오류', 'msg.error.body': '{action} 중 오류가 발생했습니다:\n{error}', 'msg.input.title': '시간 입력', 'msg.input_error.date_format': '날짜 형식이 잘못되었습니다.\n올바른 형식: YYYY-MM-DD (예: 2024-01-15)', 'msg.input_error.overtime_unit': '30분 단위로만 사용 가능합니다.\n예) 0.5시간, 1시간, 1.5시간', 'msg.overtime_use.title': '연장근무 사용', 'msg.overtime_use_minus.title': '연장근무 사용 (마이너스 전환)', 'msg.overtime_use.body': '{minutes}분의 연장근무를 사용하시겠습니까?\n\n현재 잔액: {balance}분\n사용 후 잔액: {new_balance}분', 'msg.overtime_use_minus.body': '{minutes}분의 연장근무를 사용하시겠습니까?\n\n현재 잔액: {balance}분\n사용 후 잔액: {new_balance}분 (마이너스)\n\n⚠️ 잔액이 마이너스가 됩니다.\n나중에 초과근무로 갚아야 합니다.', 'msg.overtime_use_done.title': '사용 완료', 'msg.overtime_use_done.body': '{minutes}분이 사용되었습니다.', 'msg.overtime_use_fail.title': '사용 실패', 'msg.overtime_input.body': '사용할 시간을 입력하세요 (0.5시간 단위):\n예) 0.5, 1, 1.5, 2, 3, 4', 'msg.leave_use.title': '연차 사용', 'msg.leave_use_date.title': '연차 사용 날짜', 'msg.leave_use_date.body': '사용 날짜를 입력하세요 (YYYY-MM-DD):', 'msg.leave_use_reason.title': '연차 사유', 'msg.leave_use_reason.body': '사유를 입력하세요 (선택):', 'msg.leave_use_confirm.body': '{date}에 {type} {days}를 사용하시겠습니까?\n\n사용 후 잔액: {balance_after}일', 'msg.leave_use_done.title': '사용 완료', 'msg.leave_use_done.body': '{type}가 사용되었습니다.', 'msg.leave_use_impossible.title': '사용 불가', 'msg.leave_short.title': '잔액 부족', 'msg.leave_short.body': '사용 가능한 연차가 부족합니다.\n현재 잔액: {balance}일\n요청: {days}일', 'msg.leave_short_hours.body': '사용 가능한 연차가 부족합니다.\n현재 잔액: {balance}일 ({balance_hours}시간)\n요청: {days}일 ({hours}시간)', 'msg.settings_updated.title': '설정 업데이트', 'msg.settings_updated.body': '변경된 설정이 즉시 반영되었습니다.', 'msg.meal_need_clock_in.title': '출근 필요', 'msg.meal_need_clock_in.body': '출근 후에만 식사 시간을 기록할 수 있습니다.', 'msg.meal_recorded.title': '기록 완료', 'msg.meal_recorded.body': '{meal} {minutes}분 기록되었습니다.\n({start} ~ {end})', 'msg.meal_actual_input': '{meal} 실제 시간 입력...', 'msg.workday_boundary.title': '근무일 경계 경과', 'msg.workday_boundary.body': '근무일 경계 시간({hour}시)이 지나 자동으로 처리되었습니다.\n\n전날 근무: {before} 퇴근 처리\n금일 근무: {boundary} 출근 처리\n\n자정~{hour}시 전까지의 야근은 전날 초과근무로 인정됩니다.', 'msg.new_workday.title': '새 근무일', 'msg.new_workday.body': '새로운 근무일입니다. ({date})\n\n출근 처리를 하시겠습니까?', 'msg.clock_in_set.title': '출근 시간 설정', 'msg.clock_in_set.body': '출근 시간이 설정되었습니다.\n\n출근: {time}', 'leave.type.annual': '연차', 'leave.type.sick': '병가', 'leave.type.hourly_leave': '시간연차', 'leave.use.full_day': '1일', 'leave.use.half_day': '0.5일 (4시간)', 'leave.use.hour_1': '0.125일 (1시간)', 'leave.use.min_30': '0.0625일 (30분)', 'leave.use.custom': '{days}일 ({hours}시간)', 'leave.type.half_am': '오전 반차', 'leave.type.half_pm': '오후 반차', 'leave.type.time_off': '시간 연차', 'leave.type.half': '반차', 'leave.type.quarter': '반반차', 'report.leave_used': '🌴 연차 사용: {value}', 'report.leave_used_days_hours': '{days}일 {hours}시간', 'report.leave_used_days': '{days}일', 'report.leave_used_hours': '{hours}시간', 'report.leave_detail': ' - {type}: {time}{memo}', 'report.title': '📋 일일 근무 보고서 - {date}', 'report.clock_in': '🕐 출근 시간: {time}', 'report.clock_out': '🕐 퇴근 시간: {time}', 'report.not_clocked_out': '🕐 퇴근 시간: 미퇴근', 'report.total_work': '⏱️ 총 근무: {time}', 'report.break_time': '🚶 외출 시간: {time}', 'report.break_detail': ' - {start} ~ {end} ({duration}분){reason}', 'report.break_in_progress': ' - {start} ~ 복귀중{reason}', 'report.meal_actual': '{label}: {time} (실측)', 'report.meal_in_progress': ' - {start} ~ 진행중', 'report.meal_default': '{label}: 포함 ({time})', 'report.memo': '📝 메모: {memo}', 'report.copied.title': '보고서 복사 완료', 'report.copied.body': '일일 근무 보고서가 클립보드에 복사되었습니다.\n\n{report}', 'label.lunch': '🍱 점심시간', 'label.lunch_short': '점심', 'label.dinner': '🍽️ 저녁시간', 'label.dinner_short': '저녁', 'label.overtime_balance_zero': '0분 (×0)', 'label.leave_balance_zero': '잔여: 0일', 'label.today_estimate': '오늘 추정: {amount}', 'label.in_progress': '진행중', 'label.break_returning': '복귀중', 'label.meal_actual_suffix': '실측', 'label.meal_included': '포함', 'report.overtime_occurred': '⏰ 추가 근무 발생: {time}', 'report.overtime_banked': ' 💰 적립: {time} (30분 단위 절삭)', 'report.overtime_used': '🕐 추가 근무 사용: {time}', 'report.overtime_used_detail': ' - {time}{reason}', 'update.new_version_title': '새 버전 발견', 'update.apply_failed_title': '업데이트 실패', 'update.check_title': '업데이트 확인', 'update.up_to_date': '현재 최신 버전입니다 (v{version}).', 'update.network_error': '업데이트 서버에 연결할 수 없습니다.\n네트워크 상태를 확인해 주세요.', 'update.no_release': '업데이트 저장소에서 릴리스를 찾을 수 없습니다.\n(저장소 비공개 또는 첫 릴리스 전)', 'update.no_asset': '새 버전은 있지만 다운로드 가능한 main.exe 자산이 없습니다.\n관리자에게 문의하세요.', 'update.unknown': '알 수 없는 응답입니다.', 'update.new_found_dev': '새 버전 {version}이 있습니다.\n(개발 환경에서는 자동 적용 불가 — git pull 또는 빌드 후 사용)', 'update.new_found': '현재: v{current}\n새 버전: v{new}\n\n릴리스 노트:\n{notes}\n\n지금 다운로드 후 업데이트할까요?', 'update.downloading': '다운로드 중...', 'update.download_title': '업데이트 다운로드', 'update.download_failed': '새 버전 다운로드 중 오류가 발생했습니다.', 'update.updater_failed': 'updater.exe를 찾을 수 없거나 실행에 실패했습니다.', 'update.restart': '업데이트 적용을 위해 프로그램이 종료됩니다.', 'settings.title': '설정', 'settings.work_pattern': '근무 패턴:', 'settings.preset.standard_8h': '표준 8시간 (점심 60분)', 'settings.preset.short_7h30m': '단축근무 7시간 30분 (점심 30분)', 'settings.preset.short_7h': '단축근무 7시간 (점심 60분)', 'settings.preset.short_6h': '단축근무 6시간 (점심 30분)', 'settings.preset.half_4h': '반일 4시간 (점심 0분)', 'settings.preset.custom': '사용자 정의', 'settings.daily_work': '하루 기본 근무:', 'settings.lunch_default': '점심시간 기본:', 'settings.dinner_default': '저녁시간 기본:', 'settings.auto_apply': '자동 적용', 'settings.auto_apply_tooltip': '출근 후 4시간 경과 시 자동 적용', 'settings.suffix_hour': ' 시간', 'settings.suffix_minute': ' 분', 'settings.notif_clock_out': '퇴근 30분 전 알림', 'settings.notif_lunch': '점심시간 등록 알림', 'settings.notif_dinner': '저녁시간 등록 알림', 'settings.notif_overtime': '연장근무 적립 알림', 'settings.notif_health': '건강 경고 알림', 'settings.notif_break': '휴식 권고 알림', 'settings.notif_break_tooltip': '오랜 시간 자리에서 일하면 스트레칭을 권유 (연속 근무 N시간 기준)', 'settings.notif_before': '퇴근 알림 시점:', 'settings.notif_before_spin_suffix': '분 전', 'settings.notif_before_tooltip': '퇴근 임박 알림이 표시될 시점 (분 단위)', 'settings.advanced_thresholds': '고급 임계값', 'settings.advanced_thresholds_tooltip': '회사 정책·개인 선호에 맞춰 알림 발생 시점 조정', 'settings.lunch_alert_after': '점심 알림 (출근 +):', 'settings.lunch_alert_tooltip': '출근 후 N시간 경과 시 점심 미등록 알림', 'settings.dinner_alert_after': '저녁 알림 (출근 +):', 'settings.dinner_alert_tooltip': '출근 후 N시간 경과 시 저녁 미등록 알림', 'settings.overtime_alert_at': '연장 누적 알림:', 'settings.overtime_alert_tooltip': '연장근무 잔액이 N시간 이상이면 알림', 'settings.weekly_limit': '주간 한도 경고:', 'settings.weekly_limit_tooltip': '주간 총 근무가 N시간 초과 시 경고 (한국 노동법 기본 52)', 'settings.consecutive_ot': '연속 연장 경고:', 'settings.consecutive_ot_tooltip': 'N일 이상 연속 연장근무 시 건강 경고', 'settings.break_after': '휴식 권고 시점:', 'settings.break_after_tooltip': '연속 근무 N시간 경과 시 스트레칭 권유', 'settings.time_format': '시간 형식:', 'settings.time_format_12': '오전/오후 (오후 5:30)', 'settings.time_format_24': '24시간 (17:30)', 'settings.theme': '테마:', 'settings.theme_light': '라이트', 'settings.theme_dark': '다크', 'settings.font_scale': '글꼴 크기:', 'settings.high_contrast': '고대비 모드', 'settings.high_contrast_tooltip': '검정 배경 + 노란 텍스트 (시각약자/야간)', 'settings.language_restart_tooltip': '언어 변경은 재시작 후 완전히 적용됩니다.', 'settings.current_balance': '현재 잔액: 계산 중...', 'settings.calc_unit': '계산 단위:', 'settings.initial_overtime': '기존 연장근무:', 'settings.auto_bank': '자동 적립', 'settings.auto_bank_tooltip': '퇴근 시 연장근무 자동 적립', 'settings.initial_overtime_note': '※ 프로그램 사용 전 쌓인 연장근무 시간 (절대값)', 'settings.goal_group': '월간 목표 (0=비활성)', 'settings.monthly_ot_cap': '월 연장근무 상한:', 'settings.daily_avg_goal': '일 평균 근무 목표:', 'settings.goal_note': '※ 통계 → 월간 탭에서 진행률 확인', 'settings.annual_leave': '연간 연차:', 'settings.remaining_leave': '남은 연차: 계산 중...', 'settings.used_leave': '기존 사용:', 'settings.used_leave_note': '※ 프로그램 사용 전 이미 사용한 연차 (1일=8시간)', 'settings.registered': '등록:', 'settings.add_korean_holidays': '한국 공휴일 (자동)', 'settings.add_korean_holidays_tooltip': '음력 명절(설/추석) + 임시공휴일 포함 자동 등록', 'settings.holiday_note': '※ 공휴일 근무 시 모든 시간이 연장근무로 적립됩니다', 'settings.list': '목록', 'settings.korean_holidays_title': '한국 공휴일 자동 추가', 'settings.korean_holidays_years_label': '{start}년 + {end}년', 'settings.korean_holidays_years_label_single': '{year}년', 'settings.korean_holidays_years_label': '{start}년 + {end}년', 'settings.korean_holidays_years_label_single': '{year}년', 'settings.korean_holidays_body': '{years} 한국 공휴일을 자동으로 등록하시겠습니까?\n\n포함:\n• 양력 공휴일 (신정/삼일절/어린이날/근로자의 날 등)\n• 음력 명절 (설날 연휴/추석 연휴/석가탄신일)\n• 정부 지정 대체·임시공휴일\n\n※ 1차: 공공데이터포털 특일정보 API (정부 공인, 임시공휴일 포함)\n※ 2차 fallback: \'holidays\' 패키지 (오프라인)', 'settings.korean_holidays_added': '{year}년 한국 공휴일 {count}개가 추가되었습니다.', 'settings.korean_holidays_included': '포함:\n', 'settings.package_not_installed': '패키지 미설치', 'settings.package_fallback_body': '\'holidays\' 패키지가 설치되지 않아 고정 공휴일만 추가했습니다.\n\n{hint} pip install holidays', 'settings.package_install_hint': '음력/임시공휴일 자동 등록을 원하시면:\n', 'settings.add_done': '추가 완료', 'settings.holiday_added': '공휴일이 추가되었습니다.\n{date}: {name}', 'settings.holiday_add_title': '공휴일 추가', 'settings.holiday_date_prompt': '공휴일 날짜를 입력하세요 (YYYY-MM-DD):', 'settings.holiday_name_prompt': '공휴일 이름을 입력하세요:', 'settings.holiday_list_title': '공휴일 목록', 'settings.holiday_list_header': '=== {year}년 공휴일 목록 ===\n\n', 'settings.holiday_list_item': '• {date} ({weekday}): {name}{recurring}', 'settings.holiday_total': '총 {count}개', 'settings.holiday_delete_confirm': '\n\n공휴일을 삭제하시겠습니까?', 'settings.holiday_delete_title': '공휴일 삭제', 'settings.holiday_delete_prompt': '삭제할 공휴일을 선택하세요:', 'settings.delete_done': '삭제 완료', 'settings.holiday_deleted': '{item}이(가) 삭제되었습니다.', 'settings.export_csv': 'CSV 내보내기', 'settings.export_work': '근무기록', 'settings.export_overtime': '연장근무', 'settings.export_monthly': '월간 요약', 'settings.import_csv': 'CSV 가져오기', 'settings.import_tooltip': 'date,clock_in,clock_out,lunch_minutes,memo 헤더 포맷', 'settings.import_format': '우리 표준 포맷 (헤더: date,clock_in,clock_out,lunch_minutes,memo)', 'settings.db_path_label': 'DB 경로:', 'settings.change': '변경...', 'settings.db_path_tooltip': '클라우드 폴더(OneDrive/Dropbox 등) 경로로 변경 가능. 재시작 필요.', 'settings.auto_break_lock_tooltip': 'PC가 잠기면 외출 시작, 풀리면 복귀를 자동 처리합니다.', 'settings.gitea_feedback_label': 'Gitea 피드백:', 'settings.gitea_token_placeholder': 'PAT (issue 쓰기 권한, 옵션)', 'settings.clock_in_unlock_tooltip': 'PC를 끄지 않고 출근하는 경우 — 부팅 이벤트가 없어도 화면 잠금 해제 시점을 출근으로 기록합니다.', 'settings.auto_break_lock': '화면 잠금 시 자동 외출/복귀', 'settings.gitea_feedback_tooltip': "오류 발생 시 'Gitea에 보고' 버튼 활성화", 'settings.clock_in_unlock': '첫 잠금 해제 시각을 출근시간으로 사용', 'settings.version': '버전: v{version}', 'settings.check_update': '업데이트 확인 (F5)', 'settings.select_db': '데이터베이스 파일 선택', 'settings.db_path_saved': '새 경로가 저장되었습니다:\n{path}\n\n기존 데이터를 사용하려면 현재 database.db 파일을 새 위치로 복사하고\n프로그램을 재시작하세요.', 'settings.parse_failed': '파싱 실패', 'settings.empty_file': '빈 파일', 'settings.empty_file_body': '유효한 행이 없습니다.', 'settings.conflict_title': '충돌 처리', 'settings.conflict_body': '기존 일자와 충돌하면 어떻게 처리할까요?\n', 'settings.conflict_body_detailed': '기존 일자와 충돌하면 어떻게 처리할까요?\nYes = 덮어쓰기\nNo = 건너뛰기\nCancel = 취소', 'settings.import_failed': '가져오기 실패', 'settings.import_result': '가져오기 결과:\n• 추가: {added}건\n• 갱신: {updated}건\n• 건너뜀: {skipped}건', 'settings.save_done': '저장 완료', 'settings.save_done_body': '설정이 저장되었습니다.', 'settings.restart_title': '재시작 / Restart', 'settings.restart_body': '주요 화면은 즉시 적용됩니다. 일부 다이얼로그는 재시작 후 완전히 반영됩니다.\n지금 재시작할까요?\n\n', 'settings.initial_overtime_title': '기존 연장근무 설정', 'settings.initial_overtime_body': '현재 설정: {old_hours}시간 {old_mins}분\n변경할 값: {hours}시간 {mins}분\n\n기존 연장근무 시간을 변경하시겠습니까?', 'settings.initial_overtime_done': '설정 완료', 'settings.initial_overtime_done_body': '기존 연장근무가 {hours}시간 {mins}분으로 설정되었습니다.', 'settings.initial_overtime_error': '기존 연장근무 설정 중 오류가 발생했습니다:\n{error}', 'settings.current_overtime_balance': '현재 잔액: {hours}시간 {minutes}분 ({balance}분)', 'settings.remaining_leave_fmt': '남은 연차: {remaining:.1f}일 (총 {total}일 중 {used}일 사용)', 'settings.holiday_count': '{count}개 ({year}년)', 'settings.error': '오류', 'settings.export_no_records': '내보낼 기록이 없습니다.', 'settings.save_work_title': '근무 기록 저장', 'settings.export_done': '내보내기 완료', 'settings.work_exported': '근무 기록이 저장되었습니다.\n{path}', 'settings.save_ot_title': '연장근무 내역 저장', 'settings.ot_exported': '연장근무 내역이 저장되었습니다.\n{path}', 'settings.save_monthly_title': '월간 요약 저장', 'settings.monthly_exported': '월간 요약이 저장되었습니다.\n{path}', 'settings.export_failed': '내보내기 실패', 'settings.export_error': '오류: {error}', 'settings.initial_leave_title': '기존 사용 연차 설정', 'settings.initial_leave_body': '현재 설정: {old_hours}시간 {old_mins}분\n변경할 값: {hours}시간 {mins}분\n\n기존 사용 연차를 변경하시겠습니까?', 'settings.initial_leave_done': '설정 완료', 'settings.initial_leave_done_body': '기존 사용 연차가 {hours}시간 {mins}분으로 설정되었습니다.', 'date_format.full': '{year}년 {month}월 {day}일 ({weekday})', 'achieve.cat_ambition': '야망', 'achieve.cat_balance': '워라밸', 'achieve.cat_break_use': '외출', 'achieve.cat_health': '건강', 'achieve.cat_korea': '한국 문화', 'achieve.cat_leave': '연차', 'achieve.cat_meal': '식사', 'achieve.cat_meta': '메타', 'achieve.cat_milestone': '마일스톤', 'achieve.cat_ot_bank': '연장 적립', 'achieve.cat_ot_use': '연장 사용', 'achieve.cat_pattern': '패턴', 'achieve.cat_punctual': '시간 엄수', 'achieve.cat_season': '시즌', 'achieve.cat_secret': '시크릿', 'achieve.cat_settings': '설정', 'achieve.cat_special_day': '특별일', 'achieve.cat_stats': '통계', 'achieve.cat_streak': '출근 streak', 'achieve.cat_time_slot': '시간대', 'achieve.completion_rate': '달성률', 'achieve.earned_date': ' ✓ {date} 달성 ', 'achieve.empty': '(아직 없음)', 'achieve.secret_locked': '🔒 달성하면 공개됩니다', 'achieve.tab_all': '🌐 전체 · {count}', 'achieve.tab_completed': '✓ 완료 · {count}', 'achieve.tab_in_progress': '⚡ 진행 중 · {count}', 'achieve.tab_secret': '🌑 시크릿 · {earned}/{total}', 'achieve.tier_bronze': '브론즈', 'achieve.tier_gold': '골드', 'achieve.tier_legend': '레전드', 'achieve.tier_platinum': '플래티넘', 'achieve.tier_silver': '실버', 'achieve.title': '도전과제', 'cal.add_done_body': '{date} 기록이 추가되었습니다.', 'cal.add_done_title': '추가 완료', 'cal.add_error_body': '기록 추가 실패: {error}', 'cal.add_error_title': '오류', 'cal.btn_minus_30': '-30분', 'cal.btn_plus_30': '+30분', 'cal.check_dinner_1h': '저녁 (1시간)', 'cal.check_lunch_1h': '점심 (1시간)', 'cal.context_add': '{date} 기록 추가', 'cal.context_delete': '{date} 삭제', 'cal.context_edit': '{date} 편집', 'cal.delete_confirm_body': '{date} 기록을 정말 삭제하시겠습니까?\n(연장근무 적립 내역도 함께 삭제됩니다)', 'cal.delete_confirm_title': '삭제 확인', 'cal.delete_done_body': '{date} 기록 삭제됨', 'cal.delete_done_title': '삭제 완료', 'cal.delete_record': '기록 삭제', 'cal.delete_selected_body': '{date}의 출근 기록을 삭제하시겠습니까?\n\n※ 연관된 연장근무 적립/사용 기록도 함께 삭제됩니다.\n※ 이 작업은 되돌릴 수 없습니다.', 'cal.delete_selected_title': '출근 기록 삭제', 'cal.detail_clock_in': '출근: {time}', 'cal.detail_clock_out': '퇴근: {time}', 'cal.detail_clock_out_none': '퇴근: 미기록', 'cal.detail_date_fmt': '{year}년 {month}월 {day}일', 'cal.detail_dinner_unused': '저녁시간: 미사용', 'cal.detail_dinner_used': '저녁시간: 사용함', 'cal.detail_group_title': '선택된 날짜 정보', 'cal.detail_lunch_unused': '점심시간: 미사용', 'cal.detail_lunch_used': '점심시간: 사용함', 'cal.detail_memo': '메모: {memo}', 'cal.detail_overtime_earned': '🔥 연장근무 적립: {hours}시간 {minutes}분', 'cal.detail_total_hours': '총 근무시간: {hours:.1f}시간', 'cal.dialog_title': '월간 근무 기록', 'cal.edit_dialog_subtitle': '{date} 출퇴근 시간 수정', 'cal.edit_dialog_title': '출퇴근 시간 수정', 'cal.edit_done_body': '{date}의 출퇴근 시간이 수정되었습니다.\n\n출근: {clock_in}\n퇴근: {clock_out}\n점심시간: {lunch}\n저녁시간: {dinner}\n외출시간: {break_minutes}분\n총 근무시간: {total_hours:.1f}시간\n연장근무: {overtime_earned}분 적립', 'cal.edit_done_title': '수정 완료', 'cal.edit_error_body': '수정 중 오류가 발생했습니다:\n{error}', 'cal.edit_error_title': '오류', 'cal.edit_note': '※ 수정 시 연장근무 내역이 재계산됩니다.', 'cal.edit_time': '시간 수정', 'cal.label_clock_in': '출근:', 'cal.label_clock_out': '퇴근:', 'cal.legend_leave': '휴가', 'cal.legend_none': '없음', 'cal.legend_normal': '정상', 'cal.legend_overtime': '연장', 'cal.memo_group': '메모', 'cal.memo_placeholder': '추가근무 사유, 특이사항 등...', 'cal.no_record': '기록이 없습니다.', 'cal.save_memo': '메모 저장', 'cal.save_memo_body': '{date}의 메모가 저장되었습니다.', 'cal.save_memo_title': '메모 저장', 'cal.time_error_body': '퇴근 시간은 출근 시간보다 늦어야 합니다.', 'cal.time_error_title': '시간 오류', 'clock_in_dialog.cancelled': '취소됨', 'clock_in_dialog.selected': '선택된 시간: {time}', 'field.avg_daily_value': '{hours:.1f}시간', 'field.overtime_value': '{hours}시간 {minutes}분', 'field.total_work_value': '{hours:.1f}시간 ({days}일)', 'goal.avg_daily': '일평균:', 'goal.overtime': '연장근무:', 'goal.title': '이번 달 목표', 'help.onboarding_button': '온보딩 다시 보기', 'leave_cal.detail_label': '{type} {days}일', 'leave_cal.detail_memo': '{type} {days}일 ({memo})', 'leave_cal.detail_no_record': '{date} — 연차 사용 없음', 'leave_cal.header': '잔여 {balance:.2f}일 / 총 {total:.0f}일 (사용 {used:.2f}일)', 'leave_cal.legend_full': '종일(1.0)', 'leave_cal.legend_full_planned': '종일+예정', 'leave_cal.legend_half': '반차(0.5)', 'leave_cal.legend_planned': '예정', 'leave_cal.legend_quarter': '반반차(0.25)', 'leave_cal.title': '연차 캘린더', 'meal.dialog_title': '{meal} 시간 입력', 'meal.error_after_clock_out': '퇴근({time}) 이후입니다', 'meal.error_before_clock_in': '출근({time}) 이전입니다', 'meal.error_start_after_end': '시작이 종료보다 늦습니다', 'meal.error_too_long': '식사 시간이 8시간을 초과합니다', 'meal.info_clock_in_limit': '\n출근 {time} 이후만 입력 가능.', 'meal.info_text': '{meal} 시작·종료 시각을 입력하세요.\n자동 적용된 {minutes}분 대신 정확한 시간으로 기록됩니다.', 'meal.input_error_title': '입력 오류', 'meal.label_end': '종료:', 'meal.label_start': '시작:', 'meal.preview_total': '총 {minutes}분', 'mini.close': '미니 위젯 닫기', 'mini.open_main': '메인 창 열기', 'onboarding.detection_boot': 'PC 부팅 시간 (기본 — 매일 PC를 끄는 경우)', 'onboarding.detection_info': '\nPC를 항상 켜둔 채 출근하시는 분은 두 번째 옵션을 권장합니다.', 'onboarding.detection_manual': '수동 입력만 (자동 감지 안 함)', 'onboarding.detection_subtitle': '앱이 출근 시간을 자동으로 어떻게 감지할지 선택하세요.', 'onboarding.detection_title': '출근 시간 감지 방식', 'onboarding.detection_unlock': '화면 잠금 해제 시간 (PC를 안 끄고 다니는 경우)', 'onboarding.discord_enable': 'Discord 웹훅 알림 사용', 'onboarding.discord_failed': '실패', 'onboarding.discord_failed_body': '전송 실패. URL을 다시 확인해주세요.', 'onboarding.discord_guide': '셋업 방법:\n1. Discord 서버에서 채널 우클릭 → 편집 → 연동 → 웹훅\n2. 새 웹훅 만들기 → URL 복사\n3. 위 입력란에 붙여넣기', 'onboarding.discord_subtitle': '출퇴근 시각·휴식 권고를 Discord로 받으려면 웹훅 URL을 입력하세요. (모바일에서 푸시 알림)', 'onboarding.discord_success': '성공', 'onboarding.discord_success_body': 'Discord 채널에서 테스트 메시지를 확인하세요.', 'onboarding.discord_test': '테스트 메시지 보내기', 'onboarding.discord_title': 'Discord 알림 (선택)', 'onboarding.discord_url_invalid_body': 'Discord 웹훅 URL 형식이 아닙니다.\n예: https://discord.com/api/webhooks/{ID}/{TOKEN}', 'onboarding.discord_url_invalid_title': 'URL 형식 오류', 'onboarding.discord_url_placeholder': 'https://discord.com/api/webhooks/...', 'onboarding.discord_url_required_body': '웹훅 URL을 먼저 입력해주세요.', 'onboarding.discord_url_required_title': 'URL 필요', 'onboarding.finish_msg': '설정한 내용은 [설정] 메뉴에서 언제든 바꿀 수 있습니다.\n온보딩을 다시 보고 싶으면 [도움말 → 온보딩 다시 보기]를 누르세요.\n\n단축키:\n • Ctrl+O — 출퇴근 토글\n • F1 — 도움말\n • F5 — 업데이트 확인\n • Ctrl+, — 설정', 'onboarding.finish_subtitle': '이제 출근부터 자동 추적됩니다.', 'onboarding.finish_title': '준비 완료!', 'onboarding.hourly_wage': '시급:', 'onboarding.input_error_title': '입력 오류', 'onboarding.leave_group': '연간 연차', 'onboarding.leave_salary_subtitle': '연차 일수와 급여(선택)를 입력하세요.', 'onboarding.leave_salary_title': '연차 + 급여 (옵션)', 'onboarding.my_leave': '내 연차:', 'onboarding.overtime_rate': '연장수당 가산률:', 'onboarding.rate_1_5x': '1.5배 (한국 노동법 기본)', 'onboarding.rate_1x': '1.0배 (가산 없음)', 'onboarding.rate_2x': '2.0배 (야근/휴일 가산)', 'onboarding.salary_enabled': '급여 추정 활성화', 'onboarding.salary_group': '급여 추정 (옵션 — 포괄임금이면 비활성)', 'onboarding.wage_suffix': ' 원/시간', 'onboarding.welcome_intro': '이 앱은:\n• 컴퓨터 부팅/잠금 해제로 출근 시간 자동 감지\n• 30분 단위 연장근무 적립\n• 연차·반차·외출 시간 추적\n• 매일 퇴근 시간을 1초마다 카운트다운\n\n[다음] 버튼을 눌러 시작하세요.', 'onboarding.welcome_subtitle': 'Clock-out Time Calculator를 처음 사용하시는군요. 5단계로 빠르게 설정하겠습니다.', 'onboarding.welcome_title': '환영합니다!', 'onboarding.window_title': 'Clock-out Calculator — 시작 설정', 'onboarding.work_min_too_small': '하루 근무는 최소 30분 이상이어야 합니다.', 'onboarding.work_pattern_subtitle': '본인의 하루 근무 시간을 선택하세요. 나중에 설정에서 바꿀 수 있습니다.', 'onboarding.work_pattern_title': '근무 패턴', 'past_record.check_clock_out': '입력', 'past_record.check_dinner': '저녁시간 포함', 'past_record.check_lunch': '점심시간 포함', 'past_record.dialog_title': '기록 추가 — {date}', 'past_record.info': '{date} 근무 기록을 입력하세요.', 'past_record.input_error_body': '퇴근 시간이 출근 시간보다 빠르거나 같습니다.', 'past_record.input_error_title': '입력 오류', 'past_record.label_clock_in': '출근:', 'past_record.label_clock_out': '퇴근:', 'past_record.label_memo': '메모 (선택):', 'past_record.memo_placeholder': '예: 재택근무 / 외근 / 휴가', 'recurring.add_done_body': '반복 패턴이 등록되었습니다.\n{pattern}', 'recurring.add_done_title': '추가 완료', 'recurring.add_group': '신규 패턴 추가', 'recurring.biweekly': '격주', 'recurring.btn_add': '추가', 'recurring.btn_delete_selected': '선택 삭제', 'recurring.day_suffix': '일', 'recurring.deduction_full': '1.0일 (종일)', 'recurring.deduction_half': '0.5일 (반차)', 'recurring.deduction_quarter': '0.25일 (반반차)', 'recurring.delete_confirm_body': '이 반복 패턴을 삭제하시겠습니까?\n\n{item}', 'recurring.delete_confirm_title': '삭제 확인', 'recurring.input_error_title': '입력 오류', 'recurring.input_error_weekday': '최소 한 개 요일을 선택하세요.', 'recurring.label_cycle': '주기:', 'recurring.label_deduction': '차감:', 'recurring.label_end': '종료:', 'recurring.label_memo': '메모:', 'recurring.label_monthly_day': '매월:', 'recurring.label_start': '시작:', 'recurring.label_weekday': '요일:', 'recurring.list_group': '등록된 반복 패턴', 'recurring.memo_placeholder': '예: 육아 단축근무', 'recurring.monthly': '매월 N일', 'recurring.no_end': '종료 없음 (무기한)', 'recurring.title': '반복 연차 관리', 'recurring.pattern_weekly': '{prefix} {weekdays}요일', 'recurring.pattern_monthly': '매월 {day}일', 'recurring.weekly': '매주', 'schedule.btn_add_leave': '연차 등록', 'schedule.btn_recurring': '반복 패턴 관리', 'schedule.delete': '삭제', 'schedule.delete_leave_confirm_body': '이 연차 기록을 삭제하시겠습니까? (잔액이 자동 복구됩니다.)', 'schedule.delete_leave_confirm_title': '삭제 확인', 'schedule.delete_recurring_confirm_body': '이 반복 패턴을 삭제하시겠습니까? (이후 모든 인스턴스 제거)', 'schedule.delete_recurring_confirm_title': '삭제 확인', 'schedule.detail_placeholder': '날짜를 선택하세요', 'schedule.header': '월간 스케줄 — 휴일 + 연차 + 반복 패턴', 'schedule.holiday': '공휴일: {name}', 'schedule.leave_label': '{type} {days}일', 'schedule.recurring_item': '{pattern} · {days}일 ({type})', 'schedule.legend_half': '반차/반반차', 'schedule.legend_holiday': '공휴일', 'schedule.legend_leave_planned': '연차 예정', 'schedule.legend_leave_used': '연차 사용', 'schedule.legend_recurring': '반복 패턴', 'schedule.no_events': '일정 없음', 'schedule.title': '스케줄', 'schedule.weekend': '주말 ({weekday})', 'schedule.weekday_suffix': '요일', 'today.detail_break': '외출 {minutes}분', 'today.detail_dinner': '저녁 {minutes}분', 'today.detail_lunch': '점심 {minutes}분', 'today.detail_overtime': '연장 {actual}분 → 적립 {earned}분', 'today.title': '오늘의 요약', 'today.total_work': '총 근무: {hours}시간 {minutes}분', 'view.leave.btn_schedule': '스케줄', 'view.leave.duplicate_register_body': '{date}에 이미 {existing_days:.2f}일이 등록되어 있어\n추가 {days:.2f}일을 더하면 1일을 초과합니다.', 'view.leave.duplicate_register_title': '중복 등록 초과', 'view.leave.holiday_register_forbidden_body': '{date}는 이미 공휴일({name})입니다.\n연차를 차감할 필요가 없습니다.', 'view.leave.holiday_register_forbidden_title': '공휴일 등록 불가', 'view.leave.schedule_tooltip': '휴일 + 연차 + 반복 패턴 통합 보기', 'view.leave.used_1day': '1일', 'view.leave.used_half_day': '0.5일 (4시간)', 'view.leave.used_hours_fmt': '{days}일 ({hours}시간)', 'view.leave.used_days_fmt': '{days}일', 'view.leave.weekend_register_forbidden_body': '주말에는 연차를 등록할 수 없습니다. (이미 비근무일)', 'view.leave.weekend_register_forbidden_title': '주말 등록 불가', # === Achievements === 'achieve.streak_first.name': '첫걸음', 'achieve.streak_first.desc': '첫 출근 기록', 'achieve.streak_3.name': '뿌리내림', 'achieve.streak_3.desc': '3일 연속 영업일 출근', 'achieve.streak_5.name': '첫 주 완주', 'achieve.streak_5.desc': '5 영업일 연속 출근', 'achieve.streak_7_cal.name': '7일 연속', 'achieve.streak_7_cal.desc': '주말 포함 7일 연속 출근', 'achieve.streak_10.name': '2주 연속', 'achieve.streak_10.desc': '10 영업일 연속 출근', 'achieve.streak_22.name': '한 달 개근', 'achieve.streak_22.desc': '한 달 영업일 100% 출근 (22일)', 'achieve.streak_50.name': '50일 연속', 'achieve.streak_50.desc': '50 영업일 연속 출근', 'achieve.streak_100.name': '100일 연속', 'achieve.streak_100.desc': '100 영업일 연속 출근', 'achieve.streak_quarter.name': '분기 완주', 'achieve.streak_quarter.desc': '약 65 영업일 (3개월)', 'achieve.streak_half_year.name': '반년 마라톤', 'achieve.streak_half_year.desc': '약 130 영업일 (6개월)', 'achieve.streak_year.name': '1년 풀 시즌', 'achieve.streak_year.desc': '약 260 영업일 (1년)', 'achieve.streak_200.name': '사이언스', 'achieve.streak_200.desc': '200 영업일 연속', 'achieve.streak_365_cal.name': '불사신', 'achieve.streak_365_cal.desc': '365일 달력 연속', 'achieve.streak_resilience.name': '회복력', 'achieve.streak_resilience.desc': '결근 후 다음날 즉시 출근 (자동: 달력 streak 깨진 후 재시작)', 'achieve.streak_total_100.name': '누적 100회', 'achieve.streak_total_100.desc': '누적 출근 100회', 'achieve.streak_total_500.name': '누적 500회', 'achieve.streak_total_500.desc': '누적 출근 500회', 'achieve.streak_total_1000.name': '누적 1000회', 'achieve.streak_total_1000.desc': '누적 출근 1000회', 'achieve.punc_before_8_1.name': '얼리버드', 'achieve.punc_before_8_1.desc': '08:00 이전 출근 1회', 'achieve.punc_before_8_10.name': '참새족', 'achieve.punc_before_8_10.desc': '08:00 이전 10회', 'achieve.punc_before_8_30.name': '일찍 자고 일찍', 'achieve.punc_before_8_30.desc': '08:00 이전 30회', 'achieve.punc_before_6_1.name': '새벽잠 없음', 'achieve.punc_before_6_1.desc': '06:00 이전 1회', 'achieve.punc_before_6_10.name': '어둠을 가르는 자', 'achieve.punc_before_6_10.desc': '06:00 이전 10회', 'achieve.punc_before_5.name': '새벽 챔피언', 'achieve.punc_before_5.desc': '05:00 이전 출근', 'achieve.punc_at_9.name': '9시 정각', 'achieve.punc_at_9.desc': '09:00 정각(±1분) 출근 1회', 'achieve.punc_at_9_5.name': '완벽한 9시', 'achieve.punc_at_9_5.desc': '09:00 정각(±1분) 5회', 'achieve.punc_late_5min.name': '5분 늦음', 'achieve.punc_late_5min.desc': '09:00~09:05 출근 1회 (자조)', 'achieve.punc_at_909.name': '운명의 시각', 'achieve.punc_at_909.desc': '09:09 출근 (시크릿)', 'achieve.bal_first_punct.name': '첫 칼퇴', 'achieve.bal_first_punct.desc': '정시 퇴근 첫 달성', 'achieve.bal_punct_10.name': '칼퇴러', 'achieve.bal_punct_10.desc': '정시 퇴근 10회', 'achieve.bal_punct_30.name': '칼퇴 챔프', 'achieve.bal_punct_30.desc': '정시 퇴근 30회', 'achieve.bal_punct_100.name': '진정한 자유', 'achieve.bal_punct_100.desc': '정시 퇴근 100회', 'achieve.bal_punct_300.name': '워라밸 마스터', 'achieve.bal_punct_300.desc': '정시 퇴근 300회', 'achieve.ot_first_30m.name': '첫 30분', 'achieve.ot_first_30m.desc': '첫 연장 적립', 'achieve.ot_total_60m.name': '1시간 적금', 'achieve.ot_total_60m.desc': '누적 1시간 적립', 'achieve.ot_total_5h.name': '5시간 적립', 'achieve.ot_total_5h.desc': '누적 5시간', 'achieve.ot_total_10h.name': '10시간 적립', 'achieve.ot_total_10h.desc': '누적 10시간', 'achieve.ot_total_25h.name': '25시간 적립', 'achieve.ot_total_25h.desc': '누적 25시간', 'achieve.ot_total_50h.name': '50시간 적립', 'achieve.ot_total_50h.desc': '누적 50시간', 'achieve.ot_total_100h.name': '마라토너', 'achieve.ot_total_100h.desc': '누적 100시간 (걱정 메시지)', 'achieve.ot_total_200h.name': '워크홀릭 경고', 'achieve.ot_total_200h.desc': '누적 200시간 (경고)', 'achieve.ot_total_300h.name': '위험 신호', 'achieve.ot_total_300h.desc': '누적 300시간 (강한 경고)', 'achieve.ot_total_500h.name': '응급실 단골', 'achieve.ot_total_500h.desc': '누적 500시간 (자조)', 'achieve.use_first.name': '첫 휴식', 'achieve.use_first.desc': '적립 첫 사용', 'achieve.use_total_5h.name': '선물 사용', 'achieve.use_total_5h.desc': '누적 5시간 사용', 'achieve.use_total_25h.name': '휴식의 가치', 'achieve.use_total_25h.desc': '누적 25시간 사용', 'achieve.use_total_50h.name': '회복 마스터', 'achieve.use_total_50h.desc': '누적 50시간 사용', 'achieve.use_total_100h.name': '마사지', 'achieve.use_total_100h.desc': '누적 100시간 사용', 'achieve.leave_first.name': '첫 연차', 'achieve.leave_first.desc': '첫 연차 사용', 'achieve.leave_half.name': '첫 반차', 'achieve.leave_half.desc': '0.5일 연차 사용', 'achieve.leave_quarter.name': '시간 연차', 'achieve.leave_quarter.desc': '0.25일 연차 사용', 'achieve.leave_streak_3.name': '미니 휴가', 'achieve.leave_streak_3.desc': '연속 3일 연차', 'achieve.leave_streak_5.name': '본격 휴가', 'achieve.leave_streak_5.desc': '연속 5일 연차', 'achieve.leave_streak_7.name': '장거리 휴가', 'achieve.leave_streak_7.desc': '연속 7일 이상 연차', 'achieve.leave_total_10.name': '연차 10회', 'achieve.leave_total_10.desc': '연차 기록 10건', 'achieve.leave_sick.name': '병가', 'achieve.leave_sick.desc': 'sick 타입 연차 사용', 'achieve.meal_lunch_first.name': '첫 점심 등록', 'achieve.meal_lunch_first.desc': '점심 첫 토글', 'achieve.meal_lunch_30.name': '점심 마스터', 'achieve.meal_lunch_30.desc': '점심 등록 30회', 'achieve.meal_lunch_100.name': '점심 챔프', 'achieve.meal_lunch_100.desc': '점심 등록 100회', 'achieve.meal_dinner_first.name': '첫 저녁 등록', 'achieve.meal_dinner_first.desc': '저녁 첫 토글', 'achieve.meal_dinner_10.name': '저녁 단골', 'achieve.meal_dinner_10.desc': '저녁 등록 10회 (경고)', 'achieve.meal_dinner_30.name': '야식 단골', 'achieve.meal_dinner_30.desc': '저녁 등록 30회 (경고)', 'achieve.meal_lunch_actual.name': '실측 점심', 'achieve.meal_lunch_actual.desc': '실제 점심 시각 입력', 'achieve.meal_dinner_actual.name': '실측 저녁', 'achieve.meal_dinner_actual.desc': '실제 저녁 시각 입력', 'achieve.break_first.name': '첫 외출', 'achieve.break_first.desc': '첫 외출 시작', 'achieve.break_10.name': '외출 챔프', 'achieve.break_10.desc': '외출 10회', 'achieve.break_50.name': '산책러', 'achieve.break_50.desc': '외출 50회', 'achieve.slot_in_06.name': '06시대 출근', 'achieve.slot_in_06.desc': '06:00-06:59 출근 1회', 'achieve.slot_in_07.name': '07시대 출근', 'achieve.slot_in_07.desc': '07:00-07:59 출근 1회', 'achieve.slot_in_08.name': '08시대 출근', 'achieve.slot_in_08.desc': '08:00-08:59 출근 1회', 'achieve.slot_in_10.name': '10시대 출근', 'achieve.slot_in_10.desc': '10시대 출근 (지각/유연근무)', 'achieve.slot_in_11.name': '11시대 출근', 'achieve.slot_in_11.desc': '11시대 출근 (자조)', 'achieve.slot_out_19.name': '19시대 퇴근', 'achieve.slot_out_19.desc': '19시대 퇴근 10회 (경고)', 'achieve.slot_out_20.name': '20시대 퇴근', 'achieve.slot_out_20.desc': '20시대 퇴근 10회 (경고)', 'achieve.slot_out_21.name': '21시대 퇴근', 'achieve.slot_out_21.desc': '21시대 퇴근 5회 (경고)', 'achieve.slot_out_22.name': '22시대 퇴근', 'achieve.slot_out_22.desc': '22시대 퇴근 1회 (경고)', 'achieve.slot_out_23.name': '23시대 퇴근', 'achieve.slot_out_23.desc': '23시대 퇴근 1회 (경고)', 'achieve.slot_midnight.name': '자정 퇴근', 'achieve.slot_midnight.desc': '자정 이후 퇴근 (경고)', 'achieve.slot_midnight_3.name': '올빼미 트리오', 'achieve.slot_midnight_3.desc': '자정 이후 퇴근 3회 (경고)', 'achieve.weekend_1.name': '주말 출근 1회', 'achieve.weekend_1.desc': '토/일 출근 1회', 'achieve.weekend_5.name': '주말 워커', 'achieve.weekend_5.desc': '주말 출근 5회 (경고)', 'achieve.weekend_20.name': '진짜 워크홀릭', 'achieve.weekend_20.desc': '주말 출근 20회 (강한 자조)', 'achieve.holiday_1.name': '공휴일 출근', 'achieve.holiday_1.desc': '한국 공휴일 출근 1회', 'achieve.holiday_5.name': '공휴일 워커홀릭', 'achieve.holiday_5.desc': '한국 공휴일 출근 5회 (경고)', 'achieve.day_christmas.name': '크리스마스 출근', 'achieve.day_christmas.desc': '12/25 출근 (자조)', 'achieve.day_newyear.name': '신정 출근', 'achieve.day_newyear.desc': '1/1 출근 (자조)', 'achieve.day_liberation.name': '광복절 출근', 'achieve.day_liberation.desc': '8/15 출근', 'achieve.day_children.name': '어린이날 출근', 'achieve.day_children.desc': '5/5 출근 (자조)', 'achieve.day_hangul.name': '한글날 출근', 'achieve.day_hangul.desc': '10/9 출근', 'achieve.day_valentine.name': '발렌타인데이 출근', 'achieve.day_valentine.desc': '2/14 출근', 'achieve.day_white.name': '화이트데이 출근', 'achieve.day_white.desc': '3/14 출근', 'achieve.day_pepero.name': '빼빼로데이', 'achieve.day_pepero.desc': '11/11 출근', 'achieve.day_halloween.name': '핼러윈 출근', 'achieve.day_halloween.desc': '10/31 출근', 'achieve.day_aprilfools.name': '만우절 출근', 'achieve.day_aprilfools.desc': '4/1 출근', 'achieve.day_77.name': '칠월칠석', 'achieve.day_77.desc': '7/7 출근', 'achieve.day_dongji.name': '동지 출근', 'achieve.day_dongji.desc': '12/22 출근', 'achieve.day_parents.name': '어버이날 정시 퇴근', 'achieve.day_parents.desc': '5/8 정시 퇴근', 'achieve.day_teacher.name': '스승의 날 정시 퇴근', 'achieve.day_teacher.desc': '5/15 정시 퇴근', 'achieve.day_xmas_eve.name': '크리스마스이브 정시 퇴근', 'achieve.day_xmas_eve.desc': '12/24 정시 퇴근', 'achieve.day_earth.name': '지구의 날', 'achieve.day_earth.desc': '4/22 출근 (시크릿)', 'achieve.season_jan.name': '1월 정착', 'achieve.season_jan.desc': '1월 한 달 출근', 'achieve.season_feb.name': '2월 정착', 'achieve.season_feb.desc': '2월 영업일 모두 출근', 'achieve.season_mar.name': '봄을 맞이', 'achieve.season_mar.desc': '3월 첫 출근', 'achieve.season_apr.name': '4월 정착', 'achieve.season_apr.desc': '4월 한 달 출근', 'achieve.season_may.name': '5월 정착', 'achieve.season_may.desc': '5월 영업일 모두 출근', 'achieve.season_jun.name': '여름의 시작', 'achieve.season_jun.desc': '6월 첫 출근', 'achieve.season_jul.name': '7월 정착', 'achieve.season_jul.desc': '7월 한 달 출근', 'achieve.season_aug.name': '8월 정착', 'achieve.season_aug.desc': '8월 영업일 모두 출근', 'achieve.season_sep.name': '가을의 시작', 'achieve.season_sep.desc': '9월 첫 출근', 'achieve.season_oct.name': '10월 정착', 'achieve.season_oct.desc': '10월 한 달 출근', 'achieve.season_nov.name': '11월 단풍', 'achieve.season_nov.desc': '11월 영업일 모두 출근', 'achieve.season_dec.name': '겨울의 시작', 'achieve.season_dec.desc': '12월 첫 출근', 'achieve.mile_first.name': 'Hello, World!', 'achieve.mile_first.desc': '앱 첫 실행', 'achieve.mile_7days.name': '일주일 사용', 'achieve.mile_7days.desc': '7일 사용', 'achieve.mile_30days.name': '한 달 사용', 'achieve.mile_30days.desc': '30일 사용', 'achieve.mile_365days.name': '1주년', 'achieve.mile_365days.desc': '365일 사용', 'achieve.mile_730days.name': '2주년', 'achieve.mile_730days.desc': '730일 사용', 'achieve.mile_1095days.name': '3주년', 'achieve.mile_1095days.desc': '3년 사용', 'achieve.mile_5years.name': '5년 사용자', 'achieve.mile_5years.desc': '5년 사용', 'achieve.mile_10years.name': '10년 사용자', 'achieve.mile_10years.desc': '10년 사용', 'achieve.stat_weekly_10.name': '주간 통계러', 'achieve.stat_weekly_10.desc': '주간 탭 10회 조회', 'achieve.stat_monthly_10.name': '월간 통계러', 'achieve.stat_monthly_10.desc': '월간 탭 10회', 'achieve.stat_pattern_10.name': '패턴 분석가', 'achieve.stat_pattern_10.desc': '패턴 탭 10회', 'achieve.stat_calendar_30.name': '캘린더 챔프', 'achieve.stat_calendar_30.desc': '캘린더 30회 조회', 'achieve.stat_report_first.name': '일일 보고서 첫 생성', 'achieve.stat_report_first.desc': '일일 보고 1회', 'achieve.stat_report_30.name': '보고서 챔프', 'achieve.stat_report_30.desc': '일일 보고 30회', 'achieve.stat_chart_hover.name': '차트 호버 발견', 'achieve.stat_chart_hover.desc': '차트 hover 첫 발견', 'achieve.stat_achievements_open.name': '도전과제 박물관', 'achieve.stat_achievements_open.desc': '도전과제 뷰 50회', 'achieve.secret_palindrome.name': '회문 시각', 'achieve.secret_palindrome.desc': '출근 시각이 회문', 'achieve.secret_jackpot.name': '잭팟 시각', 'achieve.secret_jackpot.desc': '출근 시각 모든 자릿수 동일', 'achieve.secret_fri13.name': '13일 금요일', 'achieve.secret_fri13.desc': '13일 금요일 출근', 'achieve.secret_777.name': '7-7-7', 'achieve.secret_777.desc': '7월 7일 7시 7분 출근', 'achieve.secret_exact_8h.name': '정확 8시간', 'achieve.secret_exact_8h.desc': '정확히 8h 0m 근무', 'achieve.secret_pi_day.name': '파이 데이', 'achieve.secret_pi_day.desc': '3/14 01:59 출근', 'achieve.secret_fibonacci.name': '피보나치', 'achieve.secret_fibonacci.desc': '출근 분이 피보나치 수', 'achieve.secret_double_six.name': '더블 식스', 'achieve.secret_double_six.desc': '6/6 18:06 출근', 'achieve.secret_anniversary.name': '마법사', 'achieve.secret_anniversary.desc': '가입 후 정확히 365일 후 출근', 'achieve.set_dark.name': '다크 사이드', 'achieve.set_dark.desc': '다크 테마 1회 사용', 'achieve.set_lang.name': '이중언어', 'achieve.set_lang.desc': '언어 변경 (en 사용)', 'achieve.set_a11y.name': '접근성 활용', 'achieve.set_a11y.desc': '글꼴 크기≠100% 또는 고대비 ON', 'achieve.set_overtime_unit.name': '단위 변경', 'achieve.set_overtime_unit.desc': 'overtime_unit 변경', 'achieve.set_goal_full.name': '목표 마스터', 'achieve.set_goal_full.desc': '월 연장+일평균 둘 다 설정', 'achieve.set_discord_full.name': '풀 셋업', 'achieve.set_discord_full.desc': 'Discord URL + 모든 알림 ON', 'achieve.set_cloud.name': '클라우드 동기화', 'achieve.set_cloud.desc': 'DB 경로 변경', 'achieve.meta_first.name': '첫 도전과제', 'achieve.meta_first.desc': '첫 도전과제 획득', 'achieve.meta_10.name': '10개 달성', 'achieve.meta_10.desc': '10개 보유', 'achieve.meta_25.name': '25개 달성', 'achieve.meta_25.desc': '25개 보유', 'achieve.meta_50.name': '50개 달성', 'achieve.meta_50.desc': '50개 보유', 'achieve.meta_75.name': '75개 달성', 'achieve.meta_75.desc': '75개 보유', 'achieve.meta_100.name': '100개 달성', 'achieve.meta_100.desc': '100개 보유', 'achieve.meta_secret_1.name': '시크릿 발견', 'achieve.meta_secret_1.desc': '첫 시크릿 발견', 'achieve.meta_secret_5.name': '시크릿 헌터', 'achieve.meta_secret_5.desc': '시크릿 5개 발견', 'achieve.streak_monday_10.name': '월요일 정복', 'achieve.streak_monday_10.desc': '월요일 10주 연속 출근', 'achieve.streak_friday_10.name': '금요일 무결', 'achieve.streak_friday_10.desc': '금요일 10주 연속 출근', }, 'en': { # === Menu/Buttons === 'menu.stats': 'Stats', 'menu.calendar': 'Calendar', 'menu.daily_report': 'Daily Report', 'menu.help': 'Help', 'menu.settings': 'Settings', 'btn.clock_out': 'Clock Out', 'btn.clock_out_cancel': 'Cancel Clock-out', 'btn.lunch_add': 'Add Lunch', 'btn.lunch_applied': 'Lunch (Applied)', 'btn.dinner_add': 'Add Dinner', 'btn.dinner_applied': 'Dinner (Applied)', 'btn.break_out': 'Start Break', 'btn.break_in': 'Return', 'btn.save': 'Save', 'btn.close': 'Close', 'btn.apply': 'Apply', 'btn.cancel': 'Cancel', 'btn.add': 'Add', 'btn.delete': 'Delete', 'btn.edit': 'Edit', 'btn.confirm': 'Confirm', 'btn.ok': 'OK', # === Windows === 'window.main_title': 'Clock-out Time Calculator', 'window.settings': 'Settings', 'window.help': 'User Guide', 'window.stats': 'Statistics', 'window.calendar': 'Calendar', 'window.mini_widget': 'Clock-out', 'window.clock_in_dialog': 'Clock-in Time', 'window.break_view': 'Break Management', 'window.overtime_view': 'Overtime Management', 'window.leave_view': 'Leave Management', # === Labels === 'label.remaining': 'Remaining', 'label.overtime_progress': 'Overtime', 'label.expected_clock_out': 'Expected Clock-out', 'label.clock_in_time': 'Clock-in', 'label.current_time': 'Current', 'label.clock_out_time': 'Clock-out Time', 'label.work_hours_label': 'Daily work:', 'label.lunch_default': 'Lunch break:', 'label.dinner_default': 'Dinner break:', 'label.work_pattern': 'Work pattern:', 'label.time_format': 'Time format:', 'label.theme': 'Theme:', 'label.language': 'Language / 언어:', 'label.unit_hour': 'h', 'label.unit_minute': 'min', 'label.unit_day': 'day(s)', 'label.unit_count': '', 'label.weekday_mon': 'Mon', 'label.weekday_tue': 'Tue', 'label.weekday_wed': 'Wed', 'label.weekday_thu': 'Thu', 'label.weekday_fri': 'Fri', 'label.weekday_sat': 'Sat', 'label.weekday_sun': 'Sun', 'label.am': 'AM', 'label.pm': 'PM', 'label.recurring_yearly': ' (yearly)', # === Notifications === 'notif.clock_out_soon.title': '⏰ Clock-out Soon', 'notif.clock_out_soon.body': "{minutes} minutes until clock-out.\nWrap things up!", 'notif.lunch_reminder.title': '🍱 Lunch Reminder', 'notif.lunch_reminder.body': "You haven't registered lunch yet.\nWant to add it?", 'notif.dinner_reminder.title': '🍽️ Dinner Reminder', 'notif.dinner_reminder.body': "You haven't registered dinner yet.\nWant to add it?", # === Onboarding work pattern presets === 'onboarding.preset.standard_8h': 'Standard 8h (Lunch 60min)', 'onboarding.preset.short_7h30m': 'Reduced 7h 30m (Lunch 30min)', 'onboarding.preset.short_7h': 'Reduced 7h (Lunch 60min)', 'onboarding.preset.short_6h': 'Reduced 6h (Lunch 30min)', 'onboarding.preset.half_4h': 'Half-day 4h (No Lunch)', 'onboarding.preset.custom_box': 'Custom', 'onboarding.preset.custom_radio': 'Manual entry:', 'onboarding.preset.suffix_hours': ' h', 'onboarding.preset.suffix_minutes': ' min', 'onboarding.preset.lunch_prefix': 'Lunch ', 'onboarding.preset.dinner_prefix': 'Dinner ', 'onboarding.preset.dinner_tooltip': 'Set if you often have dinner during overtime (typically 0~60 min)', 'notif.health_break.title': '🌿 Take a Break', 'notif.health_break.body': "You've been at your desk for over {hours} hours.\nStand up and stretch!", 'notif.overtime_earning.title': '🔥 Overtime Will Accrue', 'notif.overtime_earning.body': "{time_str} of overtime will be banked today!", 'notif.overtime_threshold.title': '💰 Overtime Balance High', 'notif.overtime_threshold.body': "{hours:.1f} hours of overtime banked.\nConsider using some.", 'notif.health.title': '⚠️ Health Warning', 'notif.health.body': "{days} consecutive days of overtime.\nTake care of your health!", 'notif.weekly_52.title': '🚨 Weekly 52h Exceeded', 'notif.weekly_52.body': "This week's total work hours: {hours:.1f}\nLegal limit exceeded!", 'notif.weekly_report.title': '📊 Last Week Summary', 'notif.weekly_report.body': 'Period: {start} ~ {end}\nTotal: {total_h:.1f}h ({days} days)\nDaily Avg: {avg_h:.1f}h\nOvertime: {ot_h}h {ot_m}m\nLongest Day: {longest}', 'field.total_work': 'Total Work', 'field.avg_daily': 'Daily Avg', 'field.overtime': 'Overtime', 'field.longest_day': 'Longest Day', 'notif.achievement.title': '{icon} Achievement Unlocked!', 'notif.achievement.body': '{name}\n{description}', 'discord.achievement.title': '🏆 {count} Achievements Unlocked!', 'discord.achievement.body': 'Newly unlocked achievements.{extra}', # === Message Boxes === 'msg.save_success.title': 'Saved', 'msg.save_success.body': 'Settings saved successfully.', 'msg.input_error.title': 'Input Error', 'msg.work_min_too_small': 'Daily work time must be at least 30 minutes.', 'msg.no_clock_in.title': 'Cannot Take Break', 'msg.no_clock_in.body': 'Not clocked in.', 'msg.already_break.body': 'Already on break.', 'msg.no_record.title': 'No Record', 'msg.no_record.body': 'No clock-in record for today.', 'msg.confirm_delete.title': 'Confirm Delete', 'msg.no_data.title': 'No Data', 'msg.manual_added': 'Manual', # === Tray === 'tray.open': 'Open Program', 'tray.mini_widget': 'Mini Widget', 'tray.toggle_lunch': 'Toggle Lunch', 'tray.quit': 'Quit', 'tray.tooltip_remaining': 'Until clock-out: {time}', 'tray.tooltip_overtime': 'Overtime: {time}', 'tray.background': 'Program is running in the tray.', # === Groups === 'group.work_time': 'Work Time Settings', 'group.notification': 'Notifications & Display', 'group.overtime': 'Overtime Settings', 'group.leave': 'Leave Settings', 'group.holiday': 'Holidays', 'group.data': 'Data Management', # === StatsView === 'stats.title': 'Work Statistics', 'stats.tab_weekly': 'Weekly', 'stats.tab_monthly': 'Monthly', 'stats.tab_pattern': 'Patterns', 'stats.weekly_summary': 'This Week', 'stats.monthly_summary': 'This Month', 'stats.total_hours': 'Total hours:', 'stats.work_days': 'Work days:', 'stats.avg_hours': 'Avg hours/day:', 'stats.total_overtime': 'Total overtime:', 'stats.pattern_insights': 'Work Pattern Insights', 'stats.analyzing': 'Analyzing...', 'stats.no_data': 'Not enough data yet.', 'stats.total_work_hours': 'Total Work Hours', 'stats.card_work_days': 'Work Days', 'stats.card_avg_hours': 'Daily Avg', 'stats.card_overtime': 'Overtime', 'stats.this_week': 'This Week', 'stats.this_month': 'This Month', 'stats.daily_work_hours': 'Daily Work Hours', 'stats.weekday_avg': 'Avg by Weekday', 'stats.clock_in_distribution': 'Clock-in Distribution', 'stats.no_pattern_data': 'Not enough data to analyze patterns.', 'stats.value_hours': '{hours}h', 'stats.value_hours_minutes': '{hours}h {minutes}m', 'stats.value_days': '{days}d', 'stats.avg_clock_in': '📌 Avg clock-in: {time}', 'stats.overtime_frequency': '📌 OT frequency: {rate}% ({days}/{total} days)', 'stats.longest_work': '📌 Longest day: {date} ({hours}h)', 'stats.consecutive_ot_warning': '⚠️ {days} consecutive OT days!', 'stats.weekly_52_exceeded': '🚨 Weekly 52h exceeded: {hours}h', 'stats.salary_estimate': '💰 Est. salary: {total} (base {base} + OT {overtime})', # === CalendarView === 'cal.title': 'Monthly Calendar', 'cal.year_label': 'Y', 'cal.month_label': 'M', 'cal.prev': '◀ Prev', 'cal.next': 'Next ▶', 'cal.today': 'Today', 'cal.no_record': 'No record', 'cal.edit_record': 'Edit record', # === HelpView === 'help.tab_intro': 'Getting Started', 'help.tab_work_hours': 'Work Hours', 'help.tab_overtime': 'Overtime', 'help.tab_leave': 'Leave', 'help.tab_break': 'Break/Dinner', 'help.tab_faq': 'FAQ', # === clock_in_dialog === 'dlg.clock_in.prompt': "Enter today's clock-in time", 'dlg.clock_in.label': 'Clock-in time:', 'dlg.clock_in.quick': 'Quick pick:', 'dlg.clock_in.btn_now': 'Now', # === break_view === 'dlg.break.edit_title': 'Edit Break Record', 'dlg.break.out_label': 'Break out:', 'dlg.break.in_label': 'Return:', 'dlg.break.reason_label': 'Reason:', 'view.break.today_title': "Today's Break Records", 'view.break.col_out': 'Break out', 'view.break.col_in': 'Return', 'view.break.col_duration': 'Duration', 'view.break.col_reason': 'Reason', 'view.break.in_progress': 'In progress', 'view.break.total_zero': 'Total break: 0 min', 'view.break.total_fmt': 'Total break: {h}h {m}m', 'view.break.total_min_only': 'Total break: {m} min', 'view.break.duration_fmt': '{h}h {m}m', 'view.break.duration_min_only': '{m} min', 'view.break.delete_confirm': 'Delete this break record?', 'btn.refresh': 'Refresh', 'btn.edit_short': 'Edit', 'btn.delete_short': 'Delete', # === overtime_view === 'view.overtime.title': 'Overtime History', 'view.overtime.balance_zero': 'Balance: 0 min', 'view.overtime.balance_fmt': 'Current balance: {h}h {m}m ({total} min)', 'view.overtime.earned_group': 'Earned', 'view.overtime.used_group': 'Used', 'view.overtime.col_date': 'Date', 'view.overtime.col_earned': 'Earned', 'view.overtime.col_used': 'Used', 'view.overtime.col_memo': 'Memo', 'view.overtime.col_reason': 'Reason', 'view.overtime.btn_add_earned': 'Manual Earn', 'view.overtime.btn_add_used': 'Manual Use', 'view.overtime.menu_delete': 'Delete', 'view.overtime.delete_confirm_body': 'Delete this usage record?\n\nDate: {date}\nTime: {time}\nReason: {reason}', 'view.overtime.delete_earned_confirm_body': 'Delete this accrual record?\n\nDate: {date}\nEarned: {time}\n\nThe balance will be reduced accordingly.', 'view.overtime.manual_earned_title': 'Manual Overtime Earn', 'view.overtime.manual_used_title': 'Manual Overtime Use', 'view.overtime.field_date': 'Date:', 'view.overtime.field_time': 'Time:', 'view.overtime.field_memo': 'Memo:', 'view.overtime.field_reason': 'Reason:', 'view.overtime.unit_hour_suffix': 'h', 'view.overtime.minute_0': '0 min', 'view.overtime.minute_30': '30 min', 'view.overtime.placeholder_memo': 'Optional', 'view.overtime.placeholder_reason': 'e.g., personal', 'view.overtime.zero_add_error': 'Cannot add 0 minutes.', 'view.overtime.zero_use_error': 'Cannot use 0 minutes.', 'view.overtime.balance_short_title': 'Insufficient Balance', 'view.overtime.balance_short_body': 'Not enough balance.\n\nRequested: {req_h}h {req_m}m\nBalance: {bal_h}h {bal_m}m', 'view.overtime.saved_earned': '{h}h {m}m banked.', 'view.overtime.saved_used': '{h}h {m}m used.', # === leave_view === 'view.leave.title': 'Leave Management', 'view.leave.balance_zero': 'Balance: 0 days', 'view.leave.balance_fmt': 'Balance: {days} days ({hours}h total)', 'view.leave.btn_set_balance': 'Set Balance', 'view.leave.used_group': 'Used', 'view.leave.col_date': 'Date', 'view.leave.col_type': 'Type', 'view.leave.col_used': 'Used', 'view.leave.col_reason': 'Reason', 'view.leave.btn_add': 'Add Leave Usage', 'view.leave.btn_calendar': 'Calendar', 'view.leave.delete_confirm_body': 'Delete this leave record?\n\nDate: {date}\nType: {type}\nUsed: {days}', 'view.leave.set_title': 'Set Leave Hours', 'view.leave.set_prompt': 'Enter leave hours remaining (0.5h step):\ne.g. 8h = 1d, 4h = 0.5d (half), 2h = 0.25d, 0.5h = 30min', 'view.leave.set_done_title': 'Saved', 'view.leave.set_done_body': 'Leave balance set to {days} days ({hours}h).', 'view.leave.add_title': 'Add Leave Usage', 'view.leave.field_date': 'Date:', 'view.leave.field_type': 'Type:', 'view.leave.field_hours': 'Hours:', 'view.leave.field_reason': 'Reason:', 'view.leave.type_annual': 'Annual', 'view.leave.type_half': 'Half', 'view.leave.type_quarter': 'Quarter', 'view.leave.type_hourly': 'Hourly', 'view.leave.placeholder_reason': 'e.g., personal, medical', 'view.leave.note_auto_deduct': '※ Leave balance is auto-deducted.', 'view.leave.short_title': 'Insufficient Leave', 'view.leave.short_body': 'Not enough leave.\nCurrent: {balance} days\nRequested: {req} days', 'view.leave.confirm_title': 'Add Leave Usage', 'view.leave.confirm_body': 'Date: {date}\nType: {type}\nUsed: {days} days ({hours}h)\nReason: {reason}\n\nAdd this record?', 'view.leave.added_title': 'Added', 'view.leave.added_body': '{days} days ({hours}h) of leave usage recorded.', 'view.leave.error_title': 'Error', 'view.leave.error_body': 'Failed to add leave record:\n{err}', # === Main Window additions === 'app.title': 'Clock-out Time Calculator', 'group.today_work': "Today's Work", 'group.remaining_time': 'Remaining Time', 'group.overtime_leave': 'Overtime & Leave Status', 'tooltip.meal_click': 'Left click: toggle / Right click: enter actual time', 'tooltip.clock_in_edit': 'Click to edit clock-in time', 'btn.achievements': 'Achievements', 'btn.break_manage': 'Manage Breaks', 'section.overtime_earned': 'Overtime Banked', 'section.leave': 'Annual Leave', 'section.total_time': 'Total Banked Time', 'btn.use_30min': '30m', 'btn.use_1hour': '1h', 'btn.use_2hour': '2h', 'btn.custom_input': 'Custom', 'btn.detail': 'Detail', 'btn.half_leave': 'Half-day', 'btn.full_leave': 'Full-day', 'msg.auto_clock_in.title': 'Auto Clock-in Detected', 'msg.auto_clock_in.body': 'Clock-in time was automatically detected.\nClock-in: {time}\n\nYou can edit it if incorrect.', 'msg.manual_clock_in.title': 'Enter Clock-in Time', 'msg.manual_clock_in.body': 'Could not detect clock-in time automatically.\n\nEnter manually?\n(Run as administrator for auto detection.)', 'msg.full_day_leave.title': 'Full-day Leave Registered', 'msg.full_day_leave.body': 'Today is registered as full-day leave.\nDo you still want to clock in?\n\n(All time will be banked as overtime.)', 'label.full_day_leave_override': 'Leave Override (Full Bank)', 'label.weekend_work': 'Weekend Work (Full Bank)', 'label.holiday_work': 'Holiday Work (Full Bank)', 'label.holiday_work_no_clock_out': 'Holiday Work (No fixed clock-out)', 'label.holiday_default': 'Holiday', 'label.expected_clock_out_prefix': 'Expected: ', 'label.total_work_hours': 'Total work: {hours:.1f}h', 'label.weekend_work_tag': '[Weekend Work]', 'label.holiday_work_tag': '[Holiday Work - {name}]', 'label.overtime_earned_msg': 'Overtime earned: {time} (🕐×{tokens})', 'label.full_earned_msg': 'Full earned: {time} (🕐×{tokens})', 'label.full_day_leave_today': 'Today is leave', 'label.full_day_leave_in_use': 'Leave in use', 'label.full_day_leave_format': '{type} — {memo}', 'label.vacation': '🌴 Leave', 'label.time_hours_minutes': '{hours}h {minutes}m', 'time_format.12h': '{hour}:{minute} {period}', 'break.status_in_progress': 'On break (since {time})', 'break.status_total_hours_minutes': 'Total break today: {hours}h {minutes}m', 'break.status_total_minutes': 'Total break today: {minutes}m', 'break.reason.lock': 'Screen lock', 'break.cannot_no_clock_in.title': 'Cannot Start Break', 'break.cannot_no_clock_in.body': 'Not clocked in.', 'break.cannot_already_on_break.body': 'Already on break.', 'break.cannot_no_record.body': 'No clock-in record found.', 'break.started.title': 'Break Started', 'break.started.body': 'Break started: {time}', 'break.cannot_return_no_active.body': 'No active break record found.', 'break.cannot_return_corrupt.body': 'Break record is corrupted.', 'break.cannot_return_unusable.body': 'Break record too corrupted to return.', 'break.return.title': 'Return', 'break.return.body': 'Returned: {time}\nBreak: {minutes}m', 'mini.open_main': 'Open main window', 'mini.close': 'Close mini widget', 'msg.clock_out_confirm.title': 'Clock-out Confirm', 'msg.clock_out_confirm.body': 'Clock out now?\n\nClock-out: {time}', 'msg.auto_overtime_confirm.title': 'Confirm Overtime Bank', 'msg.auto_overtime_confirm.body': 'Overtime {actual} occurred, {earned} eligible for banking.\n\nBank it?\n(No = this clock-out will not be banked)', 'msg.clock_out_done.title': 'Clock-out Complete', 'msg.clock_out_done.body': 'Clocked out!\n\n{type_info}{total_work}\n{overtime_info}', 'msg.cancel_clock_out_confirm.body': 'Cancel clock-out?\n\nClock-out time and overtime bank entries will be deleted.', 'msg.cancel_clock_out_done.title': 'Clock-out Cancelled', 'msg.cancel_clock_out_done.body': 'Clock-out cancelled.\nReturned to working state.', 'msg.cancel_clock_out_fail.title': 'Cancel Failed', 'msg.cancel_clock_out_fail.body': 'Clock-out record not found.', 'msg.error.title': 'Error', 'msg.error.body': 'Error while {action}:\n{error}', 'msg.input.title': 'Enter Time', 'msg.input_error.date_format': 'Invalid date format.\nCorrect format: YYYY-MM-DD (e.g. 2024-01-15)', 'msg.input_error.overtime_unit': 'Only 30-minute units allowed.\nExamples: 0.5h, 1h, 1.5h', 'msg.overtime_use.title': 'Use Overtime', 'msg.overtime_use_minus.title': 'Use Overtime (Negative)', 'msg.overtime_use.body': 'Use {minutes}m of overtime?\n\nCurrent balance: {balance}m\nNew balance: {new_balance}m', 'msg.overtime_use_minus.body': 'Use {minutes}m of overtime?\n\nCurrent balance: {balance}m\nNew balance: {new_balance}m (negative)\n\n⚠️ Balance will be negative.\nYou must earn overtime later to cover it.', 'msg.overtime_use_done.title': 'Used', 'msg.overtime_use_done.body': '{minutes}m used.', 'msg.overtime_use_fail.title': 'Use Failed', 'msg.overtime_input.body': 'Enter hours to use (0.5h units):\nEx) 0.5, 1, 1.5, 2, 3, 4', 'msg.leave_use.title': 'Use Leave', 'msg.leave_use_date.title': 'Leave Date', 'msg.leave_use_date.body': 'Enter date (YYYY-MM-DD):', 'msg.leave_use_reason.title': 'Leave Reason', 'msg.leave_use_reason.body': 'Enter reason (optional):', 'msg.leave_use_confirm.body': 'Use {type} {days} on {date}?\n\nBalance after: {balance_after} days', 'msg.leave_use_done.title': 'Used', 'msg.leave_use_done.body': '{type} used.', 'msg.leave_use_impossible.title': 'Cannot Use', 'msg.leave_short.title': 'Insufficient Balance', 'msg.leave_short.body': 'Insufficient leave balance.\nCurrent: {balance} days\nRequested: {days} days', 'msg.leave_short_hours.body': 'Insufficient leave balance.\nCurrent: {balance} days ({balance_hours}h)\nRequested: {days} days ({hours}h)', 'msg.settings_updated.title': 'Settings Updated', 'msg.settings_updated.body': 'Settings changes applied.', 'msg.meal_need_clock_in.title': 'Clock-in Required', 'msg.meal_need_clock_in.body': 'Meal times can only be recorded after clocking in.', 'msg.meal_recorded.title': 'Recorded', 'msg.meal_recorded.body': '{meal} {minutes}m recorded.\n({start} ~ {end})', 'msg.meal_actual_input': 'Enter actual {meal} time...', 'msg.workday_boundary.title': 'Workday Boundary Crossed', 'msg.workday_boundary.body': 'Workday boundary ({hour}:00) passed; auto-processed.\n\nPrevious day: clocked out at {before}\nToday: clocked in at {boundary}\n\nWork between midnight and {hour}:00 is counted as previous day overtime.', 'msg.new_workday.title': 'New Workday', 'msg.new_workday.body': 'New workday ({date}).\n\nClock in?', 'msg.clock_in_set.title': 'Set Clock-in', 'msg.clock_in_set.body': 'Clock-in time set.\n\nClock-in: {time}', 'leave.type.annual': 'Annual Leave', 'leave.type.sick': 'Sick Leave', 'leave.type.hourly_leave': 'Hourly Leave', 'leave.use.full_day': '1 day', 'leave.use.half_day': '0.5 day (4h)', 'leave.use.hour_1': '0.125 day (1h)', 'leave.use.min_30': '0.0625 day (30m)', 'leave.use.custom': '{days} days ({hours}h)', 'leave.type.half_am': 'AM Half-day', 'leave.type.half_pm': 'PM Half-day', 'leave.type.time_off': 'Time Off', 'leave.type.half': 'Half-day', 'leave.type.quarter': 'Quarter-day', 'report.leave_used': '🌴 Leave used: {value}', 'report.leave_used_days_hours': '{days}d {hours}h', 'report.leave_used_days': '{days}d', 'report.leave_used_hours': '{hours}h', 'report.leave_detail': ' - {type}: {time}{memo}', 'report.title': '📋 Daily Work Report - {date}', 'report.clock_in': '🕐 Clock-in: {time}', 'report.clock_out': '🕐 Clock-out: {time}', 'report.not_clocked_out': '🕐 Clock-out: not yet', 'report.total_work': '⏱️ Total work: {time}', 'report.break_time': '🚶 Break: {time}', 'report.break_detail': ' - {start} ~ {end} ({duration}m){reason}', 'report.break_in_progress': ' - {start} ~ on break{reason}', 'report.meal_actual': '{label}: {time} (actual)', 'report.meal_in_progress': ' - {start} ~ in progress', 'report.meal_default': '{label}: included ({time})', 'report.memo': '📝 Memo: {memo}', 'report.copied.title': 'Report Copied', 'report.copied.body': 'Daily work report copied to clipboard.\n\n{report}', 'label.lunch': '🍱 Lunch', 'label.lunch_short': 'Lunch', 'label.dinner': '🍽️ Dinner', 'label.dinner_short': 'Dinner', 'label.overtime_balance_zero': '0m (×0)', 'label.leave_balance_zero': 'Balance: 0 days', 'label.today_estimate': 'Today est.: {amount}', 'label.in_progress': 'in progress', 'label.break_returning': 'on break', 'label.meal_actual_suffix': 'actual', 'label.meal_included': 'included', 'report.overtime_occurred': '⏰ Overtime occurred: {time}', 'report.overtime_banked': ' 💰 Banked: {time} (30-min trunc)', 'report.overtime_used': '🕐 Overtime used: {time}', 'report.overtime_used_detail': ' - {time}{reason}', 'update.new_version_title': 'New Version Found', 'update.apply_failed_title': 'Update Failed', 'update.check_title': 'Update Check', 'update.up_to_date': 'You are on the latest version (v{version}).', 'update.network_error': 'Cannot connect to update server.\nPlease check your network.', 'update.no_release': 'No release found in update repository.\n(Private repo or before first release)', 'update.no_asset': 'New version exists but no downloadable main.exe asset.\nContact administrator.', 'update.unknown': 'Unknown response.', 'update.new_found_dev': 'New version {version} available.\n(Auto update not available in development — git pull or build)', 'update.new_found': 'Current: v{current}\nNew: v{new}\n\nRelease notes:\n{notes}\n\nDownload and update now?', 'update.downloading': 'Downloading...', 'update.download_title': 'Update Download', 'update.download_failed': 'Failed to download new version.', 'update.updater_failed': 'updater.exe not found or failed to run.', 'update.restart': 'Program will restart to apply update.', 'settings.title': 'Settings', 'settings.work_pattern': 'Work pattern:', 'settings.preset.standard_8h': 'Standard 8h (Lunch 60min)', 'settings.preset.short_7h30m': 'Reduced 7h 30m (Lunch 30min)', 'settings.preset.short_7h': 'Reduced 7h (Lunch 60min)', 'settings.preset.short_6h': 'Reduced 6h (Lunch 30min)', 'settings.preset.half_4h': 'Half-day 4h (No lunch)', 'settings.preset.custom': 'Custom', 'settings.daily_work': 'Daily work:', 'settings.lunch_default': 'Lunch break:', 'settings.dinner_default': 'Dinner break:', 'settings.auto_apply': 'Auto apply', 'settings.auto_apply_tooltip': 'Auto-apply 4 hours after clock-in', 'settings.suffix_hour': ' h', 'settings.suffix_minute': ' min', 'settings.notif_clock_out': 'Clock-out 30-min reminder', 'settings.notif_lunch': 'Lunch reminder', 'settings.notif_dinner': 'Dinner reminder', 'settings.notif_overtime': 'Overtime bank reminder', 'settings.notif_health': 'Health warning', 'settings.notif_break': 'Break reminder', 'settings.notif_break_tooltip': 'Suggest stretching after long continuous work', 'settings.notif_before': 'Clock-out alert:', 'settings.notif_before_spin_suffix': 'min before', 'settings.notif_before_tooltip': 'Minutes before clock-out to show alert', 'settings.advanced_thresholds': 'Advanced thresholds', 'settings.advanced_thresholds_tooltip': 'Adjust alert thresholds', 'settings.lunch_alert_after': 'Lunch alert (clock-in +):', 'settings.lunch_alert_tooltip': 'Hours after clock-in to remind lunch', 'settings.dinner_alert_after': 'Dinner alert (clock-in +):', 'settings.dinner_alert_tooltip': 'Hours after clock-in to remind dinner', 'settings.overtime_alert_at': 'Overtime balance alert:', 'settings.overtime_alert_tooltip': 'Alert when overtime balance reaches N hours', 'settings.weekly_limit': 'Weekly limit warning:', 'settings.weekly_limit_tooltip': 'Warn when weekly work exceeds N hours', 'settings.consecutive_ot': 'Consecutive OT warning:', 'settings.consecutive_ot_tooltip': 'Health warning after N consecutive OT days', 'settings.break_after': 'Break suggestion:', 'settings.break_after_tooltip': 'Suggest break after N hours', 'settings.time_format': 'Time format:', 'settings.time_format_12': 'AM/PM (5:30 PM)', 'settings.time_format_24': '24-hour (17:30)', 'settings.theme': 'Theme:', 'settings.theme_light': 'Light', 'settings.theme_dark': 'Dark', 'settings.font_scale': 'Font scale:', 'settings.high_contrast': 'High contrast mode', 'settings.high_contrast_tooltip': 'Black background + yellow text', 'settings.language_restart_tooltip': 'Language changes fully apply after restart.', 'settings.current_balance': 'Current balance: calculating...', 'settings.calc_unit': 'Calculation unit:', 'settings.initial_overtime': 'Previous overtime:', 'settings.auto_bank': 'Auto bank', 'settings.auto_bank_tooltip': 'Bank overtime on clock-out', 'settings.initial_overtime_note': '※ Overtime accumulated before using this program (absolute value)', 'settings.goal_group': 'Monthly goals (0=disabled)', 'settings.monthly_ot_cap': 'Monthly OT cap:', 'settings.daily_avg_goal': 'Daily avg goal:', 'settings.goal_note': '※ Check progress in Stats → Monthly tab', 'settings.annual_leave': 'Annual leave:', 'settings.remaining_leave': 'Remaining leave: calculating...', 'settings.used_leave': 'Previously used:', 'settings.used_leave_note': '※ Leave already used before this program (1 day = 8h)', 'settings.registered': 'Registered:', 'settings.add_korean_holidays': 'Korean holidays (auto)', 'settings.add_korean_holidays_tooltip': 'Auto-register lunar holidays + temporary holidays', 'settings.holiday_note': '※ All work on holidays is banked as overtime', 'settings.list': 'List', 'settings.korean_holidays_title': 'Korean holidays added', 'settings.korean_holidays_years_label': '{start} + {end}', 'settings.korean_holidays_years_label_single': '{year}', 'settings.korean_holidays_body': 'Auto-register Korean holidays for {years}?\n\nIncludes:\n• Solar holidays (New Year, Independence, Children\'s, Labor Day, etc.)\n• Lunar holidays (Seollal, Chuseok, Buddha\'s Birthday)\n• Government-designated substitute/temporary holidays\n\n※ Primary: Public Data Portal special-day API\n※ Fallback: \'holidays\' package (offline)', 'settings.korean_holidays_added': '{count} Korean holidays added for {year}.', 'settings.korean_holidays_included': 'Includes:\n', 'settings.package_not_installed': 'Package not installed', 'settings.package_fallback_body': '\'holidays\' package not installed; only fixed holidays were added.\n\n{hint} pip install holidays', 'settings.package_install_hint': 'For lunar/temp holidays auto-register:\n', 'settings.add_done': 'Added', 'settings.holiday_added': 'Holiday added.\n{date}: {name}', 'settings.holiday_add_title': 'Add Holiday', 'settings.holiday_date_prompt': 'Enter holiday date (YYYY-MM-DD):', 'settings.holiday_name_prompt': 'Enter holiday name:', 'settings.holiday_list_title': 'Holiday List', 'settings.holiday_list_header': '=== Holidays for {year} ===\n\n', 'settings.holiday_list_item': '• {date} ({weekday}): {name}{recurring}', 'settings.holiday_total': 'Total: {count}', 'settings.holiday_delete_confirm': '\n\nDelete a holiday?', 'settings.holiday_delete_title': 'Delete Holiday', 'settings.holiday_delete_prompt': 'Select holiday to delete:', 'settings.delete_done': 'Deleted', 'settings.holiday_deleted': '{item} deleted.', 'settings.export_csv': 'CSV Export', 'settings.export_work': 'Work records', 'settings.export_overtime': 'Overtime', 'settings.export_monthly': 'Monthly summary', 'settings.import_csv': 'CSV Import', 'settings.import_tooltip': 'Header format: date,clock_in,clock_out,lunch_minutes,memo', 'settings.import_format': 'Standard format (header: date,clock_in,clock_out,lunch_minutes,memo)', 'settings.db_path_label': 'DB path:', 'settings.change': 'Change...', 'settings.db_path_tooltip': 'Change to cloud folder path. Restart required.', 'settings.auto_break_lock_tooltip': 'Auto start/end break on PC lock/unlock.', 'settings.gitea_feedback_label': 'Gitea feedback:', 'settings.gitea_token_placeholder': 'PAT (issue write permission, optional)', 'settings.clock_in_unlock_tooltip': 'For users who do not shut down PC — record screen unlock as clock-in.', 'settings.auto_break_lock': 'Auto break on screen lock', 'settings.gitea_feedback_tooltip': "Enable 'Report on Gitea' button on errors", 'settings.clock_in_unlock': 'Use first unlock as clock-in', 'settings.version': 'Version: v{version}', 'settings.check_update': 'Check update (F5)', 'settings.select_db': 'Select database file', 'settings.db_path_saved': 'New path saved:\n{path}\n\nCopy current database.db to new location and restart.', 'settings.parse_failed': 'Parse failed', 'settings.empty_file': 'Empty file', 'settings.empty_file_body': 'No valid rows.', 'settings.conflict_title': 'Conflict handling', 'settings.conflict_body': 'How to handle conflicts with existing dates?\n', 'settings.conflict_body_detailed': 'How to handle conflicts with existing dates?\nYes = Overwrite\nNo = Skip\nCancel = Cancel', 'settings.import_rows_intro': '{count} rows will be imported.\n\n', 'settings.import_failed': 'Import failed', 'settings.import_result': 'Import result:\n• Added: {added}\n• Updated: {updated}\n• Skipped: {skipped}', 'settings.import_complete': 'Complete', 'settings.save_done': 'Saved', 'settings.save_done_body': 'Settings saved.', 'settings.restart_title': 'Restart', 'settings.restart_body': 'Main screen applies immediately. Some dialogs require restart.\nRestart now?\n\n', 'settings.initial_overtime_title': 'Set previous overtime', 'settings.initial_overtime_body': 'Current: {old_hours}h {old_mins}m\nNew: {hours}h {mins}m\n\nChange previous overtime?', 'settings.initial_overtime_done': 'Set', 'settings.initial_overtime_done_body': 'Previous overtime set to {hours}h {mins}m.', 'settings.initial_overtime_error': 'Error setting previous overtime:\n{error}', 'settings.current_overtime_balance': 'Current balance: {hours}h {minutes}m ({balance}m)', 'settings.remaining_leave_fmt': 'Remaining: {remaining:.1f} days ({used} of {total} used)', 'settings.holiday_count': '{count} ({year})', 'settings.error': 'Error', 'settings.export_no_records': 'No records to export.', 'settings.save_work_title': 'Save work records', 'settings.export_done': 'Export complete', 'settings.work_exported': 'Work records saved.\n{path}', 'settings.save_ot_title': 'Save overtime records', 'settings.ot_exported': 'Overtime records saved.\n{path}', 'settings.save_monthly_title': 'Save monthly summary', 'settings.monthly_exported': 'Monthly summary saved.\n{path}', 'settings.export_failed': 'Export failed', 'settings.export_error': 'Error: {error}', 'settings.initial_leave_title': 'Set previous leave', 'settings.initial_leave_body': 'Current: {old_hours}h {old_mins}m\nNew: {hours}h {mins}m\n\nChange previous leave?', 'settings.initial_leave_done': 'Saved', 'settings.initial_leave_done_body': 'Previous leave set to {hours}h {mins}m.', 'date_format.full': '{year}-{month}-{day} ({weekday})', 'achieve.cat_ambition': 'Ambition', 'achieve.cat_balance': 'Work-Life Balance', 'achieve.cat_break_use': 'Break', 'achieve.cat_health': 'Health', 'achieve.cat_korea': 'Korean Culture', 'achieve.cat_leave': 'Leave', 'achieve.cat_meal': 'Meal', 'achieve.cat_meta': 'Meta', 'achieve.cat_milestone': 'Milestone', 'achieve.cat_ot_bank': 'Overtime Bank', 'achieve.cat_ot_use': 'Overtime Use', 'achieve.cat_pattern': 'Pattern', 'achieve.cat_punctual': 'Punctual', 'achieve.cat_season': 'Season', 'achieve.cat_secret': 'Secret', 'achieve.cat_settings': 'Settings', 'achieve.cat_special_day': 'Special Day', 'achieve.cat_stats': 'Stats', 'achieve.cat_streak': 'Streak', 'achieve.cat_time_slot': 'Time Slot', 'achieve.completion_rate': 'Completion', 'achieve.earned_date': ' ✓ Earned {date} ', 'achieve.empty': '(None yet)', 'achieve.secret_locked': '🔒 Revealed when achieved', 'achieve.tab_all': '🌐 All · {count}', 'achieve.tab_completed': '✓ Completed · {count}', 'achieve.tab_in_progress': '⚡ In Progress · {count}', 'achieve.tab_secret': '🌑 Secret · {earned}/{total}', 'achieve.tier_bronze': 'Bronze', 'achieve.tier_gold': 'Gold', 'achieve.tier_legend': 'Legend', 'achieve.tier_platinum': 'Platinum', 'achieve.tier_silver': 'Silver', 'achieve.title': 'Achievements', 'cal.add_done_body': 'Record added for {date}.', 'cal.add_done_title': 'Added', 'cal.add_error_body': 'Failed to add record: {error}', 'cal.add_error_title': 'Error', 'cal.btn_minus_30': '-30m', 'cal.btn_plus_30': '+30m', 'cal.check_dinner_1h': 'Dinner (1h)', 'cal.check_lunch_1h': 'Lunch (1h)', 'cal.context_add': 'Add record {date}', 'cal.context_delete': 'Delete {date}', 'cal.context_edit': 'Edit {date}', 'cal.delete_confirm_body': 'Really delete {date} record?\n(Overtime bank entries will also be deleted)', 'cal.delete_confirm_title': 'Confirm Delete', 'cal.delete_done_body': '{date} record deleted.', 'cal.delete_done_title': 'Deleted', 'cal.delete_record': 'Delete Record', 'cal.delete_selected_body': 'Delete clock-in record for {date}?\n\n※ Related overtime bank/usage entries will also be deleted.\n※ This cannot be undone.', 'cal.delete_selected_title': 'Delete Clock-in Record', 'cal.detail_clock_in': 'Clock-in: {time}', 'cal.detail_clock_out': 'Clock-out: {time}', 'cal.detail_clock_out_none': 'Clock-out: not recorded', 'cal.detail_date_fmt': '{year}-{month}-{day}', 'cal.detail_dinner_unused': 'Dinner: not used', 'cal.detail_dinner_used': 'Dinner: used', 'cal.detail_group_title': 'Selected Date Info', 'cal.detail_lunch_unused': 'Lunch: not used', 'cal.detail_lunch_used': 'Lunch: used', 'cal.detail_memo': 'Memo: {memo}', 'cal.detail_overtime_earned': '🔥 Overtime earned: {hours}h {minutes}m', 'cal.detail_total_hours': 'Total work: {hours:.1f}h', 'cal.dialog_title': 'Monthly Work Records', 'cal.edit_dialog_subtitle': 'Edit clock-in/out for {date}', 'cal.edit_dialog_title': 'Edit Clock-in/out Time', 'cal.edit_done_body': 'Clock-in/out updated for {date}.\n\nClock-in: {clock_in}\nClock-out: {clock_out}\nLunch: {lunch}\nDinner: {dinner}\nBreak: {break_minutes}m\nTotal work: {total_hours:.1f}h\nOvertime: {overtime_earned}m banked', 'cal.edit_done_title': 'Updated', 'cal.edit_error_body': 'Error while updating:\n{error}', 'cal.edit_error_title': 'Error', 'cal.edit_note': '※ Overtime will be recalculated.', 'cal.edit_time': 'Edit Time', 'cal.label_clock_in': 'Clock-in:', 'cal.label_clock_out': 'Clock-out:', 'cal.legend_leave': 'Leave', 'cal.legend_none': 'None', 'cal.legend_normal': 'Normal', 'cal.legend_overtime': 'Overtime', 'cal.memo_group': 'Memo', 'cal.memo_placeholder': 'Overtime reason, notes...', 'cal.no_record': 'No record.', 'cal.save_memo': 'Save Memo', 'cal.save_memo_body': 'Memo saved for {date}.', 'cal.save_memo_title': 'Save Memo', 'cal.time_error_body': 'Clock-out must be later than clock-in.', 'cal.time_error_title': 'Time Error', 'clock_in_dialog.cancelled': 'Cancelled', 'clock_in_dialog.selected': 'Selected time: {time}', 'field.avg_daily_value': '{hours:.1f}h', 'field.overtime_value': '{hours}h {minutes}m', 'field.total_work_value': '{hours:.1f}h ({days} days)', 'goal.avg_daily': 'Daily Avg:', 'goal.overtime': 'Overtime:', 'goal.title': 'Monthly Goals', 'help.onboarding_button': 'Re-run Onboarding', 'leave_cal.detail_label': '{type} {days} days', 'leave_cal.detail_memo': '{type} {days} days ({memo})', 'leave_cal.detail_no_record': '{date} — No leave usage', 'leave_cal.header': 'Remaining {balance:.2f}d / Total {total:.0f}d (Used {used:.2f}d)', 'leave_cal.legend_full': 'Full (1.0)', 'leave_cal.legend_full_planned': 'Full+Planned', 'leave_cal.legend_half': 'Half (0.5)', 'leave_cal.legend_planned': 'Planned', 'leave_cal.legend_quarter': 'Quarter (0.25)', 'leave_cal.title': 'Leave Calendar', 'meal.dialog_title': 'Enter {meal} Time', 'meal.error_after_clock_out': 'After clock-out ({time})', 'meal.error_before_clock_in': 'Before clock-in ({time})', 'meal.error_start_after_end': 'Start is later than end', 'meal.error_too_long': 'Meal time exceeds 8 hours', 'meal.info_clock_in_limit': '\nMust be after clock-in ({time}).', 'meal.info_text': 'Enter {meal} start and end times.\nThis records the exact time instead of the default {minutes} minutes.', 'meal.input_error_title': 'Input Error', 'meal.label_end': 'End:', 'meal.label_start': 'Start:', 'meal.preview_total': 'Total {minutes} min', 'mini.close': 'Close mini widget', 'mini.open_main': 'Open main window', 'onboarding.detection_boot': 'PC boot time (default — if you shut down daily)', 'onboarding.detection_info': '\nRecommended for users who leave their PC running.', 'onboarding.detection_manual': 'Manual only (no auto detection)', 'onboarding.detection_subtitle': 'Choose how the app detects your clock-in time.', 'onboarding.detection_title': 'Clock-in Detection', 'onboarding.detection_unlock': 'First screen unlock (if you leave PC on)', 'onboarding.discord_enable': 'Use Discord webhook notifications', 'onboarding.discord_failed': 'Failed', 'onboarding.discord_failed_body': 'Send failed. Please check the URL.', 'onboarding.discord_guide': 'Setup:\n1. In Discord, right-click channel → Integrations → Webhooks\n2. New Webhook → Copy URL\n3. Paste it above', 'onboarding.discord_subtitle': 'Enter a webhook URL to receive clock-in/out and break reminders on Discord. (Mobile push)', 'onboarding.discord_success': 'Success', 'onboarding.discord_success_body': 'Check the Discord channel for the test message.', 'onboarding.discord_test': 'Send test message', 'onboarding.discord_title': 'Discord Notifications (Optional)', 'onboarding.discord_url_invalid_body': 'Not a valid Discord webhook URL.\nExample: https://discord.com/api/webhooks/{ID}/{TOKEN}', 'onboarding.discord_url_invalid_title': 'Invalid URL', 'onboarding.discord_url_placeholder': 'https://discord.com/api/webhooks/...', 'onboarding.discord_url_required_body': 'Please enter a webhook URL first.', 'onboarding.discord_url_required_title': 'URL Required', 'onboarding.finish_msg': 'You can change these settings anytime in [Settings].\nTo re-run onboarding, use [Help → Re-run Onboarding].\n\nShortcuts:\n • Ctrl+O — Toggle clock-in/out\n • F1 — Help\n • F5 — Check update\n • Ctrl+, — Settings', 'onboarding.finish_subtitle': 'Your clock-in will now be tracked automatically.', 'onboarding.finish_title': 'Ready!', 'onboarding.hourly_wage': 'Hourly wage:', 'onboarding.input_error_title': 'Input Error', 'onboarding.leave_group': 'Annual Leave', 'onboarding.leave_salary_subtitle': 'Enter annual leave days and optional salary info.', 'onboarding.leave_salary_title': 'Leave + Salary (Optional)', 'onboarding.my_leave': 'My leave:', 'onboarding.overtime_rate': 'Overtime rate:', 'onboarding.rate_1_5x': '1.5x (Korean labor law default)', 'onboarding.rate_1x': '1.0x (no premium)', 'onboarding.rate_2x': '2.0x (night/holiday premium)', 'onboarding.salary_enabled': 'Enable salary estimate', 'onboarding.salary_group': 'Salary Estimate (Optional — disable if flat rate)', 'onboarding.wage_suffix': ' KRW/h', 'onboarding.welcome_intro': 'This app:\n• Auto-detects clock-in from boot/unlock\n• Banks overtime in 30-min units\n• Tracks annual/half-day leave and breaks\n• Counts down to clock-out every second\n\nPress [Next] to start.', 'onboarding.welcome_subtitle': "First time using Clock-out Time Calculator? Let's set it up in 5 steps.", 'onboarding.welcome_title': 'Welcome!', 'onboarding.window_title': 'Clock-out Calculator — Setup', 'onboarding.work_min_too_small': 'Daily work must be at least 30 minutes.', 'onboarding.work_pattern_subtitle': 'Choose your daily work hours. You can change this later in Settings.', 'onboarding.work_pattern_title': 'Work Pattern', 'past_record.check_clock_out': 'Enter', 'past_record.check_dinner': 'Include dinner', 'past_record.check_lunch': 'Include lunch', 'past_record.dialog_title': 'Add Record — {date}', 'past_record.info': 'Enter work record for {date}.', 'past_record.input_error_body': 'Clock-out must be later than clock-in.', 'past_record.input_error_title': 'Input Error', 'past_record.label_clock_in': 'Clock-in:', 'past_record.label_clock_out': 'Clock-out:', 'past_record.label_memo': 'Memo (optional):', 'past_record.memo_placeholder': 'e.g. remote work / business trip / leave', 'recurring.add_done_body': 'Recurring pattern registered.\n{pattern}', 'recurring.add_done_title': 'Added', 'recurring.add_group': 'Add New Pattern', 'recurring.biweekly': 'Biweekly', 'recurring.btn_add': 'Add', 'recurring.btn_delete_selected': 'Delete Selected', 'recurring.day_suffix': '', 'recurring.deduction_full': '1.0 day (full)', 'recurring.deduction_half': '0.5 day (half)', 'recurring.deduction_quarter': '0.25 day (quarter)', 'recurring.delete_confirm_body': 'Delete this recurring pattern?\n\n{item}', 'recurring.delete_confirm_title': 'Confirm Delete', 'recurring.input_error_title': 'Input Error', 'recurring.input_error_weekday': 'Select at least one weekday.', 'recurring.label_cycle': 'Cycle:', 'recurring.label_deduction': 'Deduct:', 'recurring.label_end': 'End:', 'recurring.label_memo': 'Memo:', 'recurring.label_monthly_day': 'Day:', 'recurring.label_start': 'Start:', 'recurring.label_weekday': 'Weekday:', 'recurring.list_group': 'Registered Recurring Patterns', 'recurring.memo_placeholder': 'e.g. childcare reduced hours', 'recurring.monthly': 'Monthly Nth day', 'recurring.no_end': 'No end (indefinite)', 'recurring.title': 'Recurring Leave Management', 'recurring.pattern_weekly': '{prefix} {weekdays}', 'recurring.pattern_monthly': 'Monthly {day}', 'recurring.weekly': 'Weekly', 'schedule.btn_add_leave': 'Register Leave', 'schedule.btn_recurring': 'Manage Recurring Patterns', 'schedule.delete': 'Delete', 'schedule.delete_leave_confirm_body': 'Delete this leave record? (Balance will be restored automatically.)', 'schedule.delete_leave_confirm_title': 'Confirm Delete', 'schedule.delete_recurring_confirm_body': 'Delete this recurring pattern? (Removes all future instances)', 'schedule.delete_recurring_confirm_title': 'Confirm Delete', 'schedule.detail_placeholder': 'Select a date', 'schedule.header': 'Monthly Schedule — Holidays + Leave + Recurring Patterns', 'schedule.holiday': 'Holiday: {name}', 'schedule.leave_label': '{type} {days} days', 'schedule.recurring_item': '{pattern} · {days}d ({type})', 'schedule.legend_half': 'Half/Quarter Day', 'schedule.legend_holiday': 'Holiday', 'schedule.legend_leave_planned': 'Leave Planned', 'schedule.legend_leave_used': 'Leave Used', 'schedule.legend_recurring': 'Recurring Pattern', 'schedule.no_events': 'No events', 'schedule.title': 'Schedule', 'schedule.weekend': 'Weekend ({weekday})', 'schedule.weekday_suffix': '', 'today.detail_break': 'Break {minutes}m', 'today.detail_dinner': 'Dinner {minutes}m', 'today.detail_lunch': 'Lunch {minutes}m', 'today.detail_overtime': 'Overtime {actual}m → banked {earned}m', 'today.title': "Today's Summary", 'today.total_work': 'Total work: {hours}h {minutes}m', 'view.leave.btn_schedule': 'Schedule', 'view.leave.duplicate_register_body': '{date} already has {existing_days:.2f} days registered.\nAdding {days:.2f} more days would exceed 1 day.', 'view.leave.duplicate_register_title': 'Duplicate Exceeds Limit', 'view.leave.holiday_register_forbidden_body': '{date} is already a holiday ({name}).\nNo need to deduct leave.', 'view.leave.holiday_register_forbidden_title': 'Cannot Register on Holiday', 'view.leave.schedule_tooltip': 'Unified view of holidays + leave + recurring patterns', 'view.leave.used_1day': '1 day', 'view.leave.used_half_day': '0.5 day (4h)', 'view.leave.used_hours_fmt': '{days} days ({hours}h)', 'view.leave.used_days_fmt': '{days} days', 'view.leave.weekend_register_forbidden_body': 'Leave cannot be registered on weekends. (Already non-working day)', 'view.leave.weekend_register_forbidden_title': 'Cannot Register on Weekend', # === Achievements === 'achieve.streak_first.name': 'First Step', 'achieve.streak_first.desc': 'First clock-in record.', 'achieve.streak_3.name': 'Taking Root', 'achieve.streak_3.desc': '3 consecutive business days clocked in.', 'achieve.streak_5.name': 'First Week Clear', 'achieve.streak_5.desc': '5 consecutive business days clocked in.', 'achieve.streak_7_cal.name': '7 Days Straight', 'achieve.streak_7_cal.desc': '7 consecutive calendar days clocked in, weekends included.', 'achieve.streak_10.name': 'Two Weeks Running', 'achieve.streak_10.desc': '10 consecutive business days clocked in.', 'achieve.streak_22.name': 'Monthly Perfect Attendance', 'achieve.streak_22.desc': '100% business-day attendance for one month (22 days).', 'achieve.streak_50.name': '50-Day Streak', 'achieve.streak_50.desc': '50 consecutive business days clocked in.', 'achieve.streak_100.name': '100-Day Streak', 'achieve.streak_100.desc': '100 consecutive business days clocked in.', 'achieve.streak_quarter.name': 'Quarter Clear', 'achieve.streak_quarter.desc': 'About 65 business days (3 months).', 'achieve.streak_half_year.name': 'Half-Year Marathon', 'achieve.streak_half_year.desc': 'About 130 business days (6 months).', 'achieve.streak_year.name': 'Full-Year Season', 'achieve.streak_year.desc': 'About 260 business days (1 year).', 'achieve.streak_200.name': 'Science', 'achieve.streak_200.desc': '200 consecutive business days clocked in.', 'achieve.streak_365_cal.name': 'Immortal', 'achieve.streak_365_cal.desc': '365 consecutive calendar days clocked in.', 'achieve.streak_resilience.name': 'Bounce Back', 'achieve.streak_resilience.desc': 'Clocked in the day immediately after absence (auto: restart after calendar streak breaks).', 'achieve.streak_total_100.name': '100 Total Clock-ins', 'achieve.streak_total_100.desc': '100 total clock-ins.', 'achieve.streak_total_500.name': '500 Total Clock-ins', 'achieve.streak_total_500.desc': '500 total clock-ins.', 'achieve.streak_total_1000.name': '1000 Total Clock-ins', 'achieve.streak_total_1000.desc': '1000 total clock-ins.', 'achieve.punc_before_8_1.name': 'Early Bird', 'achieve.punc_before_8_1.desc': 'Clocked in before 08:00 once.', 'achieve.punc_before_8_10.name': 'Early Bird Flock', 'achieve.punc_before_8_10.desc': 'Clocked in before 08:00 10 times.', 'achieve.punc_before_8_30.name': 'Early to Bed, Early to Rise', 'achieve.punc_before_8_30.desc': 'Clocked in before 08:00 30 times.', 'achieve.punc_before_6_1.name': 'No Dawn Sleep', 'achieve.punc_before_6_1.desc': 'Clocked in before 06:00 once.', 'achieve.punc_before_6_10.name': 'Cutter of Darkness', 'achieve.punc_before_6_10.desc': 'Clocked in before 06:00 10 times.', 'achieve.punc_before_5.name': 'Dawn Champion', 'achieve.punc_before_5.desc': 'Clocked in before 05:00.', 'achieve.punc_at_9.name': 'Exactly Nine', 'achieve.punc_at_9.desc': 'Clocked in exactly at 09:00 (±1 min) once.', 'achieve.punc_at_9_5.name': 'Perfect Nine', 'achieve.punc_at_9_5.desc': 'Clocked in exactly at 09:00 (±1 min) 5 times.', 'achieve.punc_late_5min.name': '5 Minutes Late', 'achieve.punc_late_5min.desc': 'Clocked in at 09:00–09:05 once (self-deprecating).', 'achieve.punc_at_909.name': 'Fateful Moment', 'achieve.punc_at_909.desc': 'Clocked in at 09:09 (secret).', 'achieve.bal_first_punct.name': 'First On-Time Leave', 'achieve.bal_first_punct.desc': 'First on-time clock-out.', 'achieve.bal_punct_10.name': 'Clock-outer', 'achieve.bal_punct_10.desc': 'On-time clock-out 10 times.', 'achieve.bal_punct_30.name': 'On-Time Champ', 'achieve.bal_punct_30.desc': 'On-time clock-out 30 times.', 'achieve.bal_punct_100.name': 'True Freedom', 'achieve.bal_punct_100.desc': 'On-time clock-out 100 times.', 'achieve.bal_punct_300.name': 'Work-Life Master', 'achieve.bal_punct_300.desc': 'On-time clock-out 300 times.', 'achieve.ot_first_30m.name': 'First 30 Minutes', 'achieve.ot_first_30m.desc': 'First overtime banked.', 'achieve.ot_total_60m.name': '1-Hour Savings', 'achieve.ot_total_60m.desc': '1 hour banked in total.', 'achieve.ot_total_5h.name': '5 Hours Banked', 'achieve.ot_total_5h.desc': '5 hours banked in total.', 'achieve.ot_total_10h.name': '10 Hours Banked', 'achieve.ot_total_10h.desc': '10 hours banked in total.', 'achieve.ot_total_25h.name': '25 Hours Banked', 'achieve.ot_total_25h.desc': '25 hours banked in total.', 'achieve.ot_total_50h.name': '50 Hours Banked', 'achieve.ot_total_50h.desc': '50 hours banked in total.', 'achieve.ot_total_100h.name': 'Marathoner', 'achieve.ot_total_100h.desc': '100 hours banked in total (concerned message).', 'achieve.ot_total_200h.name': 'Workaholic Warning', 'achieve.ot_total_200h.desc': '200 hours banked in total (warning).', 'achieve.ot_total_300h.name': 'Danger Signal', 'achieve.ot_total_300h.desc': '300 hours banked in total (strong warning).', 'achieve.ot_total_500h.name': 'ER Regular', 'achieve.ot_total_500h.desc': '500 hours banked in total (self-deprecating).', 'achieve.use_first.name': 'First Break', 'achieve.use_first.desc': 'First time using banked time.', 'achieve.use_total_5h.name': 'Using the Gift', 'achieve.use_total_5h.desc': '5 hours used in total.', 'achieve.use_total_25h.name': 'Value of Rest', 'achieve.use_total_25h.desc': '25 hours used in total.', 'achieve.use_total_50h.name': 'Recovery Master', 'achieve.use_total_50h.desc': '50 hours used in total.', 'achieve.use_total_100h.name': 'Massage', 'achieve.use_total_100h.desc': '100 hours used in total.', 'achieve.leave_first.name': 'First Leave', 'achieve.leave_first.desc': 'First leave usage.', 'achieve.leave_half.name': 'First Half-Day', 'achieve.leave_half.desc': '0.5-day leave used.', 'achieve.leave_quarter.name': 'Hourly Leave', 'achieve.leave_quarter.desc': '0.25-day leave used.', 'achieve.leave_streak_3.name': 'Mini Vacation', 'achieve.leave_streak_3.desc': '3 consecutive days of leave.', 'achieve.leave_streak_5.name': 'Serious Vacation', 'achieve.leave_streak_5.desc': '5 consecutive days of leave.', 'achieve.leave_streak_7.name': 'Long-Distance Vacation', 'achieve.leave_streak_7.desc': '7 or more consecutive days of leave.', 'achieve.leave_total_10.name': 'Leave x10', 'achieve.leave_total_10.desc': '10 leave records.', 'achieve.leave_sick.name': 'Sick Leave', 'achieve.leave_sick.desc': 'Sick-type leave used.', 'achieve.meal_lunch_first.name': 'First Lunch Entry', 'achieve.meal_lunch_first.desc': 'First lunch toggle.', 'achieve.meal_lunch_30.name': 'Lunch Master', 'achieve.meal_lunch_30.desc': 'Lunch toggled 30 times.', 'achieve.meal_lunch_100.name': 'Lunch Champ', 'achieve.meal_lunch_100.desc': 'Lunch toggled 100 times.', 'achieve.meal_dinner_first.name': 'First Dinner Entry', 'achieve.meal_dinner_first.desc': 'First dinner toggle.', 'achieve.meal_dinner_10.name': 'Dinner Regular', 'achieve.meal_dinner_10.desc': 'Dinner toggled 10 times (warning).', 'achieve.meal_dinner_30.name': 'Late-Night Regular', 'achieve.meal_dinner_30.desc': 'Dinner toggled 30 times (warning).', 'achieve.meal_lunch_actual.name': 'Measured Lunch', 'achieve.meal_lunch_actual.desc': 'Entered actual lunch time.', 'achieve.meal_dinner_actual.name': 'Measured Dinner', 'achieve.meal_dinner_actual.desc': 'Entered actual dinner time.', 'achieve.break_first.name': 'First Break', 'achieve.break_first.desc': 'First break started.', 'achieve.break_10.name': 'Break Champ', 'achieve.break_10.desc': '10 breaks.', 'achieve.break_50.name': 'Walker', 'achieve.break_50.desc': '50 breaks.', 'achieve.slot_in_06.name': '06:00 Clock-in', 'achieve.slot_in_06.desc': 'Clocked in during 06:00–06:59 once.', 'achieve.slot_in_07.name': '07:00 Clock-in', 'achieve.slot_in_07.desc': 'Clocked in during 07:00–07:59 once.', 'achieve.slot_in_08.name': '08:00 Clock-in', 'achieve.slot_in_08.desc': 'Clocked in during 08:00–08:59 once.', 'achieve.slot_in_10.name': '10:00 Clock-in', 'achieve.slot_in_10.desc': 'Clocked in during 10:00–10:59 (late / flexible).', 'achieve.slot_in_11.name': '11:00 Clock-in', 'achieve.slot_in_11.desc': 'Clocked in during 11:00–11:59 (self-deprecating).', 'achieve.slot_out_19.name': '19:00 Clock-out', 'achieve.slot_out_19.desc': 'Clocked out during 19:00–19:59 10 times (warning).', 'achieve.slot_out_20.name': '20:00 Clock-out', 'achieve.slot_out_20.desc': 'Clocked out during 20:00–20:59 10 times (warning).', 'achieve.slot_out_21.name': '21:00 Clock-out', 'achieve.slot_out_21.desc': 'Clocked out during 21:00–21:59 5 times (warning).', 'achieve.slot_out_22.name': '22:00 Clock-out', 'achieve.slot_out_22.desc': 'Clocked out during 22:00–22:59 once (warning).', 'achieve.slot_out_23.name': '23:00 Clock-out', 'achieve.slot_out_23.desc': 'Clocked out during 23:00–23:59 once (warning).', 'achieve.slot_midnight.name': 'Midnight Clock-out', 'achieve.slot_midnight.desc': 'Clocked out after midnight (warning).', 'achieve.slot_midnight_3.name': 'Owl Trio', 'achieve.slot_midnight_3.desc': 'Clocked out after midnight 3 times (warning).', 'achieve.weekend_1.name': 'Weekend Work Once', 'achieve.weekend_1.desc': 'Clocked in on a Saturday/Sunday once.', 'achieve.weekend_5.name': 'Weekend Worker', 'achieve.weekend_5.desc': 'Clocked in on weekends 5 times (warning).', 'achieve.weekend_20.name': 'True Workaholic', 'achieve.weekend_20.desc': 'Clocked in on weekends 20 times (strong self-deprecating).', 'achieve.holiday_1.name': 'Holiday Work', 'achieve.holiday_1.desc': 'Clocked in on a Korean public holiday once.', 'achieve.holiday_5.name': 'Holiday Workaholic', 'achieve.holiday_5.desc': 'Clocked in on Korean public holidays 5 times (warning).', 'achieve.day_christmas.name': 'Christmas at Work', 'achieve.day_christmas.desc': 'Clocked in on 12/25 (self-deprecating).', 'achieve.day_newyear.name': 'New Year at Work', 'achieve.day_newyear.desc': 'Clocked in on 1/1 (self-deprecating).', 'achieve.day_liberation.name': 'Liberation Day at Work', 'achieve.day_liberation.desc': 'Clocked in on 8/15 (Liberation Day).', 'achieve.day_children.name': "Children's Day at Work", 'achieve.day_children.desc': "Clocked in on 5/5 (Children's Day, self-deprecating).", 'achieve.day_hangul.name': 'Hangeul Day at Work', 'achieve.day_hangul.desc': 'Clocked in on 10/9 (Hangeul Day).', 'achieve.day_valentine.name': 'Valentine at Work', 'achieve.day_valentine.desc': 'Clocked in on 2/14.', 'achieve.day_white.name': 'White Day at Work', 'achieve.day_white.desc': 'Clocked in on 3/14.', 'achieve.day_pepero.name': 'Pepero Day', 'achieve.day_pepero.desc': 'Clocked in on 11/11 (Pepero Day).', 'achieve.day_halloween.name': 'Halloween at Work', 'achieve.day_halloween.desc': 'Clocked in on 10/31.', 'achieve.day_aprilfools.name': 'April Fools at Work', 'achieve.day_aprilfools.desc': 'Clocked in on 4/1.', 'achieve.day_77.name': 'Chilseok (July 7)', 'achieve.day_77.desc': 'Clocked in on 7/7 (Chilseok).', 'achieve.day_dongji.name': 'Dongji at Work', 'achieve.day_dongji.desc': 'Clocked in on 12/22 (Dongji, winter solstice).', 'achieve.day_parents.name': 'Parents Day On-Time Leave', 'achieve.day_parents.desc': 'On-time clock-out on 5/8 (Parents Day).', 'achieve.day_teacher.name': "Teachers' Day On-Time Leave", 'achieve.day_teacher.desc': "On-time clock-out on 5/15 (Teachers' Day).", 'achieve.day_xmas_eve.name': 'Christmas Eve On-Time Leave', 'achieve.day_xmas_eve.desc': 'On-time clock-out on 12/24.', 'achieve.day_earth.name': 'Earth Day', 'achieve.day_earth.desc': 'Clocked in on 4/22 (secret).', 'achieve.season_jan.name': 'January Settled', 'achieve.season_jan.desc': 'Clocked in during January.', 'achieve.season_feb.name': 'February Perfect', 'achieve.season_feb.desc': 'Attended all business days in February.', 'achieve.season_mar.name': 'Spring Greeting', 'achieve.season_mar.desc': 'First clock-in of March.', 'achieve.season_apr.name': 'April Settled', 'achieve.season_apr.desc': 'Attended all business days in April.', 'achieve.season_may.name': 'May Perfect', 'achieve.season_may.desc': 'Attended all business days in May.', 'achieve.season_jun.name': 'Start of Summer', 'achieve.season_jun.desc': 'First clock-in of June.', 'achieve.season_jul.name': 'July Settled', 'achieve.season_jul.desc': 'Attended all business days in July.', 'achieve.season_aug.name': 'August Perfect', 'achieve.season_aug.desc': 'Attended all business days in August.', 'achieve.season_sep.name': 'Start of Autumn', 'achieve.season_sep.desc': 'First clock-in of September.', 'achieve.season_oct.name': 'October Settled', 'achieve.season_oct.desc': 'Attended all business days in October.', 'achieve.season_nov.name': 'November Maple', 'achieve.season_nov.desc': 'Attended all business days in November.', 'achieve.season_dec.name': 'Start of Winter', 'achieve.season_dec.desc': 'First clock-in of December.', 'achieve.mile_first.name': 'Hello, World!', 'achieve.mile_first.desc': 'First app run.', 'achieve.mile_7days.name': 'One Week User', 'achieve.mile_7days.desc': 'Used the app for 7 days.', 'achieve.mile_30days.name': 'One Month User', 'achieve.mile_30days.desc': 'Used the app for 30 days.', 'achieve.mile_365days.name': '1st Anniversary', 'achieve.mile_365days.desc': 'Used the app for 365 days.', 'achieve.mile_730days.name': '2nd Anniversary', 'achieve.mile_730days.desc': 'Used the app for 730 days.', 'achieve.mile_1095days.name': '3rd Anniversary', 'achieve.mile_1095days.desc': 'Used the app for 3 years.', 'achieve.mile_5years.name': '5-Year User', 'achieve.mile_5years.desc': 'Used the app for 5 years.', 'achieve.mile_10years.name': '10-Year User', 'achieve.mile_10years.desc': 'Used the app for 10 years.', 'achieve.stat_weekly_10.name': 'Weekly Stats Viewer', 'achieve.stat_weekly_10.desc': 'Viewed the Weekly tab 10 times.', 'achieve.stat_monthly_10.name': 'Monthly Stats Viewer', 'achieve.stat_monthly_10.desc': 'Viewed the Monthly tab 10 times.', 'achieve.stat_pattern_10.name': 'Pattern Analyst', 'achieve.stat_pattern_10.desc': 'Viewed the Pattern tab 10 times.', 'achieve.stat_calendar_30.name': 'Calendar Champ', 'achieve.stat_calendar_30.desc': 'Viewed the Calendar 30 times.', 'achieve.stat_report_first.name': 'First Daily Report', 'achieve.stat_report_first.desc': 'Generated a daily report once.', 'achieve.stat_report_30.name': 'Report Champ', 'achieve.stat_report_30.desc': 'Generated daily reports 30 times.', 'achieve.stat_chart_hover.name': 'Chart Hover Discovery', 'achieve.stat_chart_hover.desc': 'Discovered chart hover for the first time.', 'achieve.stat_achievements_open.name': 'Achievement Museum', 'achieve.stat_achievements_open.desc': 'Opened the Achievements view 50 times.', 'achieve.secret_palindrome.name': 'Palindrome Time', 'achieve.secret_palindrome.desc': 'Clock-in time is a palindrome.', 'achieve.secret_jackpot.name': 'Jackpot Time', 'achieve.secret_jackpot.desc': 'Clock-in time has all identical digits.', 'achieve.secret_fri13.name': 'Friday the 13th', 'achieve.secret_fri13.desc': 'Clocked in on Friday the 13th.', 'achieve.secret_777.name': '7-7-7', 'achieve.secret_777.desc': 'Clocked in at 07:07 on July 7.', 'achieve.secret_exact_8h.name': 'Exactly 8 Hours', 'achieve.secret_exact_8h.desc': 'Worked exactly 8h 0m.', 'achieve.secret_pi_day.name': 'Pi Day', 'achieve.secret_pi_day.desc': 'Clocked in at 01:59 on 3/14.', 'achieve.secret_fibonacci.name': 'Fibonacci', 'achieve.secret_fibonacci.desc': 'Clock-in minute is a Fibonacci number.', 'achieve.secret_double_six.name': 'Double Six', 'achieve.secret_double_six.desc': 'Clocked in at 18:06 on 6/6.', 'achieve.secret_anniversary.name': 'Wizard', 'achieve.secret_anniversary.desc': 'Clocked in exactly 365 days after joining.', 'achieve.set_dark.name': 'Dark Side', 'achieve.set_dark.desc': 'Used dark theme once.', 'achieve.set_lang.name': 'Bilingual', 'achieve.set_lang.desc': 'Changed language (used en).', 'achieve.set_a11y.name': 'Accessibility User', 'achieve.set_a11y.desc': 'Font scale ≠ 100% or high contrast ON.', 'achieve.set_overtime_unit.name': 'Unit Changer', 'achieve.set_overtime_unit.desc': 'Changed overtime_unit.', 'achieve.set_goal_full.name': 'Goal Master', 'achieve.set_goal_full.desc': 'Set both monthly OT cap and daily average goal.', 'achieve.set_discord_full.name': 'Full Setup', 'achieve.set_discord_full.desc': 'Discord URL + all notifications ON.', 'achieve.set_cloud.name': 'Cloud Sync', 'achieve.set_cloud.desc': 'Changed DB path.', 'achieve.meta_first.name': 'First Achievement', 'achieve.meta_first.desc': 'Earned first achievement.', 'achieve.meta_10.name': '10 Achievements', 'achieve.meta_10.desc': 'Hold 10 achievements.', 'achieve.meta_25.name': '25 Achievements', 'achieve.meta_25.desc': 'Hold 25 achievements.', 'achieve.meta_50.name': '50 Achievements', 'achieve.meta_50.desc': 'Hold 50 achievements.', 'achieve.meta_75.name': '75 Achievements', 'achieve.meta_75.desc': 'Hold 75 achievements.', 'achieve.meta_100.name': '100 Achievements', 'achieve.meta_100.desc': 'Hold 100 achievements.', 'achieve.meta_secret_1.name': 'Secret Found', 'achieve.meta_secret_1.desc': 'Discovered first secret.', 'achieve.meta_secret_5.name': 'Secret Hunter', 'achieve.meta_secret_5.desc': 'Discovered 5 secrets.', 'achieve.streak_monday_10.name': 'Monday Conqueror', 'achieve.streak_monday_10.desc': 'Clocked in 10 Mondays in a row.', 'achieve.streak_friday_10.name': 'Friday Flawless', 'achieve.streak_friday_10.desc': 'Clocked in 10 Fridays in a row.', }, } # === HelpView 큰 HTML 콘텐츠 (별도 사전) === _HELP_HTML = { 'ko': { 'help.html.intro': """
퇴근시간 계산기는 출근 시간 자동 감지부터 연장근무 적립·사용까지 하루 근무를 정리해 주는 데스크톱 앱입니다.
예) 하루 7시간 30분 근무 + 점심 30분
7 시간 30 분,
점심시간 기본에 30 분설정에서 "자동 적용"을 체크하면 출근 후 4시간 경과 시 점심시간이 자동으로 켜집니다.
""", 'help.html.overtime': """정규 퇴근시간 이후 일한 시간은 30분 단위로 절삭되어 적립됩니다.
적립된 연장근무는 메인 화면 "30분 사용" / "1시간 사용" 버튼으로 쓸 수 있어요. 사용한 만큼 그날 퇴근시간이 앞당겨집니다.
주말 또는 등록된 공휴일에 일한 시간은 모든 시간이 연장근무로 적립됩니다.
""", 'help.html.leave': """잔액 = 연간 연차 − (프로그램 외 사용분 + 프로그램에서 기록된 사용분)
1일 연차의 시간 길이는 설정의 하루 기본 근무를 따릅니다. 예: 7시간 30분 근무자는 1일 연차가 7시간 30분(=450분)으로 환산됩니다.
""", 'help.html.break': """병원, 잠깐 외근 등으로 자리를 비울 때 외출 시작 → 복귀 버튼으로 시간을 추적하세요.
설정에서 "화면 잠금 시 자동 외출/복귀"를 켜면 PC 잠금 시 자동으로 외출이 시작되고, 풀리면 복귀로 처리됩니다.
야근하면서 저녁을 먹는다면 저녁시간 추가 버튼을 눌러주세요.
""", 'help.html.faq': """메인 화면 출근 시각 옆 편집(연필) 아이콘으로 수정할 수 있어요.
설정 → 근무 시간 → 근무 패턴에서 프리셋을 선택하거나 시·분을 직접 입력하세요.
실행 폴더의 database.db (SQLite). 자동 백업은
~/.clockout_backups/에 1일 1회 회전됩니다.
Clock-out Time Calculator is a desktop app that organizes your daily work — from auto-detecting clock-in time to banking and using overtime.
Example: 7h30m daily + 30-min lunch
Enable "Auto Apply" in settings to automatically turn on lunch after 4 hours from clock-in.
""", 'help.html.overtime': """Time worked past your scheduled clock-out is truncated to 30-min units.
Use buttons on the main screen to consume banked overtime. Each unit lets you clock out earlier on a chosen day.
All hours worked on weekends or registered holidays are banked entirely as overtime.
""", 'help.html.leave': """Balance = annual leave − (pre-program usage + recorded usage)
1 leave day equals your configured daily work time. Example: 7h30m worker → 1 day = 7h30m (450 min).
""", 'help.html.break': """For short absences (medical, errands), use Start Break / Return.
Enable "Auto break on screen lock" in settings — when the PC locks, a break starts automatically; on unlock, you return.
For overtime with dinner, press Add Dinner.
""", 'help.html.faq': """Click the pencil icon next to clock-in time on the main screen to edit.
Settings → Work Time → pick the preset or enter hours/minutes directly.
database.db in the program folder (SQLite). Daily auto-backups
rotate in ~/.clockout_backups/.
missing: {key}
" def available_languages() -> list: return list(_DICT.keys()) def language_label(code: str) -> str: return {'ko': '한국어', 'en': 'English'}.get(code, code)