chore: initial project import
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled

This commit is contained in:
Wira Basalamah
2026-04-21 09:29:29 +07:00
commit adde003fba
222 changed files with 37657 additions and 0 deletions

225
lib/i18n.ts Normal file
View File

@ -0,0 +1,225 @@
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<S extends I18nSection> = 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: "Dont 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<Locale, string>;
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<Locale> {
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<S extends I18nSection>(locale: Locale, section: S, key: MessageKey<S>): string {
return messages[section][key][locale];
}
export function getTranslator(locale: Locale) {
return function translate<S extends I18nSection>(section: S, key: MessageKey<S>) {
return t(locale, section, key);
};
}