418 lines
17 KiB
TypeScript
418 lines
17 KiB
TypeScript
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 };
|
|
}
|