export type Locale = "id" | "en"; export const SUPPORTED_LOCALES: readonly Locale[] = ["id", "en"] as const; export const DEFAULT_LOCALE: Locale = "id"; export const LOCALE_COOKIE = "wa_locale"; export type I18nSection = keyof typeof MESSAGES; export type MessageKey = keyof typeof MESSAGES[S]; export type NavKey = MessageKey<"nav">; const MESSAGES = { meta: { title: { id: "ZappCare Business Suite", en: "ZappCare Business Suite" }, description: { id: "Platform WhatsApp Business inbox multi-tenant", en: "Multi-tenant WhatsApp business inbox platform" } }, shell: { admin_title: { id: "Ruang Kerja Admin", en: "Admin Client Workspace" }, admin_subtitle: { id: "Kelola inbox, contact, broadcast, dan operasional tim.", en: "Manage inbox, contacts, broadcasts, and team operations." }, agent_title: { id: "Ruang Kerja Agent", en: "Agent Workspace" }, agent_subtitle: { id: "Tangani conversation, follow-up, dan performa pribadi.", en: "Handle conversations, follow-ups, and personal performance." }, super_admin_title: { id: "Platform Control Center", en: "Platform Control Center" }, super_admin_subtitle: { id: "Kelola tenant, channel, billing, dan kesehatan platform.", en: "Manage tenants, channels, billing, and platform health." } }, roles: { super_admin: { id: "Super Admin", en: "Super Admin" }, admin_client: { id: "Admin Client", en: "Admin Client" }, agent: { id: "Agent", en: "Agent" } }, nav: { dashboard: { id: "Dashboard", en: "Dashboard" }, shared_inbox: { id: "Shared Inbox", en: "Shared Inbox" }, inbox: { id: "Inbox", en: "Inbox" }, contacts: { id: "Kontak", en: "Contacts" }, broadcast: { id: "Broadcast", en: "Broadcast" }, templates: { id: "Template", en: "Templates" }, team: { id: "Tim", en: "Team" }, reports: { id: "Laporan", en: "Reports" }, settings: { id: "Pengaturan", en: "Settings" }, billing: { id: "Tagihan", en: "Billing" }, audit_log: { id: "Audit Log", en: "Audit Log" }, tenants: { id: "Tenant", en: "Tenants" }, channels: { id: "Channel", en: "Channels" }, security_events: { id: "Security Events", en: "Security Events" }, webhook_logs: { id: "Webhook Logs", en: "Webhook Logs" }, alerts: { id: "Peringatan", en: "Alerts" }, quick_tools: { id: "Quick Tools", en: "Quick Tools" }, performance: { id: "Performa", en: "Performance" }, "new_chat": { id: "Obrolan Baru", en: "New Chat" }, search: { id: "Cari", en: "Search" }, logout: { id: "Keluar", en: "Logout" }, global_search: { id: "Pencarian Global", en: "Global Search" }, campaign: { id: "Kampanye", en: "Campaigns" } }, common: { zappcare: { id: "ZappCare", en: "ZappCare" }, business_suite: { id: "Business Suite", en: "Business Suite" }, back_to_login: { id: "Kembali ke login", en: "Back to login" }, search_placeholder: { id: "Cari wawasan, kontak, atau pesan...", en: "Search insights, contacts, or messages..." }, new_chat_button: { id: "Obrolan Baru", en: "New Chat" }, notifications: { id: "Notifikasi", en: "Notifications" }, help: { id: "Bantuan", en: "Help" }, shortcut: { id: "Aplikasi", en: "App shortcuts" } }, login: { title: { id: "Selamat datang kembali", en: "Welcome back" }, signin_subtitle: { id: "Masuk ke workspace Anda", en: "Sign in to your ZappCare Business Suite" }, signin_label: { id: "Masuk", en: "Sign In" }, signin_help: { id: "Gunakan akun yang sudah di-seed untuk masuk.", en: "Use seeded account credentials to sign in." }, email_label: { id: "Email kerja", en: "Work email" }, password_label: { id: "Password", en: "Password" }, remember_label: { id: "Lupa akun?", en: "Forgot password?" }, no_account_label: { id: "Belum punya akun?", en: "Don’t have an account?" }, sso_button: { id: "Masuk dengan SSO", en: "Sign in with SSO" }, contact_admin: { id: "Hubungi administrator", en: "Contact Administrator" }, accept_invitation: { id: "Terima undangan", en: "Accept invitation" }, work_email_placeholder: { id: "name@company.com", en: "name@company.com" }, password_placeholder: { id: "••••••••", en: "••••••••" }, sign_in_button: { id: "Masuk", en: "Sign In" }, error_credentials_required: { id: "Email dan password wajib diisi.", en: "Email and password are required." }, error_invalid_credentials: { id: "Email / password salah atau akun belum aktif.", en: "Invalid email/password or inactive account." }, error_demo_disabled: { id: "Rute demo dinonaktifkan. Gunakan login biasa.", en: "Demo route is disabled. Use normal login." }, error_rate_limited: { id: "Terlalu banyak percobaan login. Coba lagi beberapa saat.", en: "Too many login attempts. Try again in a few minutes." }, forgot_action: { id: "Kirim tautan reset", en: "Send reset link" }, forgot_success: { id: "Jika email valid dan aktif, kami sudah menyiapkan tautan reset.", en: "If this account exists and is active, we have sent a reset link." }, reset_invalid_token: { id: "Token tidak valid atau sudah dipakai.", en: "This token is invalid or already used." }, reset_expired: { id: "Token sudah kedaluwarsa. Silakan minta tautan baru.", en: "The token expired. Please request a new one." }, password_mismatch: { id: "Konfirmasi password tidak cocok.", en: "Password confirmation doesn't match." }, missing_email: { id: "Email wajib diisi.", en: "Email is required." } }, placeholders: { operational_overview_title: { id: "Ikhtisar Operasional", en: "Operational overview" }, operational_overview_desc: { id: "Ringkasan kerja harian tim dan inbox.", en: "Daily team and inbox operations summary." }, operation_chart_note: { id: "Bagian grafik untuk volume message, workload agent, dan trend resolusi.", en: "Chart area for message volume, agent workload, and resolution trend." }, priority_queue_title: { id: "Antrian Prioritas", en: "Priority queue" }, priority_queue_desc: { id: "Conversation yang perlu tindakan cepat.", en: "Conversations that need quick action." }, conversation_list_title: { id: "Daftar percakapan", en: "Conversation list" }, conversation_list_desc: { id: "Semua, belum ditugaskan, ditugaskan, selesai.", en: "All, unassigned, assigned, resolved." }, no_conversation_found: { id: "Tidak ada conversation ditemukan.", en: "No conversation found." }, conversation_detail_title: { id: "Detail percakapan", en: "Conversation detail" }, conversation_detail_desc: { id: "Header, timeline, composer, template, catatan.", en: "Header, timeline, composer, templates, notes." }, select_to_reply: { id: "Pilih percakapan dari kiri untuk mulai menanggapi.", en: "Select a conversation from the left to start responding." }, no_messages: { id: "Belum ada pesan.", en: "No messages yet." }, reply_label: { id: "Balasan", en: "Reply" }, reply_placeholder: { id: "Tulis balasan...", en: "Write a reply..." }, send_reply: { id: "Kirim balasan", en: "Send reply" }, context_panel_title: { id: "Panel kontekstual", en: "Context panel" }, context_panel_desc: { id: "Penugasan, status, notes, tags, aktivitas.", en: "Assignment, status, notes, tags, activity." }, select_context: { id: "Pilih percakapan untuk melihat konteks.", en: "Select a conversation to view context." }, contact_label: { id: "Kontak", en: "Contact" }, tags_label: { id: "Tags", en: "Tags" }, assign_label: { id: "Assign", en: "Assign" }, unassign_label: { id: "Hapus tugas", en: "Unassign" }, take_assignment: { id: "Ambil tugas", en: "Take assignment" }, reassign: { id: "Reassign", en: "Reassign" }, status_label: { id: "Status", en: "Status" }, status_open: { id: "Open", en: "Open" }, status_pending: { id: "Pending", en: "Pending" }, status_resolved: { id: "Resolved", en: "Resolved" }, status_archived: { id: "Arsip", en: "Archived" }, status_spam: { id: "Spam", en: "Spam" }, update_status: { id: "Perbarui status", en: "Update status" }, add_note_label: { id: "Tambah catatan", en: "Add note" }, add_note_placeholder: { id: "Catatan internal...", en: "Internal note..." }, save_note: { id: "Simpan catatan", en: "Save note" }, save_tags: { id: "Simpan tags", en: "Save tags" }, notes_label: { id: "Catatan", en: "Notes" }, no_notes: { id: "Belum ada notes.", en: "No notes." }, tags_placeholder: { id: "high-priority, billing", en: "high-priority, billing" } }, tables: { total_contacts: { id: "Total kontak", en: "Total contacts" }, total_users: { id: "Total pengguna", en: "Total users" }, opted_in: { id: "Sudah opt-in", en: "Opted in" }, tagged_contacts: { id: "Kontak bertag", en: "Tagged contacts" }, agents: { id: "Agen", en: "Agents" }, invited: { id: "Diundang", en: "Invited" }, total_value: { id: "Total", en: "Total" } }, status: { open: { id: "Open", en: "Open" }, pending: { id: "Pending", en: "Pending" }, resolved: { id: "Resolved", en: "Resolved" } }, pages: { unauthorized_title: { id: "Tidak diizinkan", en: "Unauthorized" }, unauthorized_desc: { id: "Role ini belum memiliki akses ke halaman yang Anda buka.", en: "You don't have access to the page you opened." }, unauthorized_subtitle: { id: "Akses ditolak", en: "Access denied" }, forgot_password: { id: "Lupa password", en: "Forgot password" }, reset_password: { id: "Reset password", en: "Reset password" }, reset_desc: { id: "Atur password baru untuk akun Anda.", en: "Set a new password for your account." }, invalid_token: { id: "Token tidak valid atau sudah tidak berlaku.", en: "The token is invalid or no longer valid." }, reset_token_expired: { id: "Token reset sudah kedaluwarsa. Minta link baru.", en: "Your reset token expired. Request a new one." }, password_mismatch: { id: "Konfirmasi password tidak cocok.", en: "Password confirmation does not match." } } } as const; type LocaleMap = Record; type MessageCatalog = { [Section in keyof typeof MESSAGES]: { [Key in keyof typeof MESSAGES[Section]]: LocaleMap; }; }; export const messages = MESSAGES as MessageCatalog; export function isLocale(value: string | null | undefined): value is Locale { return value === "id" || value === "en"; } export async function getLocale(): Promise { const { cookies } = await import("next/headers"); const localeCookie = (await cookies()).get(LOCALE_COOKIE)?.value; if (isLocale(localeCookie)) { return localeCookie; } return DEFAULT_LOCALE; } export function t(locale: Locale, section: S, key: MessageKey): string { return messages[section][key][locale]; } export function getTranslator(locale: Locale) { return function translate(section: S, key: MessageKey) { return t(locale, section, key); }; }