""" 경량 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.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': '오후', # === 알림 === 'notif.clock_out_soon.title': '⏰ 퇴근 시간 임박', 'notif.clock_out_soon.body': '퇴근까지 {minutes}분 남았습니다.\n마무리 준비를 시작하세요!', 'notif.lunch_reminder.title': '🍱 점심시간 등록', 'notif.lunch_reminder.body': '점심시간을 등록하지 않으셨네요.\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법정 근로시간을 초과했습니다!', # === 메시지박스 === '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': '아직 충분한 데이터가 없습니다.', # === 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.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}', }, '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 Time', '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', # === 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.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!", # === 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.', # === 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.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}', }, } # === 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)