import { getRetroMode } from './mode.js'; export type Language = 'id' | 'en'; export const modernTranslations = { id: { // Branding appName: 'TautKan', appTagline: 'Satu tautan untuk semua urusan.', appBadge: 'AGILE KANBAN', // Controls lightMode: 'Mode Terang', darkMode: 'Mode Gelap', retroModeOn: '🕹️ 8-Bit Mode', retroModeOff: '✨ Modern Mode', muteAudio: 'Matikan Suara Audio', unmuteAudio: 'Nyalakan Suara Audio', changeName: 'Ubah Nama Pengguna', // Roles superadmin: 'Superadmin', member: 'Anggota', roleSuperadminDesc: 'Pemilik Papan (Akses Penuh)', roleMemberDesc: 'Anggota Tim (Kolaborator)', // Hero Section heroBadge: 'TANPA PASSWORD • TANPA EMAIL • 100% REAL-TIME', heroTitle: 'Papan Kanban Real-Time Modern', heroSubtitle: 'Kolaborasi manajemen proyek instan berbasis URL Fragment Hash. Tanpa registrasi akun, aman, cepat, dan terhubung secara langsung antar anggota tim.', // Create Board createBoardHeader: 'Buat Papan Kanban Baru', boardTitleLabel: 'Judul Proyek / Papan', boardTitlePlaceholder: 'Contoh: Pengembangan Fitur Sprint 1...', createBoardBtn: 'Buat Papan Sekarang', creatingBoardBtn: 'Sedang Membuat Papan...', rateLimitNote: 'Batas: 5 papan per jam per IP', rbacNote: 'Otorisasi Aman URL Fragment', // Saved Boards savedBoardsTitle: 'Papan Tersimpan', savedBoardsSub: 'Riwayat tersimpan di browser Anda', noSavedBoards: 'Belum ada papan yang tersimpan.', removeSaved: 'Hapus dari daftar', // Board View Header onlineUsers: 'Pengguna Online', shareInviteBtn: 'Bagikan & Undang', rotateKeyBtn: 'Putar Kunci Anggota', rotateKeyTooltip: 'Regenerasi tautan anggota untuk mencabut akses lama', deleteBoardTooltip: 'Hapus papan ini secara permanen', boardSettings: 'Pengaturan Papan', autoMoveStaleSetting: 'Otomatis kembalikan kartu macet (> batas jam) ke Backlog', backToHome: 'Kembali ke Beranda', connectingToRealm: 'Menghubungkan ke papan...', accessForbidden: 'Akses Ditolak', accessForbiddenDesc: 'Kunci otorisasi tidak valid atau sudah tidak berlaku.', reEnterKey: 'Masukkan Kunci Kembali', boardLogsBtn: 'Riwayat Log', activityLogTitle: 'Riwayat Perpindahan & Log Aktivitas', noActivityLogs: 'Belum ada riwayat pergerakan kartu yang tercatat.', // Columns & WIP addColumn: 'Tambah Kolom', columnTitlePlaceholder: 'Nama kolom (misal: QA Testing)...', addNewTask: 'Tambah Tugas', taskTitlePlaceholder: 'Tulis judul tugas...', enterToAdd: 'Tekan Enter ↵ untuk simpan', cancel: 'Batal', add: 'Tambah', save: 'Simpan', noTasksInCol: 'Belum ada tugas di kolom ini', dragColTooltip: 'Geser untuk mengatur urutan kolom', deleteColConfirm: 'Hapus kolom ini beserta semua tugas di dalamnya?', editColSettings: 'Pengaturan Kolom & WIP Limit', wipLimitLabel: 'WIP Limit (Maksimal Kartu):', wipUnlimited: '0 = Tanpa Batas', autoStaleHoursLabel: 'Batas Macet / Stale (Jam Inaktivitas):', wipLimitReached: 'WIP Limit Tercapai', wipWarningModal: 'Kolom ini telah mencapai batas kapasitas maksimum kartu (WIP Limit). Selesaikan tugas yang ada terlebih dahulu!', // Ticket Modal / Editor taskTitle: 'Judul Tugas', taskDesc: 'Deskripsi Tugas / Spesifikasi', taskDescPlaceholder: 'Tuliskan rincian tugas, kriteria penerimaan, atau catatan penting...', priorityLabel: 'Prioritas / Urgensi', tagsLabel: 'Label / Tags (Tekan Enter)', tagsPlaceholder: 'Contoh: FRONTEND, BUG, BACKEND...', assigneeLabel: 'Penanggung Jawab (Assignee)', assigneePlaceholder: 'Contoh: Budi Santoso', dueDateLabel: 'Tenggat Waktu (Due Date)', subtasksLabel: 'Checklist Sub-tugas', addSubtaskPlaceholder: 'Tambah sub-tugas baru... (Enter)', blockedLabel: 'Status Macet / Tertahan (Blocked)', markBlocked: 'Tandai Sebagai Macet (Blocked)', blockedReasonLabel: 'Alasan Kendala / Blocker:', blockedReasonPlaceholder: 'Contoh: Menunggu API pihak ketiga selesai / Butuh approval...', staleIndicator: 'Kartu Macet (Stale)', staleSince: 'Tidak ada pergerakan selama', overdue: 'Terlambat', dueToday: 'Hari Ini', autoSaving: 'Menyimpan otomatis...', synced: 'Tersinkronisasi', isTypingTitle: 'sedang mengetik judul tugas...', isTypingDesc: 'sedang mengetik deskripsi...', isEditingGeneral: 'sedang mengedit tugas ini...', deleteTask: 'Hapus Tugas', close: 'Tutup', deleteTaskConfirm: 'Apakah Anda yakin ingin menghapus tugas ini?', cardMovementHistory: 'Riwayat Perpindahan Kartu (Database Log)', // Priorities prioLow: 'Rendah', prioMedium: 'Sedang', prioHigh: 'Tinggi', prioUrgent: 'Mendesak', // Success Share Modal boardCreatedTitle: 'Papan TautKan Berhasil Dibuat!', boardName: 'Nama Papan', adminLinkTitle: 'Tautan Admin (Superadmin)', adminLinkWarning: 'JANGAN BAGIKAN! HANYA UNTUK ANDA', adminLinkSavedNote: 'Tautan ini tersimpan di browser Anda. Bookmark tautan ini untuk mengelola papan.', memberLinkTitle: 'Tautan Undangan Anggota Tim', memberLinkBadge: 'UNTUK REKAN TIM', copied: 'Tersalin!', copy: 'Salin', shareWhatsApp: 'Bagikan ke WhatsApp / Aplikasi', enterBoardBtn: 'Buka Papan Kanban', // Key Rotation Modal keyRotationTitle: 'Rotasi Kunci Anggota', keyRotationSubtitle: 'Buat Ulang Tautan Undangan Anggota Tim', keyRotationWarningTitle: 'Peringatan: Menonaktifkan Tautan Lama!', keyRotationWarningDesc: 'Membuat kunci anggota baru akan secara instan mencabut izin seluruh anggota yang menggunakan tautan lama dan memutuskan sesi mereka secara real-time.', regenerateBtn: 'Buat Ulang Tautan', rotatingBtn: 'Memproses...', newLinkActiveTitle: 'Tautan Baru Berhasil Diaktifkan!', newLinkActiveDesc: 'Tautan anggota lama telah dinonaktifkan. Bagikan tautan baru ini kepada rekan tim Anda:', done: 'Selesai', // Key Prompt Modal keyPromptTitle: 'Kunci Otorisasi Diperlukan', keyPromptDesc: 'Papan ini terlindungi oleh URL Fragment Key. Silakan tempel tautan lengkap (#admin=... atau #member=...) atau kunci rahasia Anda di bawah ini.', keyPromptPlaceholder: 'Tempel tautan #admin=... atau #member=... atau kunci Anda', unlockBoardBtn: 'Buka Papan', keyPromptError: 'Silakan masukkan kunci atau tautan undangan', // Revoked Alert sessionRevokedMsg: 'Superadmin telah membuat ulang tautan anggota. Sesi Anda telah dihentikan.', movementFailed: 'Gagal memindahkan kartu:', footerText: 'TautKan • Satu tautan untuk semua urusan • Dual-Code URL Fragment Real-Time Agile', }, en: { // Branding appName: 'TautKan', appTagline: 'One link to manage it all.', appBadge: 'AGILE KANBAN', // Controls lightMode: 'Light Mode', darkMode: 'Dark Mode', retroModeOn: '🕹️ 8-Bit Mode', retroModeOff: '✨ Modern Mode', muteAudio: 'Mute Audio', unmuteAudio: 'Unmute Audio', changeName: 'Change User Name', // Roles superadmin: 'Superadmin', member: 'Member', roleSuperadminDesc: 'Board Owner (Full Access)', roleMemberDesc: 'Team Member (Collaborator)', // Hero Section heroBadge: 'ZERO PASSWORDS • ZERO EMAILS • 100% REAL-TIME', heroTitle: 'Modern Real-Time Agile Kanban', heroSubtitle: 'Instant project collaboration powered by URL Fragment Hashes. Zero sign-up required, ultra-secure, fast, and connected in real time.', // Create Board createBoardHeader: 'Create a New Kanban Board', boardTitleLabel: 'Project / Board Title', boardTitlePlaceholder: 'e.g. Sprint 1 - Core Feature Development...', createBoardBtn: 'Create Board Now', creatingBoardBtn: 'Creating Board...', rateLimitNote: 'Limit: 5 boards/hour per IP', rbacNote: 'Secure URL Fragment Key Auth', // Saved Boards savedBoardsTitle: 'Saved Boards', savedBoardsSub: 'History stored securely in your browser', noSavedBoards: 'No saved boards found.', removeSaved: 'Remove from history', // Board View Header onlineUsers: 'Online Teammates', shareInviteBtn: 'Share & Invite', rotateKeyBtn: 'Rotate Member Key', rotateKeyTooltip: 'Regenerate member key and revoke all previous member links', deleteBoardTooltip: 'Permanently delete this board', boardSettings: 'Board Settings', autoMoveStaleSetting: 'Automatically move stale cards (> threshold hours) back to Backlog', backToHome: 'Back to Home', connectingToRealm: 'Connecting to board realm...', accessForbidden: 'Access Denied', accessForbiddenDesc: 'The authorization key in this URL is invalid or has expired.', reEnterKey: 'Re-Enter Key', boardLogsBtn: 'Activity Logs', activityLogTitle: 'Movement & Activity History', noActivityLogs: 'No card movements logged yet.', // Columns & WIP addColumn: 'Add Column', columnTitlePlaceholder: 'Column name (e.g., QA Testing)...', addNewTask: 'Add Task', taskTitlePlaceholder: 'Write task title...', enterToAdd: 'Press Enter ↵ to save', cancel: 'Cancel', add: 'Add', save: 'Save', noTasksInCol: 'No tasks in this column yet', dragColTooltip: 'Drag to reorder column', deleteColConfirm: 'Delete this column and all of its tasks?', editColSettings: 'Column Settings & WIP Limit', wipLimitLabel: 'WIP Limit (Max Cards):', wipUnlimited: '0 = Unlimited', autoStaleHoursLabel: 'Stale Inactivity Limit (Hours):', wipLimitReached: 'WIP Limit Reached', wipWarningModal: 'This column has reached its maximum Work-In-Progress (WIP) limit. Please finish active tasks first!', // Ticket Modal / Editor taskTitle: 'Task Title', taskDesc: 'Task Description / Specs', taskDescPlaceholder: 'Write specifications, acceptance criteria, or key implementation notes...', priorityLabel: 'Priority / Urgency', tagsLabel: 'Tags (Press Enter)', tagsPlaceholder: 'e.g. FRONTEND, BUG, BACKEND...', assigneeLabel: 'Assignee', assigneePlaceholder: 'e.g. Alex Morgan', dueDateLabel: 'Due Date', subtasksLabel: 'Subtask Checklist', addSubtaskPlaceholder: 'Add a new subtask... (Enter)', blockedLabel: 'Blocker Status (Blocked)', markBlocked: 'Mark as Blocked', blockedReasonLabel: 'Blocker Explanation:', blockedReasonPlaceholder: 'e.g. Waiting for 3rd-party API approval...', staleIndicator: 'Stale Card', staleSince: 'No movement for', overdue: 'Overdue', dueToday: 'Due Today', autoSaving: 'Auto-saving...', synced: 'Synced', isTypingTitle: 'is typing title...', isTypingDesc: 'is typing description...', isEditingGeneral: 'is editing this task...', deleteTask: 'Delete Task', close: 'Close', deleteTaskConfirm: 'Are you sure you want to delete this task?', cardMovementHistory: 'Card Movement History (Database Log)', // Priorities prioLow: 'Low', prioMedium: 'Medium', prioHigh: 'High', prioUrgent: 'Urgent', // Success Share Modal boardCreatedTitle: 'TautKan Board Created!', boardName: 'Board Name', adminLinkTitle: 'Admin Key Link (Superadmin)', adminLinkWarning: 'DO NOT SHARE! ADMIN ACCESS ONLY', adminLinkSavedNote: 'This link is saved in your browser. Bookmark it to maintain management permissions.', memberLinkTitle: 'Team Member Invite Link', memberLinkBadge: 'FOR TEAMMATES', copied: 'Copied!', copy: 'Copy', shareWhatsApp: 'Share via WhatsApp / Apps', enterBoardBtn: 'Open Kanban Board', // Key Rotation Modal keyRotationTitle: 'Member Key Rotation', keyRotationSubtitle: 'Regenerate Team Member Invite Link', keyRotationWarningTitle: 'Warning: Invalidates Old Links!', keyRotationWarningDesc: 'Generating a new member key will immediately revoke access for all members using old links and disconnect active sessions in real time.', regenerateBtn: 'Regenerate Link', rotatingBtn: 'Rotating...', newLinkActiveTitle: 'New Member Link Active!', newLinkActiveDesc: 'Old member links have been successfully invalidated. Share this new link with your team:', done: 'Done', // Key Prompt Modal keyPromptTitle: 'Secret Key Required', keyPromptDesc: 'This board is protected by a URL Fragment Key. Please paste your link (#admin=... or #member=...) or secret key below.', keyPromptPlaceholder: 'Paste #admin=... or #member=... link or key', unlockBoardBtn: 'Unlock Board', keyPromptError: 'Please enter your key or invite link', // Revoked Alert sessionRevokedMsg: 'The superadmin regenerated the member invite link. Your session has been revoked.', movementFailed: 'Task movement failed:', footerText: 'TautKan • One link to manage it all • Dual-Code URL Fragment Real-Time Agile', }, }; export const retroTranslations = { id: { ...modernTranslations.id, appBadge: '🕹️ 8-BIT RPG', superadmin: 'OVERLORD / GUILD MASTER', member: 'PARTY MEMBER', heroTitle: 'QUEST REALM 8-BIT', heroSubtitle: 'Bangun petualangan manajemen quest tim secara instan! Otorisasi URL Fragment Hash tanpa registrasi, chip-audio 8-bit, dan kolaborasi waktu nyata.', createBoardHeader: 'FORGE QUEST REALM BARU', boardTitleLabel: 'NAMA PETUALANGAN / REALM', boardTitlePlaceholder: 'Contoh: SPRINT NETHERS / BOSS RAID...', createBoardBtn: '⚔️ FORGE REALM BARU', creatingBoardBtn: 'FORGING REALM...', savedBoardsTitle: 'REALM TERSIMPAN SAYA', onlineUsers: 'PARTY ONLINE', shareInviteBtn: '📜 UNDANG GUILD', rotateKeyBtn: '🗝️ ROTASI KUNCI', boardLogsBtn: '📜 LOG QUEST', activityLogTitle: 'GULUNGAN LOG RIWAYAT & PERGERAKAN QUEST', addColumn: 'TAMBAH TAHAPAN QUEST', addNewTask: 'TAMBAH QUEST', taskTitlePlaceholder: 'Nama misi / quest...', taskTitle: 'NAMA MISI / QUEST', taskDesc: 'GULUNGAN DESKRIPSI & SPESIFIKASI', taskDescPlaceholder: 'Tuliskan detail misi, item reward, atau catatan petualangan...', priorityLabel: 'TINGKAT BAHAYA / URGENSI', prioLow: 'WOOD (RENDAH)', prioMedium: 'IRON (SEDANG)', prioHigh: 'GOLD (TINGGI)', prioUrgent: 'NETHERITE (MENDESAK)', subtasksLabel: 'CHECKLIST SUB-QUEST', addSubtaskPlaceholder: 'Tambah sub-quest baru... (Enter)', dueDateLabel: 'TENGGAT WAKTU BOSS RAID', blockedLabel: 'JEBAKAN / STATUS TERTAHAN (TRAPPED)', markBlocked: '🚩 TERKENA JEBAKAN (BLOCKED)', staleIndicator: 'QUEST TERTIDUR (STALE)', wipLimitReached: 'MANA WIP LIMIT PENUH', wipWarningModal: 'Tahapan ini kehabisan Mana (WIP Limit Penuh)! Selesaikan quest yang aktif sebelum memulai quest baru.', cardMovementHistory: 'GULUNGAN PERJALANAN QUEST (LOG DB)', footerText: 'TautKan • 8-Bit Retro Mode • Satu tautan untuk semua urusan • Real-Time RPG Quest Board', }, en: { ...modernTranslations.en, appBadge: '🕹️ 8-BIT RPG', superadmin: 'OVERLORD / GUILD MASTER', member: 'PARTY MEMBER', heroTitle: '8-BIT QUEST REALM', heroSubtitle: 'Forge your team quest adventure instantly! URL Fragment Hash authorization, 8-bit chip audio, and real-time multiplayer board synchronization.', createBoardHeader: 'FORGE NEW QUEST REALM', boardTitleLabel: 'REALM / ADVENTURE NAME', boardTitlePlaceholder: 'e.g. SPRINT NETHER / BOSS RAID...', createBoardBtn: '⚔️ FORGE REALM', creatingBoardBtn: 'FORGING REALM...', savedBoardsTitle: 'SAVED QUEST REALMS', onlineUsers: 'PARTY ONLINE', shareInviteBtn: '📜 SUMMON PARTY', rotateKeyBtn: '🗝️ ROTATE KEY', boardLogsBtn: '📜 QUEST LOGS', activityLogTitle: 'QUEST JOURNEY & ACTIVITY SCROLL', addColumn: 'ADD QUEST STAGE', addNewTask: 'ADD QUEST', taskTitlePlaceholder: 'Quest / Mission name...', taskTitle: 'QUEST / MISSION TITLE', taskDesc: 'QUEST SCROLL & SPECIFICATIONS', taskDescPlaceholder: 'Describe quest requirements, loot rewards, or tactical notes...', priorityLabel: 'DANGER / URGENCY TIER', prioLow: 'WOOD (LOW)', prioMedium: 'IRON (MEDIUM)', prioHigh: 'GOLD (HIGH)', prioUrgent: 'NETHERITE (URGENT)', subtasksLabel: 'SUB-QUEST CHECKLIST', addSubtaskPlaceholder: 'Add new sub-quest... (Enter)', dueDateLabel: 'BOSS RAID DUE DATE', blockedLabel: 'TRAP / BLOCKED STATUS', markBlocked: '🚩 TRAPPED IN BLOCKER', staleIndicator: 'DORMANT QUEST (STALE)', wipLimitReached: 'MANA WIP LIMIT FULL', wipWarningModal: 'This stage has reached its maximum Mana capacity (WIP Limit)! Finish ongoing quests first.', cardMovementHistory: 'QUEST MOVEMENT SCROLL (DB LOG)', footerText: 'TautKan • 8-Bit Retro Mode • One link to manage it all • Real-Time RPG Quest Board', }, }; const LANG_KEY = 'tautkan_lang'; export function getLanguage(): Language { try { const saved = localStorage.getItem(LANG_KEY) as Language; if (saved === 'id' || saved === 'en') return saved; } catch {} return 'id'; // Default to Bahasa Indonesia } export function setLanguage(lang: Language): void { try { localStorage.setItem(LANG_KEY, lang); } catch {} } export function useTranslation() { const currentLang = getLanguage(); const isRetro = getRetroMode(); const activeDict = isRetro ? retroTranslations[currentLang] : modernTranslations[currentLang]; const fallbackDict = modernTranslations['id']; const t = (key: keyof typeof modernTranslations['id']): string => { return (activeDict as any)?.[key] || (fallbackDict as any)?.[key] || (key as string); }; return { t, currentLang, isRetro }; }