en_US and en are distinct.",
-
"header": "Header",
"headerNone": "None",
"headerText": "Text",
@@ -1355,7 +1393,6 @@
"headerTextPlaceholder": "Header text (max 60 chars, optional {{1}})",
"headerSampleAria": "Sample value for header variable",
"headerSamplePlaceholder": "Sample value for {{1}} (required for Meta review)",
-
"uploadImage": "Upload image",
"uploadHint": "JPEG or PNG, ≤5 MB",
"mediaUrlPlaceholder": "https://… (or paste a public {format} link)",
@@ -1363,17 +1400,14 @@
"mediaHint": "Must be a publicly accessible HTTPS link. Meta fetches it once during review, so it needs to stay live for ~24 hrs.",
"videoHint": " Recommended: MP4 / 3GPP, ≤16 MB, ≤60 seconds.",
"documentHint": " Recommended: PDF, ≤100 MB.",
-
"bodyText": "Body Text",
"bodyPlaceholder": "Hello {{1}}, your order {{2}} is confirmed.",
"bodyHint": "Use {{1}}, {{2}} for variables (must be contiguous starting at {{1}}).",
"sampleValues": "Sample values (Meta uses these to review your template)",
"sampleAria": "Sample value for body variable {var}",
"samplePlaceholder": "Sample for {var}",
-
"footer": "Footer (optional)",
"footerPlaceholder": "Optional footer text (max 60 chars)",
-
"buttons": "Buttons (optional)",
"addButton": "Add Button",
"buttonsLimit": "Up to {max} buttons. QUICK_REPLY buttons must come before URL / phone / copy-code buttons.",
@@ -1386,19 +1420,16 @@
"urlSamplePlaceholder": "Example value for {{1}} (required when URL has a variable)",
"phonePlaceholder": "+15551234567",
"codePlaceholder": "Example code (e.g. SUMMER20)",
-
"cancel": "Cancel",
"saving": "Saving…",
"submitting": "Submitting…",
"saveResubmit": "Save & Resubmit",
"submitApproval": "Submit for Approval",
-
"deleteDialogTitle": "Delete template?",
"deleteMetaDesc": "\"{name}\" will be deleted from Meta and from wacrm. Active broadcasts using this template will start failing on their next send. This can't be undone.",
"deleteLocalDesc": "\"{name}\" will be deleted from wacrm. It was never submitted to Meta, so no remote cleanup is needed.",
"deleting": "Deleting…",
"delete": "Delete",
-
"toastLoadFailed": "Failed to load templates",
"toastSubmitFailed": "Failed to submit",
"toastSubmitEditSuccess": "Edit submitted — Meta typically reviews within 24 hours.",
@@ -1491,7 +1522,29 @@
"step4_3": "Paste the Webhook Callback URL from above",
"step4_4": "Enter the same Verify Token you set here",
"step4_5": "Subscribe to \"messages\" webhook field",
- "metaDocs": "Meta WhatsApp API Documentation"
+ "metaDocs": "Meta WhatsApp API Documentation",
+ "phoneNumberIdRequired": "Phone Number ID is required",
+ "accessTokenRequired": "Access Token is required for initial setup",
+ "loadFailed": "Failed to load WhatsApp configuration",
+ "saveFailed": "Failed to save configuration",
+ "reenterToken": "Please re-enter the Access Token to save changes",
+ "savedRegisterFailed": "Saved, but Meta couldn't register the number: {error}",
+ "savedRegisterSkipped": "Credentials saved and verified. Inbound registration was skipped (no PIN) — see Registration status below.",
+ "savedLive": "Live — {name} can now receive events.",
+ "savedConnected": "WhatsApp connected. Events will start flowing within a minute.",
+ "connectedTo": "Connected to {name}",
+ "connectionSuccess": "API connection successful",
+ "connectionFailed": "API connection failed",
+ "connectionTestFailed": "Connection test failed. Check network and try again.",
+ "numberLive": "Number is fully wired — Meta is delivering events.",
+ "numberNotRegistered": "Number is not fully registered. See the checks below for which step failed.",
+ "verifyEndpointFailed": "Could not reach the verification endpoint.",
+ "resetConfirm": "This will delete the current WhatsApp config so you can re-enter it. Continue?",
+ "resetFailed": "Failed to reset configuration",
+ "resetSuccess": "Configuration cleared. You can now re-enter your credentials.",
+ "webhookCopied": "Webhook URL copied to clipboard",
+ "phoneNumberIdPlaceholder": "e.g. 100234567890123",
+ "wabaIdPlaceholder": "e.g. 100234567890456"
},
"sections": {
"overview": "Overview",
@@ -1503,7 +1556,8 @@
"fields": "Fields & tags",
"deals": "Deals & currency",
"members": "Team members",
- "api": "API keys"
+ "api": "API keys",
+ "quick-replies": "Quick replies"
},
"groups": {
"account": "Account",
@@ -1537,7 +1591,6 @@
"profileSaved": "Profile saved",
"emailChangeFailed": "Email change failed: {message}",
"profileSavedEmailCheck": "Profile saved — check your email to confirm the address change",
-
"passwordTitle": "Password",
"passwordDesc": "Use at least {min} characters. You will stay signed in on this device after changing it.",
"currentPassword": "Current password",
@@ -1551,7 +1604,6 @@
"currentPasswordIncorrect": "Current password is incorrect",
"passwordUpdateFailed": "Password update failed: {message}",
"passwordUpdated": "Password updated",
-
"sessionsTitle": "Active sessions",
"sessionsDesc": "Sign out of every device where you're logged in — including this one. Useful if you lost a laptop or shared your password.",
"signOutAll": "Sign out of all devices",
@@ -1560,7 +1612,8 @@
"cancel": "Cancel",
"signingOut": "Signing out…",
"signOutEverywhere": "Sign out everywhere",
- "signOutFailed": "Sign-out failed: {message}"
+ "signOutFailed": "Sign-out failed: {message}",
+ "displayNamePlaceholder": "Ada Lovelace"
},
"appearance": {
"title": "Appearance",
@@ -1598,7 +1651,7 @@
"nameLabel": "Name",
"namePlaceholder": "e.g. Zapier automation",
"scopesLabel": "Scopes",
- "scopesHint": "A key with no scopes can still call GET /api/v1/me to verify it works.",
+ "scopesHint": "A key with no scopes can still call GET /api/v1/me to verify it works.",
"cancel": "Cancel",
"creating": "Creating…",
"createKey": "Create key",
@@ -1611,7 +1664,16 @@
"newKeyTitle": "New API key",
"newKeyDesc": "Name it after the integration that will use it, and grant only the scopes it needs.",
"done": "Done",
- "networkError": "Could not reach the server"
+ "networkError": "Could not reach the server",
+ "scopeDesc": {
+ "messages:send": "Send WhatsApp messages",
+ "messages:read": "Read messages and their delivery status",
+ "contacts:read": "List and read contacts",
+ "contacts:write": "Create and update contacts",
+ "conversations:read": "List and read conversations",
+ "broadcasts:send": "Launch broadcast campaigns",
+ "webhooks:manage": "Register and manage outbound event webhooks"
+ }
},
"deals": {
"title": "Deals & currency",
@@ -1691,6 +1753,259 @@
"reindex": "Reindex",
"reindexTooltip": "Re-embed all documents (e.g. after adding an embeddings key)",
"loading": "Loading…"
+ },
+ "sectionsNav": "Settings sections",
+ "quickReplies": {
+ "nameRequired": "Give the quick reply a name.",
+ "saveError": "Couldn't save the quick reply.",
+ "updated": "Quick reply updated.",
+ "created": "Quick reply created.",
+ "deleteConfirm": "Delete this quick reply?",
+ "deleteError": "Couldn't delete the quick reply.",
+ "title": "Quick replies",
+ "description": "Reusable snippets — plain text or a saved interactive message — that agents can insert from the inbox composer.",
+ "newQuickReply": "New quick reply",
+ "empty": "No quick replies yet. Create one to reuse it across conversations.",
+ "editQuickReply": "Edit quick reply",
+ "nameLabel": "Name",
+ "namePlaceholder": "e.g. Business hours",
+ "kindText": "Text",
+ "kindInteractive": "Interactive",
+ "textPlaceholder": "The message text to insert",
+ "cancel": "Cancel",
+ "save": "Save"
+ }
+ },
+ "Notifications": {
+ "title": "Notifications",
+ "subtitle": "Conversations other teammates assign to you show up here.",
+ "markAllAsRead": "Mark all as read",
+ "retry": "Retry",
+ "emptyTitle": "No notifications yet",
+ "emptyBody": "You'll see an alert here when someone assigns you a conversation.",
+ "unread": "Unread",
+ "markReadError": "Failed to mark notification as read",
+ "markAllError": "Failed to mark all as read"
+ },
+ "Signup": {
+ "title": "Create account",
+ "titleInvite": "Create account & join",
+ "description": "Get started with CRM Template for WhatsApp",
+ "descriptionInvite": "Verify your email, then accept the invitation to join your team.",
+ "checkEmailTitle": "Check your email",
+ "checkEmailBodyBefore": "We've sent a confirmation link to",
+ "checkEmailBodyAfter": ". Please check your inbox and click the link to verify your account.",
+ "backToSignIn": "Back to sign in",
+ "fullName": "Full name",
+ "fullNamePlaceholder": "John Doe",
+ "email": "Email",
+ "password": "Password",
+ "passwordPlaceholder": "At least 6 characters",
+ "confirmPassword": "Confirm password",
+ "confirmPasswordPlaceholder": "Repeat your password",
+ "createAccount": "Create account",
+ "creatingAccount": "Creating account...",
+ "alreadyHaveAccount": "Already have an account?",
+ "signIn": "Sign in",
+ "passwordsDoNotMatch": "Passwords do not match",
+ "passwordTooShort": "Password must be at least 6 characters"
+ },
+ "ForgotPassword": {
+ "title": "Reset password",
+ "description": "Enter your email and we'll send you a reset link",
+ "checkEmailTitle": "Check your email",
+ "checkEmailBodyBefore": "We've sent a password reset link to",
+ "checkEmailBodyAfter": ". Please check your inbox.",
+ "backToSignIn": "Back to sign in",
+ "email": "Email",
+ "sending": "Sending...",
+ "sendResetLink": "Send reset link"
+ },
+ "Join": {
+ "verifying": "Verifying invitation…",
+ "tryAgain": "Try again",
+ "createAccountInstead": "Create a new account instead",
+ "signIn": "Sign in",
+ "invitedTo": "You're invited to",
+ "joinAs": "You'll join as",
+ "role": {
+ "admin": "Admin",
+ "agent": "Agent",
+ "viewer": "Viewer"
+ },
+ "linkValidUntil": ". Link valid until {date}.",
+ "accepting": "Accepting…",
+ "acceptInvitation": "Accept invitation",
+ "acceptHelpBefore": "Accepting moves your login into",
+ "acceptHelpAfter": ". Your empty personal account from signup will be cleaned up.",
+ "conflictTitle": "Can't join {name} with this account",
+ "conflictHelpBefore": "To join",
+ "conflictHelpAfter": ", sign out and sign up again with a different email address. The invite link stays valid as long as it hasn't expired.",
+ "staySignedIn": "Stay signed in",
+ "signingOut": "Signing out…",
+ "signOutDifferentEmail": "Sign out & use a different email",
+ "createAccountAndJoin": "Create account & join",
+ "alreadyHaveAccount": "I already have an account",
+ "fail": {
+ "not_found": {
+ "title": "Invite not found",
+ "body": "This link doesn't match a valid invitation. Double-check the URL or ask the person who invited you to send a new one."
+ },
+ "used": {
+ "title": "Invite already used",
+ "body": "This invitation has already been accepted. If that wasn't you, ask the account admin to send a fresh link."
+ },
+ "expired": {
+ "title": "Invite expired",
+ "body": "This invitation has expired. Ask the account admin to send a new one — they take a few seconds to generate."
+ },
+ "server_error": {
+ "title": "Something went wrong",
+ "body": "We couldn't verify this invitation right now. Try refreshing the page in a moment."
+ }
+ },
+ "conflictFallback": "You are already in another account. Sign in with a different email to join this one.",
+ "acceptError": "Failed to accept invitation",
+ "welcomeToast": "Welcome to the team",
+ "serverUnreachable": "Could not reach the server",
+ "signOutError": "Could not sign out. Try refreshing the page."
+ },
+ "Agents": {
+ "title": "AI Agents",
+ "subtitle": "Your bring-your-own-key AI agent — set it up, then test it in the playground before it replies to customers in the inbox.",
+ "tabPlayground": "Playground",
+ "tabSetup": "Setup",
+ "tabUsage": "Usage"
+ },
+ "AiPlayground": {
+ "notConfiguredToast": "No agent configured yet — finish Setup first.",
+ "noReplyToast": "Couldn't get a reply.",
+ "unreachableToast": "Couldn't reach the agent.",
+ "headerTitle": "Playground",
+ "headerSubtitle": "— test replies as if you were a customer",
+ "reset": "Reset",
+ "emptyTitle": "Send a message to see how your agent would reply.",
+ "emptyDescription": "It uses your knowledge base and behaves exactly like the auto-reply bot — including handoff.",
+ "goToSetup": "Not set up yet? Go to Setup",
+ "handoffLabel": "Would hand off to a human here",
+ "thinking": "Thinking…",
+ "composerPlaceholder": "Type a customer message…"
+ },
+ "AiUsage": {
+ "loadError": "Failed to load usage",
+ "tokenUsage": "Token usage",
+ "description": "Tokens spent on your provider key by drafts and the auto-reply bot. Counts only — no message content is stored here.",
+ "lastDays": "Last {w} days",
+ "noUsage": "No AI usage in the last {n} days yet.",
+ "noUsageHint": "This fills in as the assistant drafts and auto-replies.",
+ "totalTokens": "Total tokens",
+ "llmCalls": "LLM calls",
+ "autoReply": "Auto-reply",
+ "drafts": "Drafts",
+ "tokensPerDay": "Tokens per day",
+ "byModel": "By model",
+ "modelUsage": "{tokens} tok · {calls, plural, one {# call} other {# calls}}",
+ "truncatedNote": "Showing a partial window — usage is high enough that only the most recent records are summarized here."
+ },
+ "FlowsHeader": {
+ "backToFlows": "Back to Flows",
+ "flowNamePlaceholder": "Flow name",
+ "flowNameLabel": "Flow name",
+ "unsavedChanges": "Unsaved changes — hit Save to persist",
+ "edited": "Edited",
+ "runs": "Runs",
+ "delete": "Delete",
+ "pause": "Pause",
+ "activate": "Activate",
+ "fixIssuesBeforeActivating": "Fix the issues below before activating",
+ "save": "Save",
+ "descriptionPlaceholder": "Add a short description (internal — customers don't see this)",
+ "descriptionLabel": "Flow description",
+ "statusDraft": "Draft",
+ "statusActive": "Active",
+ "statusArchived": "Archived"
+ },
+ "InteractiveBuilder": {
+ "replyButtons": "Reply buttons",
+ "list": "List",
+ "body": "Body",
+ "bodyPlaceholder": "What the customer reads above the options",
+ "headerOptional": "Header (optional)",
+ "footerOptional": "Footer (optional)",
+ "showReplyIds": "Show reply IDs (advanced)",
+ "preview": "Preview",
+ "buttonsCount": "Buttons ({count}/{max})",
+ "buttonLabel": "Button label",
+ "idPlaceholder": "id",
+ "addButton": "Add button",
+ "listButtonLabel": "List button label",
+ "rowsCount": "Rows ({count}/{max})",
+ "sectionTitleOptional": "Section title (optional)",
+ "rowTitle": "Row title",
+ "descriptionOptional": "Description (optional)",
+ "addRow": "Add row",
+ "addSection": "Add section"
+ },
+ "InteractivePreview": {
+ "messageBody": "Message body…",
+ "button": "Button",
+ "menu": "Menu"
+ },
+ "FlowTemplates": {
+ "welcome_menu": {
+ "name": "Welcome menu",
+ "description": "Greet customers who type a keyword and route them to the right agent based on whether they're new or existing."
+ },
+ "faq_bot": {
+ "name": "FAQ bot",
+ "description": "Answer common questions automatically. Customer picks a topic from a list; the bot replies with the answer and ends."
+ },
+ "lead_capture": {
+ "name": "Lead capture",
+ "description": "Greet first-time inbounds, capture name + email + company, then hand off to sales with the answers in the note."
}
+ },
+ "AutomationTemplates": {
+ "welcome_message": {
+ "name": "Welcome Message",
+ "description": "Auto-reply to first-time contacts with a greeting."
+ },
+ "out_of_office": {
+ "name": "Out of Office",
+ "description": "Auto-reply during off-hours so nobody is left waiting."
+ },
+ "lead_qualifier": {
+ "name": "Lead Qualifier",
+ "description": "Ask qualification questions to filter inbound leads."
+ },
+ "follow_up_reminder": {
+ "name": "Follow-up Reminder",
+ "description": "Send a nudge if a contact has not replied within 24 hours."
+ }
+ },
+ "Themes": {
+ "violet": {
+ "name": "Violet",
+ "description": "The default — confident, slightly playful."
+ },
+ "emerald": {
+ "name": "Emerald",
+ "description": "Growth-coded, nods at messaging without copying WhatsApp green."
+ },
+ "cobalt": {
+ "name": "Cobalt",
+ "description": "Clean B2B-SaaS blue — calm and product-y."
+ },
+ "amber": {
+ "name": "Amber",
+ "description": "Warm and friendly — feels good for SMB teams."
+ },
+ "rose": {
+ "name": "Rose",
+ "description": "Bold and modern — D2C, creator-economy, lifestyle."
+ }
+ },
+ "Common": {
+ "loading": "Loading..."
}
}
diff --git a/messages/es.json b/messages/es.json
new file mode 100644
index 0000000000..3b4e088685
--- /dev/null
+++ b/messages/es.json
@@ -0,0 +1,2011 @@
+{
+ "LoginPage": {
+ "titleAccept": "Inicia sesión para aceptar",
+ "titleWelcome": "Bienvenido de nuevo",
+ "descAccept": "Inicia sesión y te llevaremos a la invitación.",
+ "descWelcome": "Inicia sesión en tu cuenta",
+ "emailLabel": "Correo electrónico",
+ "emailPlaceholder": "tu@ejemplo.com",
+ "passwordLabel": "Contraseña",
+ "forgotPassword": "¿Olvidaste tu contraseña?",
+ "passwordPlaceholder": "Ingresa tu contraseña",
+ "signingIn": "Iniciando sesión...",
+ "signIn": "Iniciar sesión",
+ "noAccount": "¿No tienes una cuenta?",
+ "createAccount": "Crear cuenta"
+ },
+ "Sidebar": {
+ "title": "Plantilla de CRM para WhatsApp",
+ "dashboard": "Panel",
+ "inbox": "Bandeja de entrada",
+ "notifications": "Notificaciones",
+ "contacts": "Contactos",
+ "pipelines": "Embudos",
+ "broadcasts": "Difusiones",
+ "automations": "Automatizaciones",
+ "flows": "Flujos",
+ "aiAgents": "Agentes de IA",
+ "settings": "Configuración",
+ "beta": "Beta",
+ "unreadConversations": "{count} {count, plural, =1 {conversación} other {conversaciones}} sin leer",
+ "unreadNotifications": "{count} {count, plural, =1 {notificación} other {notificaciones}} sin leer",
+ "roleOwner": "Propietario",
+ "roleAdmin": "Administrador",
+ "roleAgent": "Agente",
+ "roleViewer": "Espectador",
+ "closeMenu": "Cerrar menú",
+ "defaultUser": "Usuario",
+ "defaultAvatar": "Avatar",
+ "menuProfile": "Perfil",
+ "menuSettings": "Configuración",
+ "menuSignOut": "Cerrar sesión",
+ "primaryNav": "Principal"
+ },
+ "Header": {
+ "dashboard": "Panel",
+ "inbox": "Bandeja de entrada",
+ "notifications": "Notificaciones",
+ "contacts": "Contactos",
+ "pipelines": "Embudos",
+ "broadcasts": "Difusiones",
+ "automations": "Automatizaciones",
+ "settings": "Configuración",
+ "openMenu": "Abrir menú",
+ "openAccountMenu": "Abrir menú de cuenta",
+ "defaultUser": "Usuario",
+ "defaultAvatar": "Avatar",
+ "menuProfile": "Perfil",
+ "menuSettings": "Configuración",
+ "menuSignOut": "Cerrar sesión"
+ },
+ "ModeToggle": {
+ "switchMode": "Cambiar al modo {mode}"
+ },
+ "Dashboard": {
+ "page": {
+ "title": "Panel",
+ "description": "Analíticas en vivo de conversaciones, contactos, negocios, difusiones y automatizaciones.",
+ "activeConversations": "Conversaciones activas",
+ "newContactsToday": "Nuevos contactos hoy",
+ "openDealsValue": "Valor de negocios abiertos",
+ "messagesSentToday": "Mensajes enviados hoy",
+ "newTodayVsYesterday": "nuevos hoy vs. ayer",
+ "vsYesterday": "vs. ayer",
+ "openDeals": "{count} {count, plural, =1 {negocio abierto} other {negocios abiertos}}",
+ "noChange": "Sin cambios {suffix}"
+ },
+ "quickActions": {
+ "newContact": "Nuevo contacto",
+ "newDeal": "Nuevo negocio",
+ "newBroadcast": "Nueva difusión",
+ "newAutomation": "Nueva automatización"
+ },
+ "activityFeed": {
+ "title": "Actividad reciente",
+ "viewAll": "Ver todo →",
+ "noActivity": "Aún no hay actividad",
+ "noActivityHint": "La actividad de mensajes, negocios, difusiones y automatizaciones aparecerá aquí.",
+ "showingOf": "Mostrando {visible} de {totalLoaded}{plus}",
+ "show": "Mostrar",
+ "timeS": "hace {sec}s",
+ "timeM": "hace {min}m",
+ "timeH": "hace {hr}h",
+ "timeD": "hace {day}d"
+ },
+ "conversationsChart": {
+ "title": "Conversaciones a lo largo del tiempo",
+ "description": "Volumen diario de mensajes por dirección",
+ "days": "{count} días",
+ "noActivity": "No hay actividad de mensajes en este rango",
+ "noActivityHint": "Envía o recibe mensajes para empezar a poblar este gráfico.",
+ "incoming": "Entrantes",
+ "outgoing": "Salientes",
+ "tooltipIncoming": "{count} entrantes",
+ "tooltipOutgoing": "{count} salientes",
+ "ariaLabel": "Conversaciones por día"
+ },
+ "pipelineDonut": {
+ "title": "Valor del embudo",
+ "description": "Negocios abiertos por etapa",
+ "noOpenDeals": "Aún no hay negocios abiertos",
+ "noOpenDealsHint": "Crea negocios en Embudos para ver el desglose por etapa aquí.",
+ "dealCount": "{count} {count, plural, =1 {negocio} other {negocios}}",
+ "total": "Total",
+ "ariaLabel": "Valor del embudo por etapa"
+ },
+ "responseTimeChart": {
+ "title": "Tiempo promedio de primera respuesta",
+ "description": "Minutos para responder el primer mensaje sin contestar de un cliente, por día de la semana",
+ "target": "objetivo {minutes}m",
+ "thisWeek": "Esta semana:",
+ "lastWeek": "Semana pasada:",
+ "noReplies": "Aún no se han registrado respuestas",
+ "noRepliesHint": "Este gráfico se completa a medida que respondes los mensajes de los clientes."
+ },
+ "emptyState": {
+ "title": "Aún no hay datos suficientes"
+ }
+ },
+ "Inbox": {
+ "page": {
+ "whatsappNotConnected": "WhatsApp® no está conectado. Ve a Configuración para conectar tu cuenta."
+ },
+ "conversationList": {
+ "searchPlaceholder": "Buscar conversaciones...",
+ "filterAll": "Todas",
+ "filterUnread": "Sin leer",
+ "filterOpen": "Abiertas",
+ "filterPending": "Pendientes",
+ "filterClosed": "Cerradas",
+ "tags": "Etiquetas",
+ "company": "Empresa",
+ "allCompanies": "Todas las empresas",
+ "clearAll": "Limpiar todo",
+ "noConversations": "No se encontraron conversaciones",
+ "noMessagesYet": "Aún no hay mensajes",
+ "unknown": "Desconocido"
+ },
+ "messageThread": {
+ "backToConversations": "Volver a las conversaciones",
+ "hideContactPanel": "Ocultar panel de contacto",
+ "showContactPanel": "Mostrar panel de contacto",
+ "hideContact": "Ocultar contacto",
+ "showContact": "Mostrar contacto",
+ "refresh": "Actualizar",
+ "refreshConversation": "Actualizar conversación",
+ "status": "Estado",
+ "statusOpen": "Abierta",
+ "statusPending": "Pendiente",
+ "statusClosed": "Cerrada",
+ "assign": "Asignar",
+ "assigned": "Asignada",
+ "unassign": "Quitar asignación",
+ "noTeammates": "No hay compañeros disponibles",
+ "me": " (yo)",
+ "noMessagesYet": "Aún no hay mensajes",
+ "sendTemplateHint": "Envía una plantilla para iniciar la conversación",
+ "selectConversation": "Selecciona una conversación",
+ "selectConversationHint": "Elige una conversación de la izquierda para empezar a chatear",
+ "today": "Hoy",
+ "yesterday": "Ayer",
+ "toastSendFailed": "No se pudo enviar: {reason}",
+ "toastSendTemplateFailed": "No se pudo enviar la plantilla: {reason}",
+ "toastWaitForSend": "Espera a que el mensaje termine de enviarse",
+ "toastReactionFailed": "La reacción falló: {reason}",
+ "toastAssignmentFailed": "No se pudo actualizar la asignación"
+ },
+ "sessionTimer": {
+ "expired": "Expirada",
+ "xhRemaining": "{hours}h restantes",
+ "xmRemaining": "{minutes}m restantes",
+ "noCustomerMessages": "No hay mensajes del cliente"
+ },
+ "composer": {
+ "draftHint": "Toca el ✨ para redactar una respuesta con IA — puedes editarla antes de enviar",
+ "sessionExpiredHint": "La sesión de 24 horas expiró. Usa una plantilla para retomar el contacto.",
+ "templates": "Plantillas",
+ "readOnlyPlaceholder": "Solo lectura — los espectadores pueden navegar pero no responder",
+ "sessionExpiredPlaceholder": "Sesión expirada - usa una plantilla",
+ "typeMessagePlaceholder": "Escribe un mensaje... (Shift+Enter para nueva línea)",
+ "readOnlyTitle": "Solo lectura — tu rol no puede enviar mensajes",
+ "recording": "Grabando… {current} / {max}",
+ "cancel": "Cancelar",
+ "stopAndAttach": "Detener y adjuntar",
+ "attachMedia": "Adjuntar archivo",
+ "photo": "Foto",
+ "video": "Video",
+ "document": "Documento",
+ "voiceNote": "Nota de voz",
+ "sendTemplate": "Enviar plantilla",
+ "draftWithAI": "Redactar una respuesta con IA",
+ "addCaption": "Agrega una descripción…",
+ "removeAttachment": "Quitar adjunto",
+ "moreActions": "Más",
+ "interactiveMessage": "Mensaje interactivo",
+ "quickReplies": "Respuestas rápidas",
+ "quickRepliesEmpty": "Aún no hay respuestas rápidas. Agrega algunas en Configuración → Respuestas rápidas.",
+ "saveAsQuickReply": "Guardar como respuesta rápida",
+ "send": "Enviar",
+ "quickReplyNamePrompt": "Nombra esta respuesta rápida:",
+ "quickReplySaved": "Guardada como respuesta rápida.",
+ "quickReplySaveError": "No se pudo guardar la respuesta rápida.",
+ "aiNotConfigured": "La IA aún no está configurada: actívala en Configuración → Asistente de IA.",
+ "draftFailed": "No se pudo redactar una respuesta.",
+ "assistantNoReply": "El asistente no devolvió una respuesta.",
+ "aiUnreachable": "No se pudo conectar con el asistente de IA.",
+ "recordingTooLong": "La grabación es demasiado larga (más de 16 MB).",
+ "voiceUnsupported": "La grabación de voz no es compatible con este navegador.",
+ "micDenied": "Acceso al micrófono denegado o no disponible."
+ },
+ "bubble": {
+ "photo": "Foto",
+ "video": "Video",
+ "audio": "Audio",
+ "unavailable": "{label} no disponible",
+ "document": "Documento",
+ "locationShared": "Ubicación compartida",
+ "template": "Plantilla",
+ "buttonReply": "Respuesta de botón",
+ "interactiveReply": "[Respuesta interactiva]",
+ "unsupported": "[Tipo de mensaje no compatible]",
+ "aiBadge": "IA",
+ "aiBadgeTitle": "Enviado automáticamente por el asistente de IA"
+ },
+ "actions": {
+ "reply": "Responder",
+ "copyText": "Copiar texto",
+ "delete": "Eliminar",
+ "react": "Reaccionar",
+ "reactWith": "Reaccionar con {emoji}",
+ "nothingToCopy": "Nada para copiar",
+ "copied": "Copiado",
+ "copyFailed": "Error al copiar"
+ },
+ "replyQuote": {
+ "photo": "[Foto]",
+ "video": "[Video]",
+ "document": "[Documento]",
+ "audio": "[Audio]",
+ "voiceMessage": "[Mensaje de voz]",
+ "location": "[Ubicación]",
+ "template": "[Plantilla]",
+ "message": "[Mensaje]",
+ "cancelReply": "Cancelar respuesta"
+ },
+ "templatePicker": {
+ "sendTemplate": "Enviar plantilla",
+ "fillPlaceholders": "Completa los campos para generar esta plantilla. Meta requiere que todas las variables estén definidas.",
+ "pickTemplate": "Elige una plantilla de WhatsApp aprobada para enviar a este contacto.",
+ "noApprovedTemplates": "No hay plantillas aprobadas",
+ "noApprovedTemplatesHint": "Aprueba una plantilla en el Administrador de WhatsApp de Meta y luego sincronízala desde Configuración → Plantillas.",
+ "preview": "Vista previa",
+ "headerValuePlaceholder": "Valor para la variable del encabezado",
+ "bodyValuePlaceholder": "Valor para {val}",
+ "urlSuffixValuePlaceholder": "Valor del sufijo de la URL",
+ "finalUrl": "URL final: {url}",
+ "back": "Atrás",
+ "cancel": "Cancelar",
+ "send": "Enviar plantilla"
+ },
+ "sidebar": {
+ "contactInfo": "Información de contacto",
+ "tags": "Etiquetas",
+ "notes": "Notas",
+ "deals": "Negocios",
+ "noTags": "Sin etiquetas",
+ "noDeals": "Sin negocios",
+ "addNotePlaceholder": "Agregar una nota..."
+ },
+ "aiBanner": {
+ "pausedTitle": "El asistente de IA está pausado aquí",
+ "activeText": "El asistente de IA está respondiendo automáticamente",
+ "takeOver": "Tomar el control",
+ "resume": "Reanudar IA",
+ "tookOver": "Has tomado el control de este chat.",
+ "resumed": "IA reanudada.",
+ "updateError": "No se pudo actualizar el asistente de IA.",
+ "networkError": "No se pudo conectar con el servidor."
+ }
+ },
+ "Contacts": {
+ "page": {
+ "title": "Contactos",
+ "subtitle": "Administra tu lista de contactos. {count} contactos en total.",
+ "subtitleZero": "Administra tu lista de contactos.",
+ "customFieldsBtn": "Campos personalizados",
+ "importBtn": "Importar",
+ "addContactBtn": "Agregar contacto",
+ "searchPlaceholder": "Buscar por nombre, teléfono o correo...",
+ "filterByTags": "Filtrar por etiquetas",
+ "clearAll": "Limpiar todo",
+ "noTagsYet": "Aún no hay etiquetas.",
+ "selectedCount": "{count} seleccionados",
+ "clearSelection": "Limpiar",
+ "deleteSelected": "Eliminar seleccionados",
+ "tableColumns": {
+ "name": "Nombre",
+ "phone": "Teléfono",
+ "email": "Correo electrónico",
+ "company": "Empresa",
+ "tags": "Etiquetas",
+ "createdAt": "Creado"
+ },
+ "loading": "Cargando contactos...",
+ "noContactsMatch": "Ningún contacto coincide con tus filtros.",
+ "noContactsYet": "Aún no hay contactos.",
+ "addFirstContact": "Agrega tu primer contacto",
+ "unnamed": "Sin nombre",
+ "editAction": "Editar",
+ "deleteAction": "Eliminar",
+ "showingPagination": "Mostrando {start}-{end} de {total}",
+ "pageCount": "Página {page} de {total}",
+ "deleteContactTitle": "Eliminar contacto",
+ "deleteContactDesc": "¿Seguro que quieres eliminar a {name}? Esta acción no se puede deshacer.",
+ "cancel": "Cancelar",
+ "deleteBtn": "Eliminar",
+ "deleteBulkTitle": "Eliminar contactos",
+ "deleteBulkDesc": "¿Seguro que quieres eliminar los {count} contactos seleccionados? Esta acción no se puede deshacer.",
+ "toastFailedLoad": "No se pudieron cargar los contactos",
+ "toastFailedDelete": "No se pudo eliminar el contacto",
+ "toastDeleted": "Contacto eliminado",
+ "toastBulkFailedDelete": "No se pudieron eliminar los contactos",
+ "toastBulkDeleted": "{count} contactos eliminados",
+ "selectAllAria": "Seleccionar todos los contactos de esta página"
+ },
+ "form": {
+ "addTitle": "Agregar contacto",
+ "addDesc": "Crea un nuevo contacto. El nombre es obligatorio.",
+ "editTitle": "Editar contacto",
+ "editDesc": "Actualiza los datos y las etiquetas del contacto.",
+ "nameLabel": "Nombre",
+ "namePlaceholder": "Juan Pérez",
+ "phoneLabel": "Número de teléfono",
+ "phonePlaceholder": "+1234567890",
+ "phoneHint": "Incluye el código de país, p. ej. +1 para EE. UU.",
+ "emailLabel": "Correo electrónico",
+ "emailPlaceholder": "juan@ejemplo.com",
+ "companyLabel": "Empresa",
+ "companyPlaceholder": "Acme Corp",
+ "tagsLabel": "Etiquetas",
+ "tagsPlaceholder": "Selecciona etiquetas...",
+ "noTagsFound": "No se encontraron etiquetas.",
+ "createTagAction": "Crear etiqueta \"{value}\"",
+ "cancel": "Cancelar",
+ "save": "Guardar contacto",
+ "update": "Actualizar",
+ "create": "Crear",
+ "toastSuccessAdd": "Contacto creado correctamente",
+ "toastSuccessEdit": "Contacto actualizado correctamente",
+ "toastError": "No se pudo guardar el contacto",
+ "toastConflict": "Ya existe un contacto con este número de teléfono",
+ "viewExisting": "Ver {name}",
+ "dupExact": "Ya existe un contacto con este número de teléfono.",
+ "dupSimilar": "Ya existe un contacto con un número muy similar.",
+ "loadingTags": "Cargando etiquetas...",
+ "noTagsAvailable": "No hay etiquetas disponibles. Crea etiquetas en Configuración.",
+ "phoneRequired": "El número de teléfono es obligatorio"
+ },
+ "detailView": {
+ "tabs": {
+ "details": "Detalles",
+ "activity": "Actividad",
+ "notes": "Notas",
+ "custom": "Campos personalizados",
+ "deals": "Negocios",
+ "tags": "Etiquetas",
+ "noTags": "Sin etiquetas",
+ "noDeals": "Sin negocios",
+ "addNotePlaceholder": "Agregar una nota..."
+ },
+ "actions": {
+ "edit": "Editar",
+ "message": "Mensaje",
+ "delete": "Eliminar"
+ },
+ "contactInfo": "Información de contacto",
+ "unnamed": "Desconocido",
+ "contactDetailsDesc": "Detalles del contacto",
+ "phone": "Teléfono",
+ "email": "Correo electrónico",
+ "company": "Empresa",
+ "createdAt": "Fecha de creación",
+ "customFields": "Campos personalizados",
+ "noCustomFields": "No hay campos personalizados definidos. Créalos en Configuración.",
+ "manageFields": "Administrar campos",
+ "enterCustomField": "Ingresa {name}...",
+ "activityTab": {
+ "title": "Historial de actividad",
+ "noActivity": "Aún no hay actividad."
+ },
+ "notesTab": {
+ "title": "Notas internas",
+ "placeholder": "Escribe una nota...",
+ "save": "Agregar nota",
+ "noNotes": "Aún no hay notas."
+ },
+ "dealsTab": {
+ "noDeals": "Aún no hay negocios"
+ },
+ "tagsTab": {
+ "clickTagDesc": "Haz clic en una etiqueta para agregarla o quitarla de este contacto.",
+ "noTagsAvailable": "No hay etiquetas disponibles. Crea etiquetas en Configuración."
+ },
+ "sendTemplateBtn": "Enviar plantilla",
+ "saveChangesBtn": "Guardar cambios",
+ "saveCustomFieldsBtn": "Guardar campos personalizados",
+ "toastPhoneRequired": "El número de teléfono es obligatorio",
+ "toastUpdateFailed": "No se pudo actualizar el contacto",
+ "toastUpdated": "Contacto actualizado",
+ "toastNotAuthenticated": "No autenticado",
+ "toastNoteAddFailed": "No se pudo agregar la nota",
+ "toastNoteAdded": "Nota agregada",
+ "toastNoteDeleteFailed": "No se pudo eliminar la nota",
+ "toastNoteDeleted": "Nota eliminada",
+ "toastCustomFieldsSaved": "Campos personalizados guardados",
+ "toastCustomFieldsFailed": "No se pudieron guardar los campos personalizados",
+ "toastTemplateSent": "Plantilla \"{name}\" enviada",
+ "toastTemplateFailed": "No se pudo enviar la plantilla: {reason}"
+ },
+ "importModal": {
+ "title": "Importar contactos",
+ "desc": "Sube un CSV con una columna en_US y en son distintos.",
+ "header": "Encabezado",
+ "headerNone": "Ninguno",
+ "headerText": "Texto",
+ "headerImage": "Imagen",
+ "headerVideo": "Video",
+ "headerDocument": "Documento",
+ "headerTextPlaceholder": "Texto del encabezado (máx. 60 caracteres, opcional {{1}})",
+ "headerSampleAria": "Valor de ejemplo para la variable del encabezado",
+ "headerSamplePlaceholder": "Valor de ejemplo para {{1}} (requerido para la revisión de Meta)",
+ "uploadImage": "Subir imagen",
+ "uploadHint": "JPEG o PNG, ≤5 MB",
+ "mediaUrlPlaceholder": "https://… (o pega un enlace público de {format})",
+ "imageHint": "Sube un JPEG/PNG (≤5 MB, ≥800×418 px recomendado) o pega un enlace HTTPS público — lo subimos a Meta para su revisión automáticamente.",
+ "mediaHint": "Debe ser un enlace HTTPS de acceso público. Meta lo obtiene una vez durante la revisión, así que debe permanecer activo durante ~24 h.",
+ "videoHint": " Recomendado: MP4 / 3GPP, ≤16 MB, ≤60 segundos.",
+ "documentHint": " Recomendado: PDF, ≤100 MB.",
+ "bodyText": "Texto del cuerpo",
+ "bodyPlaceholder": "Hola {{1}}, tu pedido {{2}} está confirmado.",
+ "bodyHint": "Usa {{1}}, {{2}} para las variables (deben ser contiguas empezando en {{1}}).",
+ "sampleValues": "Valores de ejemplo (Meta los usa para revisar tu plantilla)",
+ "sampleAria": "Valor de ejemplo para la variable del cuerpo {var}",
+ "samplePlaceholder": "Ejemplo para {var}",
+ "footer": "Pie de página (opcional)",
+ "footerPlaceholder": "Texto de pie de página opcional (máx. 60 caracteres)",
+ "buttons": "Botones (opcional)",
+ "addButton": "Agregar botón",
+ "buttonsLimit": "Hasta {max} botones. Los botones de RESPUESTA RÁPIDA deben ir antes de los botones de URL / teléfono / copiar código.",
+ "btnQuickReply": "Respuesta rápida",
+ "btnUrl": "URL",
+ "btnPhone": "Teléfono",
+ "btnCopyCode": "Copiar código",
+ "btnLabelPlaceholder": "Etiqueta del botón",
+ "urlPlaceholder": "https://ejemplo.com/ruta o con sufijo {{1}}",
+ "urlSamplePlaceholder": "Valor de ejemplo para {{1}} (requerido cuando la URL tiene una variable)",
+ "phonePlaceholder": "+15551234567",
+ "codePlaceholder": "Código de ejemplo (p. ej. VERANO20)",
+ "cancel": "Cancelar",
+ "saving": "Guardando…",
+ "submitting": "Enviando…",
+ "saveResubmit": "Guardar y reenviar",
+ "submitApproval": "Enviar para aprobación",
+ "deleteDialogTitle": "¿Eliminar plantilla?",
+ "deleteMetaDesc": "\"{name}\" se eliminará de Meta y de wacrm. Las difusiones activas que usen esta plantilla empezarán a fallar en su próximo envío. Esto no se puede deshacer.",
+ "deleteLocalDesc": "\"{name}\" se eliminará de wacrm. Nunca se envió a Meta, así que no se necesita limpieza remota.",
+ "deleting": "Eliminando…",
+ "delete": "Eliminar",
+ "toastLoadFailed": "No se pudieron cargar las plantillas",
+ "toastSubmitFailed": "No se pudo enviar",
+ "toastSubmitEditSuccess": "Edición enviada — Meta normalmente revisa en un plazo de 24 horas.",
+ "toastSubmitNewSuccess": "Enviada a Meta — el tiempo de revisión típico es de 24 horas. El estado se actualiza automáticamente.",
+ "toastSaveEditDry": "Plantilla actualizada (simulación — sin llamada a Meta)",
+ "toastSaveNewDry": "Plantilla guardada (simulación — sin llamada a Meta)",
+ "toastSyncCount": "Se sincronizaron {total} {total, plural, =1 {plantilla} other {plantillas}} desde Meta",
+ "toastSyncDetails": " ({inserted} nuevas, {updated} actualizadas)",
+ "toastSyncFailed": "No se pudo sincronizar: {preview}",
+ "toastSyncTruncated": "Se sincronizaron solo las primeras 2000 plantillas — tu cuenta tiene más. Vuelve a sincronizar para continuar, o contacta a soporte si esto persiste.",
+ "toastSyncError": "No se pudieron sincronizar las plantillas",
+ "toastDeleteSuccess": "Plantilla eliminada",
+ "toastDeleteError": "No se pudo eliminar la plantilla",
+ "toastInvalidImage": "La imagen del encabezado debe ser JPEG o PNG.",
+ "toastImageTooLarge": "La imagen pesa {size} MB — el límite de Meta es 5 MB.",
+ "toastUploadSuccess": "Imagen subida.",
+ "toastUploadFailed": "Error al subir."
+ },
+ "roles": {
+ "admin": "Administrador",
+ "adminHint": "Administrar miembros + todo",
+ "agent": "Agente",
+ "agentHint": "Usar funciones; sin configuración",
+ "viewer": "Espectador",
+ "viewerHint": "Solo lectura en toda la aplicación",
+ "owner": "Propietario",
+ "ownerHint": "Control total sobre la cuenta y la facturación"
+ },
+ "whatsapp": {
+ "title": "Conexión de WhatsApp",
+ "description": "Conecta tu API de WhatsApp Business de Meta. Las credenciales, el webhook y los pasos de configuración están todos aquí.",
+ "tokenCorrupted": "El token almacenado no se puede descifrar",
+ "resetting": "Restableciendo...",
+ "resetConfig": "Restablecer configuración",
+ "credentialsValid": "Credenciales válidas",
+ "notConnected": "No conectado",
+ "connectedDesc": "Tu token de acceso te autentica con Meta. Consulta el estado de registro abajo para saber si los webhooks están realmente conectados.",
+ "notConnectedDesc": "Configura tus credenciales de la API de Meta abajo para conectar tu cuenta de WhatsApp Business.",
+ "registered": "Registrado — Meta entregará eventos a wacrm",
+ "notRegistered": "No registrado — Meta no entregará eventos",
+ "verifyWithMeta": "Verificar con Meta",
+ "subscribedSince": "Suscrito desde {date}. Haz clic en Verificar con Meta si los eventos dejan de llegar.",
+ "unknownDate": "desconocida",
+ "lastAttemptFailed": "El último intento falló con: ",
+ "retryHint": "Ingresa (o corrige) el PIN de 2 pasos abajo y haz clic en Guardar configuración para reintentar.",
+ "noRegistrationHint": "Este número se guardó antes de que existiera el seguimiento de registro, o se omitió el registro. Ingresa el PIN de 2 pasos abajo y haz clic en Guardar configuración para suscribirlo.",
+ "diagnosticLastRun": "Diagnóstico — última ejecución: ",
+ "live": "activo",
+ "notLive": "no activo",
+ "apiCredentialsTitle": "Credenciales de la API",
+ "apiCredentialsDesc": "Ingresa las credenciales de tu API de WhatsApp Business de Meta.",
+ "phoneNumberId": "ID del número de teléfono",
+ "wabaId": "ID de la Cuenta de WhatsApp Business",
+ "accessToken": "Token de acceso permanente",
+ "accessTokenPlaceholder": "Ingresa tu token de acceso",
+ "tokenHidden": "El token está oculto por seguridad. Vuelve a ingresarlo para actualizar la configuración.",
+ "webhookVerifyToken": "Token de verificación del webhook",
+ "webhookVerifyTokenPlaceholder": "Crea un token de verificación personalizado",
+ "webhookVerifyTokenHint": "Una cadena personalizada que tú creas. Debe coincidir con el token que definiste en la configuración del webhook de Meta.",
+ "twoStepPin": "PIN de verificación en dos pasos",
+ "optional": "(opcional)",
+ "pinPlaceholder": "PIN de 6 dígitos del Administrador de WhatsApp de Meta",
+ "pinHint": "Solo se necesita para conectar los mensajes entrantes de un número de producción. Configúralo en Meta Business Manager → Cuentas de WhatsApp → Números de teléfono → Verificación en dos pasos, luego pégalo aquí para que wacrm pueda suscribir el número — de lo contrario, Meta enruta los eventos entrantes a la última aplicación que lo reclamó (el síntoma que afecta a los segundos números bajo una WABA compartida). Los números de prueba de Meta no tienen PIN y están preregistrados — déjalo en blanco para ellos. Dejarlo en blanco también mantiene sin cambios un registro existente.",
+ "webhookTitle": "Configuración del webhook",
+ "webhookDesc": "Usa esta URL como tu callback de webhook en el Panel de aplicaciones de Meta.",
+ "webhookUrl": "URL de callback del webhook",
+ "saving": "Guardando...",
+ "saveConfig": "Guardar configuración",
+ "testing": "Probando...",
+ "testConnection": "Probar conexión de la API",
+ "setupInstructions": "Instrucciones de configuración",
+ "setupInstructionsDesc": "Sigue estos pasos para conectar tu API de WhatsApp Business.",
+ "step1": "Crea una aplicación de Meta",
+ "step1_1": "Ve a developers.facebook.com",
+ "step1_2": "Haz clic en \"Mis aplicaciones\" y luego en \"Crear aplicación\"",
+ "step1_3": "Selecciona \"Negocios\" como tipo de aplicación",
+ "step1_4": "Completa los detalles de la aplicación y créala",
+ "step2": "Agrega el producto WhatsApp",
+ "step2_1": "En el panel de tu aplicación, haz clic en \"Agregar producto\"",
+ "step2_2": "Busca \"WhatsApp\" y haz clic en \"Configurar\"",
+ "step2_3": "Sigue el asistente de configuración para vincular tu negocio",
+ "step3": "Obtén las credenciales de la API",
+ "step3_1": "Ve a WhatsApp > Configuración de la API",
+ "step3_2": "Copia tu ID del número de teléfono",
+ "step3_3": "Copia tu ID de la Cuenta de WhatsApp Business",
+ "step3_4": "Genera un Token de acceso permanente desde Configuración del negocio > Usuarios del sistema",
+ "step4": "Configura los webhooks",
+ "step4_1": "Ve a WhatsApp > Configuración",
+ "step4_2": "Haz clic en \"Editar\" en la sección de Webhook",
+ "step4_3": "Pega la URL de callback del webhook de arriba",
+ "step4_4": "Ingresa el mismo Token de verificación que definiste aquí",
+ "step4_5": "Suscríbete al campo de webhook \"messages\"",
+ "metaDocs": "Documentación de la API de WhatsApp de Meta",
+ "phoneNumberIdRequired": "El ID del número de teléfono es obligatorio",
+ "accessTokenRequired": "El token de acceso es obligatorio para la configuración inicial",
+ "loadFailed": "No se pudo cargar la configuración de WhatsApp",
+ "saveFailed": "No se pudo guardar la configuración",
+ "reenterToken": "Vuelve a ingresar el token de acceso para guardar los cambios",
+ "savedRegisterFailed": "Se guardó, pero Meta no pudo registrar el número: {error}",
+ "savedRegisterSkipped": "Credenciales guardadas y verificadas. Se omitió el registro de entrada (sin PIN) — consulta el estado de registro abajo.",
+ "savedLive": "Activo — {name} ya puede recibir eventos.",
+ "savedConnected": "WhatsApp conectado. Los eventos comenzarán a llegar en un minuto.",
+ "connectedTo": "Conectado a {name}",
+ "connectionSuccess": "Conexión con la API exitosa",
+ "connectionFailed": "Error de conexión con la API",
+ "connectionTestFailed": "La prueba de conexión falló. Revisa la red e inténtalo de nuevo.",
+ "numberLive": "El número está totalmente configurado — Meta está entregando eventos.",
+ "numberNotRegistered": "El número no está totalmente registrado. Consulta las verificaciones a continuación para ver qué paso falló.",
+ "verifyEndpointFailed": "No se pudo acceder al endpoint de verificación.",
+ "resetConfirm": "Esto eliminará la configuración actual de WhatsApp para que puedas ingresarla de nuevo. ¿Continuar?",
+ "resetFailed": "No se pudo restablecer la configuración",
+ "resetSuccess": "Configuración eliminada. Ahora puedes volver a ingresar tus credenciales.",
+ "webhookCopied": "URL del webhook copiada al portapapeles",
+ "phoneNumberIdPlaceholder": "ej.: 100234567890123",
+ "wabaIdPlaceholder": "ej.: 100234567890456"
+ },
+ "sections": {
+ "overview": "Resumen",
+ "profile": "Tu perfil",
+ "security": "Inicio de sesión y seguridad",
+ "appearance": "Apariencia",
+ "whatsapp": "WhatsApp",
+ "templates": "Plantillas",
+ "fields": "Campos y etiquetas",
+ "deals": "Negocios y moneda",
+ "members": "Miembros del equipo",
+ "api": "Claves de API",
+ "quick-replies": "Respuestas rápidas"
+ },
+ "groups": {
+ "account": "Cuenta",
+ "workspace": "Espacio de trabajo"
+ },
+ "profile": {
+ "title": "Tu perfil",
+ "description": "Cómo apareces en toda la aplicación. Tu avatar y tu nombre aparecen en el encabezado, la barra lateral y en cualquier lugar donde te vean tus compañeros.",
+ "changePhoto": "Cambiar foto",
+ "uploadPhoto": "Subir foto",
+ "remove": "Quitar",
+ "photoHint": "PNG, JPG, WebP o GIF. Hasta 2 MB.",
+ "displayName": "Nombre visible",
+ "email": "Correo electrónico",
+ "emailChangeHint": "Revisa la bandeja de entrada de GET /api/v1/me para verificar que funciona.",
+ "cancel": "Cancelar",
+ "creating": "Creando…",
+ "createKey": "Crear clave",
+ "copyTitle": "Copia tu clave de API",
+ "copyDesc": "Esta es la única vez que se muestra la clave completa. Guárdala en un lugar seguro — si la pierdes, revócala y crea una nueva.",
+ "apiKeyLabel": "Clave de API",
+ "copy": "Copiar",
+ "copySuccess": "Clave de API copiada",
+ "copyFailed": "Error al copiar — selecciona y copia manualmente",
+ "newKeyTitle": "Nueva clave de API",
+ "newKeyDesc": "Nómbrala según la integración que la usará y otórgale solo los permisos que necesita.",
+ "done": "Listo",
+ "networkError": "No se pudo conectar con el servidor",
+ "scopeDesc": {
+ "messages:send": "Enviar mensajes de WhatsApp",
+ "messages:read": "Leer mensajes y su estado de entrega",
+ "contacts:read": "Listar y leer contactos",
+ "contacts:write": "Crear y actualizar contactos",
+ "conversations:read": "Listar y leer conversaciones",
+ "broadcasts:send": "Lanzar campañas de difusión",
+ "webhooks:manage": "Registrar y gestionar webhooks de eventos salientes"
+ }
+ },
+ "deals": {
+ "title": "Negocios y moneda",
+ "description": "La moneda usada para los nuevos negocios y para los totales del embudo y del panel.",
+ "defaultCurrency": "Moneda predeterminada",
+ "defaultCurrencyDesc": "Los nuevos negocios usan esta moneda de forma predeterminada, y los totales del embudo y del panel se muestran en ella. Los negocios existentes conservan la moneda con la que se guardaron.",
+ "currencyLabel": "Moneda",
+ "adminOnlyHint": "Solo los administradores de la cuenta pueden cambiar la moneda predeterminada.",
+ "save": "Guardar",
+ "saving": "Guardando...",
+ "saveFailed": "No se pudo guardar la moneda predeterminada",
+ "saveSuccess": "Moneda predeterminada actualizada"
+ },
+ "aiConfig": {
+ "title": "Configuración del agente",
+ "description": "Usa tu propia clave de OpenAI o Anthropic. wacrm llama al proveedor directamente con tu clave — sin tarifas de IA por usuario, y tus datos siguen siendo tuyos. Esto impulsa las respuestas redactadas con IA en la bandeja de entrada, el bot de respuesta automática y el Playground.",
+ "adminOnlyConfig": "Solo los administradores y propietarios pueden cambiar la configuración de la IA.",
+ "loadFailed": "No se pudo cargar la configuración de la IA",
+ "providerAndKey": "Proveedor y clave",
+ "encryptionNotice": "Tu clave se cifra en reposo (AES-256-GCM) y nunca se vuelve a mostrar después de guardarla.",
+ "provider": "Proveedor",
+ "model": "Modelo",
+ "apiKey": "Clave de API",
+ "testKey": "Probar clave",
+ "testSuccess": "La clave funciona — el proveedor respondió.",
+ "testRejected": "El proveedor rechazó la solicitud.",
+ "testNetworkError": "No se pudo conectar con el proveedor.",
+ "embeddingsKey": "Clave de embeddings",
+ "optionalSemanticSearch": "(opcional — habilita la búsqueda semántica en la base de conocimiento)",
+ "embeddingsHint": "Una clave de OpenAI usada solo para generar embeddings de tu base de conocimiento (text-embedding-3-small){sameKeyText}. Déjala en blanco para usar la búsqueda por palabras clave. Bórrala para desactivar la búsqueda semántica.",
+ "sameKeyText": " — puede ser la misma clave de arriba",
+ "behaviour": "Comportamiento",
+ "behaviourDesc": "Cuéntale al asistente sobre tu negocio — productos, tono, lo que puede y no puede prometer. Este contexto alimenta tanto los borradores como las respuestas automáticas.",
+ "businessContext": "Contexto e instrucciones del negocio",
+ "promptPlaceholder": "p. ej. Somos Acme, una tienda de equipos de café. Sé cálido y conciso. Nunca cotices precios ni fechas de entrega — transfiere a una persona para eso.",
+ "enableAssistant": "Habilitar asistente de IA",
+ "enableAssistantDesc": "Interruptor principal. Activa el botón “Redactar con IA” en la bandeja de entrada.",
+ "autoReply": "Respuesta automática a mensajes entrantes",
+ "autoReplyDesc": "El bot responde los nuevos mensajes entrantes automáticamente (solo cuando ningún flujo los gestiona y no hay ningún agente asignado). Transfiere a una persona cuando no puede ayudar.",
+ "maxAutoReplies": "Máximo de respuestas automáticas por conversación",
+ "maxAutoRepliesDesc": "Después de esta cantidad de respuestas del bot en un mismo hilo, el bot se queda en silencio.",
+ "handoffTo": "Transferir a",
+ "handoffToDesc": "Cuando el bot no puede ayudar — o alcanza el límite de respuestas — se detiene y enruta el chat aquí, con una nota breve sobre lo que ocurrió.",
+ "handoffQueue": "Cola sin asignar (cualquier agente puede tomarlo)",
+ "remove": "Quitar",
+ "save": "Guardar",
+ "missingModel": "Ingresa un nombre de modelo.",
+ "missingApiKey": "Ingresa tu clave de API.",
+ "saveSuccess": "Asistente de IA guardado.",
+ "saveFailed": "No se pudo guardar.",
+ "removeSuccess": "Configuración de IA eliminada.",
+ "removeFailed": "No se pudo eliminar."
+ },
+ "aiKnowledge": {
+ "loadFailed": "No se pudo cargar la base de conocimiento",
+ "openFailed": "No se pudo abrir el documento",
+ "titleContentRequired": "El título y el contenido son obligatorios.",
+ "saveSuccessNew": "Documento agregado.",
+ "saveSuccessUpdate": "Documento actualizado.",
+ "saveFailed": "No se pudo guardar.",
+ "removeSuccess": "Documento eliminado.",
+ "removeFailed": "No se pudo eliminar.",
+ "reindexSuccess": "Se reindexaron {count} documento(s).",
+ "reindexFailed": "Error al reindexar.",
+ "title": "Base de conocimiento",
+ "description": "Agrega preguntas frecuentes, políticas o detalles de productos. El asistente recupera las partes relevantes al redactar y responder automáticamente, para que pueda responder en lugar de transferir.{searchType}",
+ "semanticSearchOn": " La búsqueda semántica está activada (clave de embeddings definida).",
+ "keywordSearchOn": " Usando búsqueda por palabras clave — agrega una clave de embeddings arriba para la búsqueda semántica.",
+ "noDocs": "Aún no hay documentos.",
+ "editDocTitle": "Título",
+ "editDocTitlePlaceholder": "p. ej. Política de devoluciones y reembolsos",
+ "editDocContent": "Contenido",
+ "editDocContentPlaceholder": "Pega la respuesta de la pregunta frecuente, el texto de la política o los detalles del producto…",
+ "cancel": "Cancelar",
+ "saveDoc": "Guardar documento",
+ "addDoc": "Agregar documento",
+ "reindex": "Reindexar",
+ "reindexTooltip": "Volver a generar embeddings de todos los documentos (p. ej. después de agregar una clave de embeddings)",
+ "loading": "Cargando…"
+ },
+ "sectionsNav": "Secciones de configuración",
+ "quickReplies": {
+ "nameRequired": "Ponle un nombre a la respuesta rápida.",
+ "saveError": "No se pudo guardar la respuesta rápida.",
+ "updated": "Respuesta rápida actualizada.",
+ "created": "Respuesta rápida creada.",
+ "deleteConfirm": "¿Eliminar esta respuesta rápida?",
+ "deleteError": "No se pudo eliminar la respuesta rápida.",
+ "title": "Respuestas rápidas",
+ "description": "Fragmentos reutilizables — texto simple o un mensaje interactivo guardado — que los agentes pueden insertar desde el compositor de la bandeja de entrada.",
+ "newQuickReply": "Nueva respuesta rápida",
+ "empty": "Aún no hay respuestas rápidas. Crea una para reutilizarla en las conversaciones.",
+ "editQuickReply": "Editar respuesta rápida",
+ "nameLabel": "Nombre",
+ "namePlaceholder": "ej.: Horario de atención",
+ "kindText": "Texto",
+ "kindInteractive": "Interactivo",
+ "textPlaceholder": "El texto del mensaje que se insertará",
+ "cancel": "Cancelar",
+ "save": "Guardar"
+ }
+ },
+ "Notifications": {
+ "title": "Notificaciones",
+ "subtitle": "Las conversaciones que otros compañeros te asignan aparecen aquí.",
+ "markAllAsRead": "Marcar todas como leídas",
+ "retry": "Reintentar",
+ "emptyTitle": "Aún no hay notificaciones",
+ "emptyBody": "Verás una alerta aquí cuando alguien te asigne una conversación.",
+ "unread": "Sin leer",
+ "markReadError": "No se pudo marcar la notificación como leída",
+ "markAllError": "No se pudieron marcar todas como leídas"
+ },
+ "Signup": {
+ "title": "Crear cuenta",
+ "titleInvite": "Crear cuenta y unirse",
+ "description": "Comienza con CRM Template for WhatsApp",
+ "descriptionInvite": "Verifica tu correo y luego acepta la invitación para unirte a tu equipo.",
+ "checkEmailTitle": "Revisa tu correo",
+ "checkEmailBodyBefore": "Hemos enviado un enlace de confirmación a",
+ "checkEmailBodyAfter": ". Revisa tu bandeja de entrada y haz clic en el enlace para verificar tu cuenta.",
+ "backToSignIn": "Volver al inicio de sesión",
+ "fullName": "Nombre completo",
+ "fullNamePlaceholder": "Juan Pérez",
+ "email": "Correo electrónico",
+ "password": "Contraseña",
+ "passwordPlaceholder": "Al menos 6 caracteres",
+ "confirmPassword": "Confirmar contraseña",
+ "confirmPasswordPlaceholder": "Repite tu contraseña",
+ "createAccount": "Crear cuenta",
+ "creatingAccount": "Creando cuenta...",
+ "alreadyHaveAccount": "¿Ya tienes una cuenta?",
+ "signIn": "Iniciar sesión",
+ "passwordsDoNotMatch": "Las contraseñas no coinciden",
+ "passwordTooShort": "La contraseña debe tener al menos 6 caracteres"
+ },
+ "ForgotPassword": {
+ "title": "Restablecer contraseña",
+ "description": "Ingresa tu correo y te enviaremos un enlace de restablecimiento",
+ "checkEmailTitle": "Revisa tu correo",
+ "checkEmailBodyBefore": "Hemos enviado un enlace para restablecer la contraseña a",
+ "checkEmailBodyAfter": ". Revisa tu bandeja de entrada.",
+ "backToSignIn": "Volver al inicio de sesión",
+ "email": "Correo electrónico",
+ "sending": "Enviando...",
+ "sendResetLink": "Enviar enlace de restablecimiento"
+ },
+ "Join": {
+ "verifying": "Verificando invitación…",
+ "tryAgain": "Reintentar",
+ "createAccountInstead": "Crear una cuenta nueva",
+ "signIn": "Iniciar sesión",
+ "invitedTo": "Te han invitado a",
+ "joinAs": "Te unirás como",
+ "role": {
+ "admin": "Administrador",
+ "agent": "Agente",
+ "viewer": "Visor"
+ },
+ "linkValidUntil": ". Enlace válido hasta {date}.",
+ "accepting": "Aceptando…",
+ "acceptInvitation": "Aceptar invitación",
+ "acceptHelpBefore": "Al aceptar, tu sesión se traslada a",
+ "acceptHelpAfter": ". Tu cuenta personal vacía creada al registrarte se eliminará.",
+ "conflictTitle": "No puedes unirte a {name} con esta cuenta",
+ "conflictHelpBefore": "Para unirte a",
+ "conflictHelpAfter": ", cierra sesión y regístrate de nuevo con una dirección de correo diferente. El enlace de invitación sigue siendo válido mientras no haya expirado.",
+ "staySignedIn": "Permanecer conectado",
+ "signingOut": "Cerrando sesión…",
+ "signOutDifferentEmail": "Cerrar sesión y usar otro correo",
+ "createAccountAndJoin": "Crear cuenta y unirse",
+ "alreadyHaveAccount": "Ya tengo una cuenta",
+ "fail": {
+ "not_found": {
+ "title": "Invitación no encontrada",
+ "body": "Este enlace no coincide con una invitación válida. Verifica la URL o pide a quien te invitó que te envíe una nueva."
+ },
+ "used": {
+ "title": "Invitación ya utilizada",
+ "body": "Esta invitación ya fue aceptada. Si no fuiste tú, pide al administrador de la cuenta que envíe un enlace nuevo."
+ },
+ "expired": {
+ "title": "Invitación expirada",
+ "body": "Esta invitación ha expirado. Pide al administrador de la cuenta que envíe una nueva — tardan unos segundos en generarse."
+ },
+ "server_error": {
+ "title": "Algo salió mal",
+ "body": "No pudimos verificar esta invitación en este momento. Intenta actualizar la página en un instante."
+ }
+ },
+ "conflictFallback": "Ya estás en otra cuenta. Inicia sesión con un correo diferente para unirte a esta.",
+ "acceptError": "No se pudo aceptar la invitación",
+ "welcomeToast": "Bienvenido al equipo",
+ "serverUnreachable": "No se pudo conectar con el servidor",
+ "signOutError": "No se pudo cerrar sesión. Intenta actualizar la página."
+ },
+ "Agents": {
+ "title": "Agentes de IA",
+ "subtitle": "Tu agente de IA con clave propia — configúralo y luego pruébalo en el playground antes de que responda a los clientes en la bandeja de entrada.",
+ "tabPlayground": "Playground",
+ "tabSetup": "Configuración",
+ "tabUsage": "Uso"
+ },
+ "AiPlayground": {
+ "notConfiguredToast": "Aún no hay ningún agente configurado — completa la Configuración primero.",
+ "noReplyToast": "No se pudo obtener una respuesta.",
+ "unreachableToast": "No se pudo conectar con el agente.",
+ "headerTitle": "Playground",
+ "headerSubtitle": "— prueba las respuestas como si fueras un cliente",
+ "reset": "Restablecer",
+ "emptyTitle": "Envía un mensaje para ver cómo respondería tu agente.",
+ "emptyDescription": "Usa tu base de conocimiento y se comporta exactamente como el bot de respuesta automática — incluida la transferencia.",
+ "goToSetup": "¿Aún no lo configuraste? Ir a la Configuración",
+ "handoffLabel": "Transferiría a una persona aquí",
+ "thinking": "Pensando…",
+ "composerPlaceholder": "Escribe un mensaje de cliente…"
+ },
+ "AiUsage": {
+ "loadError": "Error al cargar el uso",
+ "tokenUsage": "Uso de tokens",
+ "description": "Tokens gastados en tu clave de proveedor por los borradores y el bot de respuesta automática. Solo recuentos — aquí no se almacena ningún contenido de los mensajes.",
+ "lastDays": "Últimos {w} días",
+ "noUsage": "Aún no hay uso de IA en los últimos {n} días.",
+ "noUsageHint": "Esto se completa a medida que el asistente redacta borradores y responde automáticamente.",
+ "totalTokens": "Tokens totales",
+ "llmCalls": "Llamadas de LLM",
+ "autoReply": "Respuesta automática",
+ "drafts": "Borradores",
+ "tokensPerDay": "Tokens por día",
+ "byModel": "Por modelo",
+ "modelUsage": "{tokens} tok · {calls, plural, one {# llamada} other {# llamadas}}",
+ "truncatedNote": "Mostrando una ventana parcial — el uso es lo suficientemente alto como para que aquí solo se resuman los registros más recientes."
+ },
+ "FlowsHeader": {
+ "backToFlows": "Volver a Flujos",
+ "flowNamePlaceholder": "Nombre del flujo",
+ "flowNameLabel": "Nombre del flujo",
+ "unsavedChanges": "Cambios sin guardar — pulsa Guardar para conservarlos",
+ "edited": "Editado",
+ "runs": "Ejecuciones",
+ "delete": "Eliminar",
+ "pause": "Pausar",
+ "activate": "Activar",
+ "fixIssuesBeforeActivating": "Corrige los problemas de abajo antes de activar",
+ "save": "Guardar",
+ "descriptionPlaceholder": "Agrega una breve descripción (interna — los clientes no la ven)",
+ "descriptionLabel": "Descripción del flujo",
+ "statusDraft": "Borrador",
+ "statusActive": "Activo",
+ "statusArchived": "Archivado"
+ },
+ "InteractiveBuilder": {
+ "replyButtons": "Botones de respuesta",
+ "list": "Lista",
+ "body": "Cuerpo",
+ "bodyPlaceholder": "Lo que el cliente lee encima de las opciones",
+ "headerOptional": "Encabezado (opcional)",
+ "footerOptional": "Pie (opcional)",
+ "showReplyIds": "Mostrar IDs de respuesta (avanzado)",
+ "preview": "Vista previa",
+ "buttonsCount": "Botones ({count}/{max})",
+ "buttonLabel": "Etiqueta del botón",
+ "idPlaceholder": "id",
+ "addButton": "Agregar botón",
+ "listButtonLabel": "Etiqueta del botón de la lista",
+ "rowsCount": "Filas ({count}/{max})",
+ "sectionTitleOptional": "Título de la sección (opcional)",
+ "rowTitle": "Título de la fila",
+ "descriptionOptional": "Descripción (opcional)",
+ "addRow": "Agregar fila",
+ "addSection": "Agregar sección"
+ },
+ "InteractivePreview": {
+ "messageBody": "Cuerpo del mensaje…",
+ "button": "Botón",
+ "menu": "Menú"
+ },
+ "FlowTemplates": {
+ "welcome_menu": {
+ "name": "Menú de bienvenida",
+ "description": "Saluda a los clientes que escriben una palabra clave y dirígelos al agente correcto según si son nuevos o ya existentes."
+ },
+ "faq_bot": {
+ "name": "Bot de preguntas frecuentes",
+ "description": "Responde preguntas comunes automáticamente. El cliente elige un tema de una lista; el bot responde y finaliza."
+ },
+ "lead_capture": {
+ "name": "Captura de prospectos",
+ "description": "Saluda a los contactos nuevos, captura nombre + correo + empresa y luego deriva a ventas con las respuestas en la nota."
+ }
+ },
+ "AutomationTemplates": {
+ "welcome_message": {
+ "name": "Mensaje de bienvenida",
+ "description": "Responder automáticamente con un saludo a los contactos por primera vez."
+ },
+ "out_of_office": {
+ "name": "Fuera de oficina",
+ "description": "Responder automáticamente fuera del horario para que nadie quede sin atención."
+ },
+ "lead_qualifier": {
+ "name": "Calificador de prospectos",
+ "description": "Hacer preguntas de calificación para filtrar los prospectos entrantes."
+ },
+ "follow_up_reminder": {
+ "name": "Recordatorio de seguimiento",
+ "description": "Enviar un recordatorio si un contacto no responde en 24 horas."
+ }
+ },
+ "Themes": {
+ "violet": {
+ "name": "Violeta",
+ "description": "La opción predeterminada — segura y un poco divertida."
+ },
+ "emerald": {
+ "name": "Esmeralda",
+ "description": "Con aire de crecimiento, evoca la mensajería sin copiar el verde de WhatsApp."
+ },
+ "cobalt": {
+ "name": "Cobalto",
+ "description": "Azul limpio de SaaS B2B — sereno y con estilo de producto."
+ },
+ "amber": {
+ "name": "Ámbar",
+ "description": "Cálido y amigable — ideal para equipos de pymes."
+ },
+ "rose": {
+ "name": "Rosa",
+ "description": "Audaz y moderno — D2C, economía de creadores, lifestyle."
+ }
+ },
+ "Common": {
+ "loading": "Cargando..."
+ }
+}
diff --git a/messages/pt.json b/messages/pt.json
new file mode 100644
index 0000000000..c1ec7bf014
--- /dev/null
+++ b/messages/pt.json
@@ -0,0 +1,2011 @@
+{
+ "LoginPage": {
+ "titleAccept": "Entre para aceitar",
+ "titleWelcome": "Bem-vindo de volta",
+ "descAccept": "Entre e levaremos você até o convite.",
+ "descWelcome": "Entre na sua conta",
+ "emailLabel": "E-mail",
+ "emailPlaceholder": "voce@exemplo.com",
+ "passwordLabel": "Senha",
+ "forgotPassword": "Esqueceu a senha?",
+ "passwordPlaceholder": "Digite sua senha",
+ "signingIn": "Entrando...",
+ "signIn": "Entrar",
+ "noAccount": "Não tem uma conta?",
+ "createAccount": "Criar conta"
+ },
+ "Sidebar": {
+ "title": "Modelo de CRM para WhatsApp",
+ "dashboard": "Painel",
+ "inbox": "Caixa de entrada",
+ "notifications": "Notificações",
+ "contacts": "Contatos",
+ "pipelines": "Funis",
+ "broadcasts": "Transmissões",
+ "automations": "Automações",
+ "flows": "Fluxos",
+ "aiAgents": "Agentes de IA",
+ "settings": "Configurações",
+ "beta": "Beta",
+ "unreadConversations": "{count} {count, plural, =1 {conversa não lida} other {conversas não lidas}}",
+ "unreadNotifications": "{count} {count, plural, =1 {notificação não lida} other {notificações não lidas}}",
+ "roleOwner": "Proprietário",
+ "roleAdmin": "Administrador",
+ "roleAgent": "Agente",
+ "roleViewer": "Visualizador",
+ "closeMenu": "Fechar menu",
+ "defaultUser": "Usuário",
+ "defaultAvatar": "Avatar",
+ "menuProfile": "Perfil",
+ "menuSettings": "Configurações",
+ "menuSignOut": "Sair",
+ "primaryNav": "Principal"
+ },
+ "Header": {
+ "dashboard": "Painel",
+ "inbox": "Caixa de entrada",
+ "notifications": "Notificações",
+ "contacts": "Contatos",
+ "pipelines": "Funis",
+ "broadcasts": "Transmissões",
+ "automations": "Automações",
+ "settings": "Configurações",
+ "openMenu": "Abrir menu",
+ "openAccountMenu": "Abrir menu da conta",
+ "defaultUser": "Usuário",
+ "defaultAvatar": "Avatar",
+ "menuProfile": "Perfil",
+ "menuSettings": "Configurações",
+ "menuSignOut": "Sair"
+ },
+ "ModeToggle": {
+ "switchMode": "Mudar para o modo {mode}"
+ },
+ "Dashboard": {
+ "page": {
+ "title": "Painel",
+ "description": "Análises em tempo real de conversas, contatos, negócios, transmissões e automações.",
+ "activeConversations": "Conversas Ativas",
+ "newContactsToday": "Novos Contatos Hoje",
+ "openDealsValue": "Valor de Negócios Abertos",
+ "messagesSentToday": "Mensagens Enviadas Hoje",
+ "newTodayVsYesterday": "novos hoje vs. ontem",
+ "vsYesterday": "vs. ontem",
+ "openDeals": "{count} {count, plural, =1 {negócio aberto} other {negócios abertos}}",
+ "noChange": "Sem alteração {suffix}"
+ },
+ "quickActions": {
+ "newContact": "Novo Contato",
+ "newDeal": "Novo Negócio",
+ "newBroadcast": "Nova Transmissão",
+ "newAutomation": "Nova Automação"
+ },
+ "activityFeed": {
+ "title": "Atividade Recente",
+ "viewAll": "Ver tudo →",
+ "noActivity": "Nenhuma atividade ainda",
+ "noActivityHint": "Atividades de mensagens, negócios, transmissões e automações aparecerão aqui.",
+ "showingOf": "Exibindo {visible} de {totalLoaded}{plus}",
+ "show": "Exibir",
+ "timeS": "há {sec}s",
+ "timeM": "há {min}min",
+ "timeH": "há {hr}h",
+ "timeD": "há {day}d"
+ },
+ "conversationsChart": {
+ "title": "Conversas ao Longo do Tempo",
+ "description": "Volume diário de mensagens por direção",
+ "days": "{count} dias",
+ "noActivity": "Nenhuma atividade de mensagens neste período",
+ "noActivityHint": "Envie ou receba mensagens para começar a preencher este gráfico.",
+ "incoming": "Recebidas",
+ "outgoing": "Enviadas",
+ "tooltipIncoming": "{count} recebidas",
+ "tooltipOutgoing": "{count} enviadas",
+ "ariaLabel": "Conversas por dia"
+ },
+ "pipelineDonut": {
+ "title": "Valor do Funil",
+ "description": "Negócios abertos por etapa",
+ "noOpenDeals": "Nenhum negócio aberto ainda",
+ "noOpenDealsHint": "Crie negócios em Funis para ver a distribuição por etapa aqui.",
+ "dealCount": "{count} {count, plural, =1 {negócio} other {negócios}}",
+ "total": "Total",
+ "ariaLabel": "Valor do funil por etapa"
+ },
+ "responseTimeChart": {
+ "title": "Tempo Médio da Primeira Resposta",
+ "description": "Minutos para responder à primeira mensagem sem resposta do cliente, por dia da semana",
+ "target": "meta {minutes}min",
+ "thisWeek": "Esta semana:",
+ "lastWeek": "Semana passada:",
+ "noReplies": "Nenhuma resposta registrada ainda",
+ "noRepliesHint": "Este gráfico é preenchido conforme você responde às mensagens dos clientes."
+ },
+ "emptyState": {
+ "title": "Dados insuficientes ainda"
+ }
+ },
+ "Inbox": {
+ "page": {
+ "whatsappNotConnected": "O WhatsApp® não está conectado. Vá até Configurações para conectar sua conta."
+ },
+ "conversationList": {
+ "searchPlaceholder": "Buscar conversas...",
+ "filterAll": "Todas",
+ "filterUnread": "Não lidas",
+ "filterOpen": "Abertas",
+ "filterPending": "Pendentes",
+ "filterClosed": "Fechadas",
+ "tags": "Etiquetas",
+ "company": "Empresa",
+ "allCompanies": "Todas as empresas",
+ "clearAll": "Limpar tudo",
+ "noConversations": "Nenhuma conversa encontrada",
+ "noMessagesYet": "Nenhuma mensagem ainda",
+ "unknown": "Desconhecido"
+ },
+ "messageThread": {
+ "backToConversations": "Voltar às conversas",
+ "hideContactPanel": "Ocultar painel do contato",
+ "showContactPanel": "Mostrar painel do contato",
+ "hideContact": "Ocultar contato",
+ "showContact": "Mostrar contato",
+ "refresh": "Atualizar",
+ "refreshConversation": "Atualizar conversa",
+ "status": "Status",
+ "statusOpen": "Aberta",
+ "statusPending": "Pendente",
+ "statusClosed": "Fechada",
+ "assign": "Atribuir",
+ "assigned": "Atribuída",
+ "unassign": "Remover atribuição",
+ "noTeammates": "Nenhum colega disponível",
+ "me": " (eu)",
+ "noMessagesYet": "Nenhuma mensagem ainda",
+ "sendTemplateHint": "Envie um modelo para iniciar a conversa",
+ "selectConversation": "Selecione uma conversa",
+ "selectConversationHint": "Escolha uma conversa à esquerda para começar a enviar mensagens",
+ "today": "Hoje",
+ "yesterday": "Ontem",
+ "toastSendFailed": "Falha ao enviar: {reason}",
+ "toastSendTemplateFailed": "Falha ao enviar modelo: {reason}",
+ "toastWaitForSend": "Aguarde a mensagem terminar de enviar",
+ "toastReactionFailed": "Falha na reação: {reason}",
+ "toastAssignmentFailed": "Falha ao atualizar a atribuição"
+ },
+ "sessionTimer": {
+ "expired": "Expirada",
+ "xhRemaining": "{hours}h restantes",
+ "xmRemaining": "{minutes}min restantes",
+ "noCustomerMessages": "Nenhuma mensagem do cliente"
+ },
+ "composer": {
+ "draftHint": "Toque no ✨ para redigir uma resposta com IA — você pode editá-la antes de enviar",
+ "sessionExpiredHint": "Sessão de 24 horas expirada. Use um modelo para reengajar.",
+ "templates": "Modelos",
+ "readOnlyPlaceholder": "Somente leitura — visualizadores podem navegar, mas não responder",
+ "sessionExpiredPlaceholder": "Sessão expirada - use um modelo",
+ "typeMessagePlaceholder": "Digite uma mensagem... (Shift+Enter para nova linha)",
+ "readOnlyTitle": "Somente leitura — seu perfil não pode enviar mensagens",
+ "recording": "Gravando… {current} / {max}",
+ "cancel": "Cancelar",
+ "stopAndAttach": "Parar e anexar",
+ "attachMedia": "Anexar mídia",
+ "photo": "Foto",
+ "video": "Vídeo",
+ "document": "Documento",
+ "voiceNote": "Mensagem de voz",
+ "sendTemplate": "Enviar modelo",
+ "draftWithAI": "Redigir uma resposta com IA",
+ "addCaption": "Adicionar uma legenda…",
+ "removeAttachment": "Remover anexo",
+ "moreActions": "Mais",
+ "interactiveMessage": "Mensagem interativa",
+ "quickReplies": "Respostas rápidas",
+ "quickRepliesEmpty": "Nenhuma resposta rápida ainda. Adicione algumas em Configurações → Respostas rápidas.",
+ "saveAsQuickReply": "Salvar como resposta rápida",
+ "send": "Enviar",
+ "quickReplyNamePrompt": "Dê um nome a esta resposta rápida:",
+ "quickReplySaved": "Salva como resposta rápida.",
+ "quickReplySaveError": "Não foi possível salvar a resposta rápida.",
+ "aiNotConfigured": "A IA ainda não está configurada — ative-a em Configurações → Assistente de IA.",
+ "draftFailed": "Não foi possível rascunhar uma resposta.",
+ "assistantNoReply": "O assistente não retornou uma resposta.",
+ "aiUnreachable": "Não foi possível conectar ao assistente de IA.",
+ "recordingTooLong": "A gravação é muito longa (mais de 16 MB).",
+ "voiceUnsupported": "A gravação de voz não é compatível com este navegador.",
+ "micDenied": "Acesso ao microfone negado ou indisponível."
+ },
+ "bubble": {
+ "photo": "Foto",
+ "video": "Vídeo",
+ "audio": "Áudio",
+ "unavailable": "{label} indisponível",
+ "document": "Documento",
+ "locationShared": "Localização compartilhada",
+ "template": "Modelo",
+ "buttonReply": "Resposta de botão",
+ "interactiveReply": "[Resposta interativa]",
+ "unsupported": "[Tipo de mensagem não suportado]",
+ "aiBadge": "IA",
+ "aiBadgeTitle": "Enviada automaticamente pelo assistente de IA"
+ },
+ "actions": {
+ "reply": "Responder",
+ "copyText": "Copiar texto",
+ "delete": "Excluir",
+ "react": "Reagir",
+ "reactWith": "Reagir com {emoji}",
+ "nothingToCopy": "Nada para copiar",
+ "copied": "Copiado",
+ "copyFailed": "Falha ao copiar"
+ },
+ "replyQuote": {
+ "photo": "[Foto]",
+ "video": "[Vídeo]",
+ "document": "[Documento]",
+ "audio": "[Áudio]",
+ "voiceMessage": "[Mensagem de voz]",
+ "location": "[Localização]",
+ "template": "[Modelo]",
+ "message": "[Mensagem]",
+ "cancelReply": "Cancelar resposta"
+ },
+ "templatePicker": {
+ "sendTemplate": "Enviar modelo",
+ "fillPlaceholders": "Preencha os campos para renderizar este modelo. A Meta exige que todas as variáveis sejam definidas.",
+ "pickTemplate": "Escolha um modelo do WhatsApp aprovado para enviar a este contato.",
+ "noApprovedTemplates": "Nenhum modelo aprovado",
+ "noApprovedTemplatesHint": "Aprove um modelo no Meta WhatsApp Manager e sincronize-o em Configurações → Modelos.",
+ "preview": "Prévia",
+ "headerValuePlaceholder": "Valor para a variável do cabeçalho",
+ "bodyValuePlaceholder": "Valor para {val}",
+ "urlSuffixValuePlaceholder": "Valor do sufixo da URL",
+ "finalUrl": "URL final: {url}",
+ "back": "Voltar",
+ "cancel": "Cancelar",
+ "send": "Enviar modelo"
+ },
+ "sidebar": {
+ "contactInfo": "Informações do contato",
+ "tags": "Etiquetas",
+ "notes": "Notas",
+ "deals": "Negócios",
+ "noTags": "Nenhuma etiqueta",
+ "noDeals": "Nenhum negócio",
+ "addNotePlaceholder": "Adicionar uma nota..."
+ },
+ "aiBanner": {
+ "pausedTitle": "O assistente de IA está pausado aqui",
+ "activeText": "O assistente de IA está respondendo automaticamente",
+ "takeOver": "Assumir",
+ "resume": "Retomar IA",
+ "tookOver": "Você assumiu esta conversa.",
+ "resumed": "IA retomada.",
+ "updateError": "Não foi possível atualizar o assistente de IA.",
+ "networkError": "Não foi possível conectar ao servidor."
+ }
+ },
+ "Contacts": {
+ "page": {
+ "title": "Contatos",
+ "subtitle": "Gerencie sua lista de contatos. {count} contatos no total.",
+ "subtitleZero": "Gerencie sua lista de contatos.",
+ "customFieldsBtn": "Campos personalizados",
+ "importBtn": "Importar",
+ "addContactBtn": "Adicionar Contato",
+ "searchPlaceholder": "Buscar por nome, telefone ou e-mail...",
+ "filterByTags": "Filtrar por etiquetas",
+ "clearAll": "Limpar tudo",
+ "noTagsYet": "Nenhuma etiqueta ainda.",
+ "selectedCount": "{count} selecionados",
+ "clearSelection": "Limpar",
+ "deleteSelected": "Excluir selecionados",
+ "tableColumns": {
+ "name": "Nome",
+ "phone": "Telefone",
+ "email": "E-mail",
+ "company": "Empresa",
+ "tags": "Etiquetas",
+ "createdAt": "Criado em"
+ },
+ "loading": "Carregando contatos...",
+ "noContactsMatch": "Nenhum contato corresponde aos seus filtros.",
+ "noContactsYet": "Nenhum contato ainda.",
+ "addFirstContact": "Adicione seu primeiro contato",
+ "unnamed": "Sem nome",
+ "editAction": "Editar",
+ "deleteAction": "Excluir",
+ "showingPagination": "Exibindo {start}-{end} de {total}",
+ "pageCount": "Página {page} de {total}",
+ "deleteContactTitle": "Excluir Contato",
+ "deleteContactDesc": "Tem certeza de que deseja excluir {name}? Esta ação não pode ser desfeita.",
+ "cancel": "Cancelar",
+ "deleteBtn": "Excluir",
+ "deleteBulkTitle": "Excluir Contatos",
+ "deleteBulkDesc": "Tem certeza de que deseja excluir {count} contatos selecionados? Esta ação não pode ser desfeita.",
+ "toastFailedLoad": "Falha ao carregar contatos",
+ "toastFailedDelete": "Falha ao excluir contato",
+ "toastDeleted": "Contato excluído",
+ "toastBulkFailedDelete": "Falha ao excluir contatos",
+ "toastBulkDeleted": "{count} contatos excluídos",
+ "selectAllAria": "Selecionar todos os contatos desta página"
+ },
+ "form": {
+ "addTitle": "Adicionar Contato",
+ "addDesc": "Crie um novo contato. O nome é obrigatório.",
+ "editTitle": "Editar Contato",
+ "editDesc": "Atualize os detalhes e etiquetas do contato.",
+ "nameLabel": "Nome",
+ "namePlaceholder": "Maria Silva",
+ "phoneLabel": "Número de Telefone",
+ "phonePlaceholder": "+5511999999999",
+ "phoneHint": "Inclua o código do país, ex.: +55 para o Brasil",
+ "emailLabel": "E-mail",
+ "emailPlaceholder": "maria@exemplo.com",
+ "companyLabel": "Empresa",
+ "companyPlaceholder": "Acme Ltda.",
+ "tagsLabel": "Etiquetas",
+ "tagsPlaceholder": "Selecionar etiquetas...",
+ "noTagsFound": "Nenhuma etiqueta encontrada.",
+ "createTagAction": "Criar etiqueta \"{value}\"",
+ "cancel": "Cancelar",
+ "save": "Salvar Contato",
+ "update": "Atualizar",
+ "create": "Criar",
+ "toastSuccessAdd": "Contato criado com sucesso",
+ "toastSuccessEdit": "Contato atualizado com sucesso",
+ "toastError": "Falha ao salvar contato",
+ "toastConflict": "Já existe um contato com este número de telefone",
+ "viewExisting": "Ver {name}",
+ "dupExact": "Já existe um contato com este número de telefone.",
+ "dupSimilar": "Já existe um contato com um número muito parecido.",
+ "loadingTags": "Carregando etiquetas...",
+ "noTagsAvailable": "Nenhuma etiqueta disponível. Crie etiquetas em Configurações.",
+ "phoneRequired": "O número de telefone é obrigatório"
+ },
+ "detailView": {
+ "tabs": {
+ "details": "Detalhes",
+ "activity": "Atividade",
+ "notes": "Notas",
+ "custom": "Campos Personalizados",
+ "deals": "Negócios",
+ "tags": "Etiquetas",
+ "noTags": "Nenhuma etiqueta",
+ "noDeals": "Nenhum negócio",
+ "addNotePlaceholder": "Adicionar uma nota..."
+ },
+ "actions": {
+ "edit": "Editar",
+ "message": "Mensagem",
+ "delete": "Excluir"
+ },
+ "contactInfo": "Informações de Contato",
+ "unnamed": "Desconhecido",
+ "contactDetailsDesc": "Detalhes do contato",
+ "phone": "Telefone",
+ "email": "E-mail",
+ "company": "Empresa",
+ "createdAt": "Criado Em",
+ "customFields": "Campos Personalizados",
+ "noCustomFields": "Nenhum campo personalizado definido. Crie-os em Configurações.",
+ "manageFields": "Gerenciar campos",
+ "enterCustomField": "Insira {name}...",
+ "activityTab": {
+ "title": "Histórico de Atividades",
+ "noActivity": "Nenhuma atividade ainda."
+ },
+ "notesTab": {
+ "title": "Notas Internas",
+ "placeholder": "Escreva uma nota...",
+ "save": "Adicionar Nota",
+ "noNotes": "Nenhuma nota ainda."
+ },
+ "dealsTab": {
+ "noDeals": "Nenhum negócio ainda"
+ },
+ "tagsTab": {
+ "clickTagDesc": "Clique em uma etiqueta para adicioná-la ou removê-la deste contato.",
+ "noTagsAvailable": "Nenhuma etiqueta disponível. Crie etiquetas em Configurações."
+ },
+ "sendTemplateBtn": "Enviar modelo",
+ "saveChangesBtn": "Salvar Alterações",
+ "saveCustomFieldsBtn": "Salvar Campos Personalizados",
+ "toastPhoneRequired": "O número de telefone é obrigatório",
+ "toastUpdateFailed": "Falha ao atualizar contato",
+ "toastUpdated": "Contato atualizado",
+ "toastNotAuthenticated": "Não autenticado",
+ "toastNoteAddFailed": "Falha ao adicionar nota",
+ "toastNoteAdded": "Nota adicionada",
+ "toastNoteDeleteFailed": "Falha ao excluir nota",
+ "toastNoteDeleted": "Nota excluída",
+ "toastCustomFieldsSaved": "Campos personalizados salvos",
+ "toastCustomFieldsFailed": "Falha ao salvar campos personalizados",
+ "toastTemplateSent": "Modelo \"{name}\" enviado",
+ "toastTemplateFailed": "Falha ao enviar modelo: {reason}"
+ },
+ "importModal": {
+ "title": "Importar Contatos",
+ "desc": "Envie um CSV com uma coluna en_US e en são distintos.",
+ "header": "Cabeçalho",
+ "headerNone": "Nenhum",
+ "headerText": "Texto",
+ "headerImage": "Imagem",
+ "headerVideo": "Vídeo",
+ "headerDocument": "Documento",
+ "headerTextPlaceholder": "Texto do cabeçalho (máx. 60 caracteres, {{1}} opcional)",
+ "headerSampleAria": "Valor de exemplo para a variável do cabeçalho",
+ "headerSamplePlaceholder": "Valor de exemplo para {{1}} (obrigatório para a análise da Meta)",
+ "uploadImage": "Enviar imagem",
+ "uploadHint": "JPEG ou PNG, ≤5 MB",
+ "mediaUrlPlaceholder": "https://… (ou cole um link público de {format})",
+ "imageHint": "Envie um JPEG/PNG (≤5 MB, ≥800×418 px recomendado) ou cole um link HTTPS público — nós o enviamos à Meta para análise automaticamente.",
+ "mediaHint": "Deve ser um link HTTPS publicamente acessível. A Meta o busca uma vez durante a análise, então ele precisa permanecer ativo por ~24 h.",
+ "videoHint": " Recomendado: MP4 / 3GPP, ≤16 MB, ≤60 segundos.",
+ "documentHint": " Recomendado: PDF, ≤100 MB.",
+ "bodyText": "Texto do Corpo",
+ "bodyPlaceholder": "Olá {{1}}, seu pedido {{2}} está confirmado.",
+ "bodyHint": "Use {{1}}, {{2}} para variáveis (devem ser contíguas, começando em {{1}}).",
+ "sampleValues": "Valores de exemplo (a Meta os usa para analisar seu modelo)",
+ "sampleAria": "Valor de exemplo para a variável do corpo {var}",
+ "samplePlaceholder": "Exemplo para {var}",
+ "footer": "Rodapé (opcional)",
+ "footerPlaceholder": "Texto de rodapé opcional (máx. 60 caracteres)",
+ "buttons": "Botões (opcional)",
+ "addButton": "Adicionar Botão",
+ "buttonsLimit": "Até {max} botões. Botões de RESPOSTA RÁPIDA devem vir antes dos botões de URL / telefone / copiar código.",
+ "btnQuickReply": "Resposta Rápida",
+ "btnUrl": "URL",
+ "btnPhone": "Telefone",
+ "btnCopyCode": "Copiar Código",
+ "btnLabelPlaceholder": "Rótulo do botão",
+ "urlPlaceholder": "https://exemplo.com/caminho ou com sufixo {{1}}",
+ "urlSamplePlaceholder": "Valor de exemplo para {{1}} (obrigatório quando a URL tem uma variável)",
+ "phonePlaceholder": "+5511999999999",
+ "codePlaceholder": "Código de exemplo (ex.: VERAO20)",
+ "cancel": "Cancelar",
+ "saving": "Salvando…",
+ "submitting": "Enviando…",
+ "saveResubmit": "Salvar e Reenviar",
+ "submitApproval": "Enviar para Aprovação",
+ "deleteDialogTitle": "Excluir modelo?",
+ "deleteMetaDesc": "\"{name}\" será excluído da Meta e do wacrm. Transmissões ativas que usam este modelo começarão a falhar no próximo envio. Isso não pode ser desfeito.",
+ "deleteLocalDesc": "\"{name}\" será excluído do wacrm. Ele nunca foi enviado à Meta, então nenhuma limpeza remota é necessária.",
+ "deleting": "Excluindo…",
+ "delete": "Excluir",
+ "toastLoadFailed": "Falha ao carregar modelos",
+ "toastSubmitFailed": "Falha ao enviar",
+ "toastSubmitEditSuccess": "Edição enviada — a Meta normalmente analisa em até 24 horas.",
+ "toastSubmitNewSuccess": "Enviado à Meta — o tempo de análise típico é de 24 horas. O status é atualizado automaticamente.",
+ "toastSaveEditDry": "Modelo atualizado (simulação — nenhuma chamada à Meta)",
+ "toastSaveNewDry": "Modelo salvo (simulação — nenhuma chamada à Meta)",
+ "toastSyncCount": "Sincronizados {total} {total, plural, =1 {modelo} other {modelos}} da Meta",
+ "toastSyncDetails": " ({inserted} novos, {updated} atualizados)",
+ "toastSyncFailed": "Falha ao sincronizar: {preview}",
+ "toastSyncTruncated": "Sincronizados apenas os primeiros 2000 modelos — sua conta tem mais. Sincronize novamente para continuar, ou contate o suporte se isso persistir.",
+ "toastSyncError": "Falha ao sincronizar modelos",
+ "toastDeleteSuccess": "Modelo excluído",
+ "toastDeleteError": "Falha ao excluir modelo",
+ "toastInvalidImage": "A imagem do cabeçalho deve ser JPEG ou PNG.",
+ "toastImageTooLarge": "A imagem tem {size} MB — o limite da Meta é 5 MB.",
+ "toastUploadSuccess": "Imagem enviada.",
+ "toastUploadFailed": "Falha no envio."
+ },
+ "roles": {
+ "admin": "Administrador",
+ "adminHint": "Gerencia membros + tudo",
+ "agent": "Agente",
+ "agentHint": "Usa recursos; sem configurações",
+ "viewer": "Visualizador",
+ "viewerHint": "Somente leitura em todo o app",
+ "owner": "Proprietário",
+ "ownerHint": "Controle total sobre conta e faturamento"
+ },
+ "whatsapp": {
+ "title": "Conexão do WhatsApp",
+ "description": "Conecte sua API do WhatsApp Business da Meta. Credenciais, webhook e etapas de configuração ficam todos aqui.",
+ "tokenCorrupted": "O token armazenado não pode ser descriptografado",
+ "resetting": "Redefinindo...",
+ "resetConfig": "Redefinir Configuração",
+ "credentialsValid": "Credenciais válidas",
+ "notConnected": "Não Conectado",
+ "connectedDesc": "Seu token de acesso autentica com a Meta. Veja o status de Registro abaixo para saber se os webhooks estão realmente configurados.",
+ "notConnectedDesc": "Configure suas credenciais da API da Meta abaixo para conectar sua conta do WhatsApp Business.",
+ "registered": "Registrado — a Meta entregará eventos ao wacrm",
+ "notRegistered": "Não registrado — a Meta não entregará eventos",
+ "verifyWithMeta": "Verificar com a Meta",
+ "subscribedSince": "Inscrito desde {date}. Clique em Verificar com a Meta se os eventos pararem de chegar.",
+ "unknownDate": "desconhecida",
+ "lastAttemptFailed": "A última tentativa falhou com: ",
+ "retryHint": "Insira (ou corrija) o PIN de verificação em 2 etapas abaixo e clique em Salvar Configuração para tentar novamente.",
+ "noRegistrationHint": "Este número foi salvo antes de existir o rastreamento de registro, ou o registro foi ignorado. Insira o PIN de verificação em 2 etapas abaixo e clique em Salvar Configuração para inscrevê-lo.",
+ "diagnosticLastRun": "Diagnóstico — última execução: ",
+ "live": "ativo",
+ "notLive": "inativo",
+ "apiCredentialsTitle": "Credenciais da API",
+ "apiCredentialsDesc": "Insira suas credenciais da API do WhatsApp Business da Meta.",
+ "phoneNumberId": "ID do Número de Telefone",
+ "wabaId": "ID da Conta do WhatsApp Business",
+ "accessToken": "Token de Acesso Permanente",
+ "accessTokenPlaceholder": "Insira seu token de acesso",
+ "tokenHidden": "O token está oculto por segurança. Insira-o novamente para atualizar a configuração.",
+ "webhookVerifyToken": "Token de Verificação do Webhook",
+ "webhookVerifyTokenPlaceholder": "Crie um token de verificação personalizado",
+ "webhookVerifyTokenHint": "Uma string personalizada que você cria. Deve corresponder ao token definido nas configurações de webhook da Meta.",
+ "twoStepPin": "PIN de verificação em duas etapas",
+ "optional": "(opcional)",
+ "pinPlaceholder": "PIN de 6 dígitos do Meta WhatsApp Manager",
+ "pinHint": "Necessário apenas para configurar mensagens recebidas de um número de produção. Defina-o em Meta Business Manager → Contas do WhatsApp → Números de Telefone → Verificação em duas etapas, depois cole-o aqui para que o wacrm possa inscrever o número — caso contrário, a Meta encaminha os eventos recebidos para qualquer app que o reivindicou por último (o sintoma que afeta números secundários sob uma WABA compartilhada). Números de teste da Meta não têm PIN e são pré-registrados — deixe em branco para eles. Deixar em branco também mantém um registro existente intacto.",
+ "webhookTitle": "Configuração do Webhook",
+ "webhookDesc": "Use esta URL como seu callback de webhook no Painel de Apps da Meta.",
+ "webhookUrl": "URL de Callback do Webhook",
+ "saving": "Salvando...",
+ "saveConfig": "Salvar Configuração",
+ "testing": "Testando...",
+ "testConnection": "Testar Conexão da API",
+ "setupInstructions": "Instruções de Configuração",
+ "setupInstructionsDesc": "Siga estas etapas para conectar sua API do WhatsApp Business.",
+ "step1": "Crie um App da Meta",
+ "step1_1": "Acesse developers.facebook.com",
+ "step1_2": "Clique em \"Meus Apps\" e depois em \"Criar App\"",
+ "step1_3": "Selecione \"Empresa\" como o tipo de app",
+ "step1_4": "Preencha os detalhes do app e crie",
+ "step2": "Adicione o Produto WhatsApp",
+ "step2_1": "No painel do seu app, clique em \"Adicionar Produto\"",
+ "step2_2": "Encontre \"WhatsApp\" e clique em \"Configurar\"",
+ "step2_3": "Siga o assistente de configuração para vincular sua empresa",
+ "step3": "Obtenha as Credenciais da API",
+ "step3_1": "Acesse WhatsApp > Configuração da API",
+ "step3_2": "Copie seu ID do Número de Telefone",
+ "step3_3": "Copie seu ID da Conta do WhatsApp Business",
+ "step3_4": "Gere um Token de Acesso Permanente em Configurações da Empresa > Usuários do Sistema",
+ "step4": "Configure os Webhooks",
+ "step4_1": "Acesse WhatsApp > Configuração",
+ "step4_2": "Clique em \"Editar\" na seção Webhook",
+ "step4_3": "Cole a URL de Callback do Webhook acima",
+ "step4_4": "Insira o mesmo Token de Verificação que você definiu aqui",
+ "step4_5": "Inscreva-se no campo de webhook \"messages\"",
+ "metaDocs": "Documentação da API do WhatsApp da Meta",
+ "phoneNumberIdRequired": "O ID do número de telefone é obrigatório",
+ "accessTokenRequired": "O token de acesso é obrigatório para a configuração inicial",
+ "loadFailed": "Falha ao carregar a configuração do WhatsApp",
+ "saveFailed": "Falha ao salvar a configuração",
+ "reenterToken": "Insira novamente o token de acesso para salvar as alterações",
+ "savedRegisterFailed": "Salvo, mas a Meta não conseguiu registrar o número: {error}",
+ "savedRegisterSkipped": "Credenciais salvas e verificadas. O registro de entrada foi ignorado (sem PIN) — veja o status de registro abaixo.",
+ "savedLive": "Ativo — {name} já pode receber eventos.",
+ "savedConnected": "WhatsApp conectado. Os eventos começarão a fluir em até um minuto.",
+ "connectedTo": "Conectado a {name}",
+ "connectionSuccess": "Conexão com a API bem-sucedida",
+ "connectionFailed": "Falha na conexão com a API",
+ "connectionTestFailed": "Falha no teste de conexão. Verifique a rede e tente novamente.",
+ "numberLive": "Número totalmente configurado — a Meta está entregando eventos.",
+ "numberNotRegistered": "O número não está totalmente registrado. Veja as verificações abaixo para saber qual etapa falhou.",
+ "verifyEndpointFailed": "Não foi possível acessar o endpoint de verificação.",
+ "resetConfirm": "Isso excluirá a configuração atual do WhatsApp para que você possa inseri-la novamente. Continuar?",
+ "resetFailed": "Falha ao redefinir a configuração",
+ "resetSuccess": "Configuração limpa. Agora você pode inserir suas credenciais novamente.",
+ "webhookCopied": "URL do webhook copiada para a área de transferência",
+ "phoneNumberIdPlaceholder": "ex.: 100234567890123",
+ "wabaIdPlaceholder": "ex.: 100234567890456"
+ },
+ "sections": {
+ "overview": "Visão geral",
+ "profile": "Seu perfil",
+ "security": "Login e segurança",
+ "appearance": "Aparência",
+ "whatsapp": "WhatsApp",
+ "templates": "Modelos",
+ "fields": "Campos e etiquetas",
+ "deals": "Negócios e moeda",
+ "members": "Membros da equipe",
+ "api": "Chaves de API",
+ "quick-replies": "Respostas rápidas"
+ },
+ "groups": {
+ "account": "Conta",
+ "workspace": "Espaço de trabalho"
+ },
+ "profile": {
+ "title": "Seu perfil",
+ "description": "Como você aparece em todo o app. Seu avatar e nome aparecem no cabeçalho, na barra lateral e em qualquer lugar onde seus colegas o veem.",
+ "changePhoto": "Alterar foto",
+ "uploadPhoto": "Enviar foto",
+ "remove": "Remover",
+ "photoHint": "PNG, JPG, WebP ou GIF. Até 2 MB.",
+ "displayName": "Nome de exibição",
+ "email": "E-mail",
+ "emailChangeHint": "Verifique as caixas de entrada de GET /api/v1/me para verificar se funciona.",
+ "cancel": "Cancelar",
+ "creating": "Criando…",
+ "createKey": "Criar chave",
+ "copyTitle": "Copie sua chave de API",
+ "copyDesc": "Esta é a única vez que a chave completa é exibida. Guarde-a em local seguro — se perdê-la, revogue-a e crie uma nova.",
+ "apiKeyLabel": "Chave de API",
+ "copy": "Copiar",
+ "copySuccess": "Chave de API copiada",
+ "copyFailed": "Falha ao copiar — selecione e copie manualmente",
+ "newKeyTitle": "Nova chave de API",
+ "newKeyDesc": "Dê um nome de acordo com a integração que a usará e conceda apenas os escopos necessários.",
+ "done": "Concluído",
+ "networkError": "Não foi possível conectar ao servidor",
+ "scopeDesc": {
+ "messages:send": "Enviar mensagens do WhatsApp",
+ "messages:read": "Ler mensagens e o status de entrega",
+ "contacts:read": "Listar e ler contatos",
+ "contacts:write": "Criar e atualizar contatos",
+ "conversations:read": "Listar e ler conversas",
+ "broadcasts:send": "Disparar campanhas de transmissão",
+ "webhooks:manage": "Registrar e gerenciar webhooks de eventos de saída"
+ }
+ },
+ "deals": {
+ "title": "Negócios e moeda",
+ "description": "A moeda usada para novos negócios e para os totais do funil e do painel.",
+ "defaultCurrency": "Moeda padrão",
+ "defaultCurrencyDesc": "Novos negócios usam esta moeda por padrão, e os totais do funil e do painel são exibidos nela. Negócios existentes mantêm a moeda com que foram salvos.",
+ "currencyLabel": "Moeda",
+ "adminOnlyHint": "Apenas administradores da conta podem alterar a moeda padrão.",
+ "save": "Salvar",
+ "saving": "Salvando...",
+ "saveFailed": "Falha ao salvar a moeda padrão",
+ "saveSuccess": "Moeda padrão atualizada"
+ },
+ "aiConfig": {
+ "title": "Configuração do agente",
+ "description": "Traga sua própria chave da OpenAI ou Anthropic. O wacrm chama o provedor diretamente com sua chave — sem taxas de IA por assento, e seus dados continuam seus. Isso alimenta as respostas redigidas por IA na caixa de entrada, o bot de resposta automática e o Playground.",
+ "adminOnlyConfig": "Apenas administradores e proprietários podem alterar a configuração de IA.",
+ "loadFailed": "Falha ao carregar a configuração de IA",
+ "providerAndKey": "Provedor e chave",
+ "encryptionNotice": "Sua chave é criptografada em repouso (AES-256-GCM) e nunca é exibida novamente após ser salva.",
+ "provider": "Provedor",
+ "model": "Modelo",
+ "apiKey": "Chave de API",
+ "testKey": "Testar chave",
+ "testSuccess": "A chave funciona — o provedor respondeu.",
+ "testRejected": "O provedor rejeitou a solicitação.",
+ "testNetworkError": "Não foi possível conectar ao provedor.",
+ "embeddingsKey": "Chave de embeddings",
+ "optionalSemanticSearch": "(opcional — habilita a busca semântica na base de conhecimento)",
+ "embeddingsHint": "Uma chave da OpenAI usada apenas para gerar embeddings da sua base de conhecimento (text-embedding-3-small){sameKeyText}. Deixe em branco para usar a busca por palavra-chave. Limpe-a para desativar a busca semântica.",
+ "sameKeyText": " — pode ser a mesma chave acima",
+ "behaviour": "Comportamento",
+ "behaviourDesc": "Conte ao assistente sobre seu negócio — produtos, tom, o que ele pode e não pode prometer. Este contexto alimenta tanto os rascunhos quanto as respostas automáticas.",
+ "businessContext": "Contexto e instruções do negócio",
+ "promptPlaceholder": "ex.: Somos a Acme, uma loja de equipamentos de café. Seja acolhedor e conciso. Nunca informe preços ou prazos de entrega — transfira para um humano nesses casos.",
+ "enableAssistant": "Habilitar assistente de IA",
+ "enableAssistantDesc": "Interruptor principal. Ativa o botão “Redigir com IA” na caixa de entrada.",
+ "autoReply": "Resposta automática a mensagens recebidas",
+ "autoReplyDesc": "O bot responde automaticamente a novas mensagens recebidas (apenas quando nenhum fluxo as trata e nenhum agente está atribuído). Transfere para um humano quando não consegue ajudar.",
+ "maxAutoReplies": "Máximo de respostas automáticas por conversa",
+ "maxAutoRepliesDesc": "Após este número de respostas do bot em uma conversa, o bot fica em silêncio.",
+ "handoffTo": "Transferir para",
+ "handoffToDesc": "Quando o bot não consegue ajudar — ou atinge o limite de respostas — ele pausa e direciona a conversa para cá, com uma breve nota sobre o que aconteceu.",
+ "handoffQueue": "Fila não atribuída (qualquer agente pode assumir)",
+ "remove": "Remover",
+ "save": "Salvar",
+ "missingModel": "Insira um nome de modelo.",
+ "missingApiKey": "Insira sua chave de API.",
+ "saveSuccess": "Assistente de IA salvo.",
+ "saveFailed": "Falha ao salvar.",
+ "removeSuccess": "Configuração de IA removida.",
+ "removeFailed": "Falha ao remover."
+ },
+ "aiKnowledge": {
+ "loadFailed": "Falha ao carregar a base de conhecimento",
+ "openFailed": "Falha ao abrir o documento",
+ "titleContentRequired": "O título e o conteúdo são obrigatórios.",
+ "saveSuccessNew": "Documento adicionado.",
+ "saveSuccessUpdate": "Documento atualizado.",
+ "saveFailed": "Falha ao salvar.",
+ "removeSuccess": "Documento removido.",
+ "removeFailed": "Falha ao remover.",
+ "reindexSuccess": "Reindexados {count} documento(s).",
+ "reindexFailed": "Falha na reindexação.",
+ "title": "Base de conhecimento",
+ "description": "Adicione perguntas frequentes, políticas ou detalhes de produtos. O assistente recupera os trechos relevantes ao redigir e responder automaticamente, para que possa responder em vez de transferir.{searchType}",
+ "semanticSearchOn": " A busca semântica está ativada (chave de embeddings definida).",
+ "keywordSearchOn": " Usando busca por palavra-chave — adicione uma chave de embeddings acima para busca semântica.",
+ "noDocs": "Nenhum documento ainda.",
+ "editDocTitle": "Título",
+ "editDocTitlePlaceholder": "ex.: Política de trocas e reembolsos",
+ "editDocContent": "Conteúdo",
+ "editDocContentPlaceholder": "Cole a resposta da FAQ, o texto da política ou os detalhes do produto…",
+ "cancel": "Cancelar",
+ "saveDoc": "Salvar documento",
+ "addDoc": "Adicionar documento",
+ "reindex": "Reindexar",
+ "reindexTooltip": "Regerar embeddings de todos os documentos (ex.: após adicionar uma chave de embeddings)",
+ "loading": "Carregando…"
+ },
+ "sectionsNav": "Seções de configurações",
+ "quickReplies": {
+ "nameRequired": "Dê um nome à resposta rápida.",
+ "saveError": "Não foi possível salvar a resposta rápida.",
+ "updated": "Resposta rápida atualizada.",
+ "created": "Resposta rápida criada.",
+ "deleteConfirm": "Excluir esta resposta rápida?",
+ "deleteError": "Não foi possível excluir a resposta rápida.",
+ "title": "Respostas rápidas",
+ "description": "Trechos reutilizáveis — texto simples ou uma mensagem interativa salva — que os agentes podem inserir a partir do compositor da caixa de entrada.",
+ "newQuickReply": "Nova resposta rápida",
+ "empty": "Ainda não há respostas rápidas. Crie uma para reutilizá-la nas conversas.",
+ "editQuickReply": "Editar resposta rápida",
+ "nameLabel": "Nome",
+ "namePlaceholder": "ex.: Horário de atendimento",
+ "kindText": "Texto",
+ "kindInteractive": "Interativa",
+ "textPlaceholder": "O texto da mensagem a inserir",
+ "cancel": "Cancelar",
+ "save": "Salvar"
+ }
+ },
+ "Notifications": {
+ "title": "Notificações",
+ "subtitle": "As conversas que outros colegas atribuem a você aparecem aqui.",
+ "markAllAsRead": "Marcar todas como lidas",
+ "retry": "Tentar novamente",
+ "emptyTitle": "Nenhuma notificação ainda",
+ "emptyBody": "Você verá um alerta aqui quando alguém atribuir uma conversa a você.",
+ "unread": "Não lida",
+ "markReadError": "Falha ao marcar a notificação como lida",
+ "markAllError": "Falha ao marcar todas como lidas"
+ },
+ "Signup": {
+ "title": "Criar conta",
+ "titleInvite": "Criar conta e entrar",
+ "description": "Comece a usar o CRM Template for WhatsApp",
+ "descriptionInvite": "Verifique seu e-mail e depois aceite o convite para entrar na sua equipe.",
+ "checkEmailTitle": "Verifique seu e-mail",
+ "checkEmailBodyBefore": "Enviamos um link de confirmação para",
+ "checkEmailBodyAfter": ". Verifique sua caixa de entrada e clique no link para confirmar sua conta.",
+ "backToSignIn": "Voltar para o login",
+ "fullName": "Nome completo",
+ "fullNamePlaceholder": "João da Silva",
+ "email": "E-mail",
+ "password": "Senha",
+ "passwordPlaceholder": "Pelo menos 6 caracteres",
+ "confirmPassword": "Confirmar senha",
+ "confirmPasswordPlaceholder": "Repita sua senha",
+ "createAccount": "Criar conta",
+ "creatingAccount": "Criando conta...",
+ "alreadyHaveAccount": "Já tem uma conta?",
+ "signIn": "Entrar",
+ "passwordsDoNotMatch": "As senhas não coincidem",
+ "passwordTooShort": "A senha deve ter pelo menos 6 caracteres"
+ },
+ "ForgotPassword": {
+ "title": "Redefinir senha",
+ "description": "Informe seu e-mail e enviaremos um link de redefinição",
+ "checkEmailTitle": "Verifique seu e-mail",
+ "checkEmailBodyBefore": "Enviamos um link para redefinir a senha para",
+ "checkEmailBodyAfter": ". Verifique sua caixa de entrada.",
+ "backToSignIn": "Voltar para o login",
+ "email": "E-mail",
+ "sending": "Enviando...",
+ "sendResetLink": "Enviar link de redefinição"
+ },
+ "Join": {
+ "verifying": "Verificando convite…",
+ "tryAgain": "Tentar novamente",
+ "createAccountInstead": "Criar uma nova conta",
+ "signIn": "Entrar",
+ "invitedTo": "Você foi convidado para",
+ "joinAs": "Você entrará como",
+ "role": {
+ "admin": "Administrador",
+ "agent": "Agente",
+ "viewer": "Visualizador"
+ },
+ "linkValidUntil": ". Link válido até {date}.",
+ "accepting": "Aceitando…",
+ "acceptInvitation": "Aceitar convite",
+ "acceptHelpBefore": "Ao aceitar, seu login será movido para",
+ "acceptHelpAfter": ". Sua conta pessoal vazia criada no cadastro será removida.",
+ "conflictTitle": "Não é possível entrar em {name} com esta conta",
+ "conflictHelpBefore": "Para entrar em",
+ "conflictHelpAfter": ", saia e cadastre-se novamente com um endereço de e-mail diferente. O link do convite permanece válido enquanto não expirar.",
+ "staySignedIn": "Continuar conectado",
+ "signingOut": "Saindo…",
+ "signOutDifferentEmail": "Sair e usar outro e-mail",
+ "createAccountAndJoin": "Criar conta e entrar",
+ "alreadyHaveAccount": "Já tenho uma conta",
+ "fail": {
+ "not_found": {
+ "title": "Convite não encontrado",
+ "body": "Este link não corresponde a um convite válido. Verifique a URL ou peça à pessoa que convidou para enviar um novo."
+ },
+ "used": {
+ "title": "Convite já utilizado",
+ "body": "Este convite já foi aceito. Se não foi você, peça ao administrador da conta para enviar um novo link."
+ },
+ "expired": {
+ "title": "Convite expirado",
+ "body": "Este convite expirou. Peça ao administrador da conta para enviar um novo — leva alguns segundos para gerar."
+ },
+ "server_error": {
+ "title": "Algo deu errado",
+ "body": "Não conseguimos verificar este convite agora. Tente atualizar a página em instantes."
+ }
+ },
+ "conflictFallback": "Você já está em outra conta. Entre com um e-mail diferente para participar desta.",
+ "acceptError": "Falha ao aceitar o convite",
+ "welcomeToast": "Bem-vindo à equipe",
+ "serverUnreachable": "Não foi possível conectar ao servidor",
+ "signOutError": "Não foi possível sair. Tente atualizar a página."
+ },
+ "Agents": {
+ "title": "Agentes de IA",
+ "subtitle": "Seu agente de IA com chave própria — configure-o e depois teste-o no playground antes que ele responda aos clientes na caixa de entrada.",
+ "tabPlayground": "Playground",
+ "tabSetup": "Configuração",
+ "tabUsage": "Uso"
+ },
+ "AiPlayground": {
+ "notConfiguredToast": "Nenhum agente configurado ainda — conclua a Configuração primeiro.",
+ "noReplyToast": "Não foi possível obter uma resposta.",
+ "unreachableToast": "Não foi possível conectar ao agente.",
+ "headerTitle": "Playground",
+ "headerSubtitle": "— teste as respostas como se você fosse um cliente",
+ "reset": "Redefinir",
+ "emptyTitle": "Envie uma mensagem para ver como seu agente responderia.",
+ "emptyDescription": "Ele usa sua base de conhecimento e se comporta exatamente como o bot de resposta automática — incluindo a transferência.",
+ "goToSetup": "Ainda não configurou? Ir para a Configuração",
+ "handoffLabel": "Transferiria para um humano aqui",
+ "thinking": "Pensando…",
+ "composerPlaceholder": "Digite uma mensagem de cliente…"
+ },
+ "AiUsage": {
+ "loadError": "Falha ao carregar o uso",
+ "tokenUsage": "Uso de tokens",
+ "description": "Tokens gastos na sua chave de provedor por rascunhos e pelo bot de resposta automática. Apenas contagens — nenhum conteúdo de mensagem é armazenado aqui.",
+ "lastDays": "Últimos {w} dias",
+ "noUsage": "Nenhum uso de IA nos últimos {n} dias ainda.",
+ "noUsageHint": "Isso é preenchido conforme o assistente cria rascunhos e responde automaticamente.",
+ "totalTokens": "Total de tokens",
+ "llmCalls": "Chamadas de LLM",
+ "autoReply": "Resposta automática",
+ "drafts": "Rascunhos",
+ "tokensPerDay": "Tokens por dia",
+ "byModel": "Por modelo",
+ "modelUsage": "{tokens} tok · {calls, plural, one {# chamada} other {# chamadas}}",
+ "truncatedNote": "Mostrando uma janela parcial — o uso é alto o suficiente para que apenas os registros mais recentes sejam resumidos aqui."
+ },
+ "FlowsHeader": {
+ "backToFlows": "Voltar para Fluxos",
+ "flowNamePlaceholder": "Nome do fluxo",
+ "flowNameLabel": "Nome do fluxo",
+ "unsavedChanges": "Alterações não salvas — clique em Salvar para persistir",
+ "edited": "Editado",
+ "runs": "Execuções",
+ "delete": "Excluir",
+ "pause": "Pausar",
+ "activate": "Ativar",
+ "fixIssuesBeforeActivating": "Corrija os problemas abaixo antes de ativar",
+ "save": "Salvar",
+ "descriptionPlaceholder": "Adicione uma breve descrição (interna — os clientes não veem isso)",
+ "descriptionLabel": "Descrição do fluxo",
+ "statusDraft": "Rascunho",
+ "statusActive": "Ativo",
+ "statusArchived": "Arquivado"
+ },
+ "InteractiveBuilder": {
+ "replyButtons": "Botões de resposta",
+ "list": "Lista",
+ "body": "Corpo",
+ "bodyPlaceholder": "O que o cliente lê acima das opções",
+ "headerOptional": "Cabeçalho (opcional)",
+ "footerOptional": "Rodapé (opcional)",
+ "showReplyIds": "Mostrar IDs de resposta (avançado)",
+ "preview": "Pré-visualização",
+ "buttonsCount": "Botões ({count}/{max})",
+ "buttonLabel": "Rótulo do botão",
+ "idPlaceholder": "id",
+ "addButton": "Adicionar botão",
+ "listButtonLabel": "Rótulo do botão da lista",
+ "rowsCount": "Linhas ({count}/{max})",
+ "sectionTitleOptional": "Título da seção (opcional)",
+ "rowTitle": "Título da linha",
+ "descriptionOptional": "Descrição (opcional)",
+ "addRow": "Adicionar linha",
+ "addSection": "Adicionar seção"
+ },
+ "InteractivePreview": {
+ "messageBody": "Corpo da mensagem…",
+ "button": "Botão",
+ "menu": "Menu"
+ },
+ "FlowTemplates": {
+ "welcome_menu": {
+ "name": "Menu de boas-vindas",
+ "description": "Cumprimente clientes que digitam uma palavra-chave e direcione-os ao atendente certo com base em serem novos ou já existentes."
+ },
+ "faq_bot": {
+ "name": "Bot de perguntas frequentes",
+ "description": "Responda perguntas comuns automaticamente. O cliente escolhe um tópico em uma lista; o bot responde e encerra."
+ },
+ "lead_capture": {
+ "name": "Captura de leads",
+ "description": "Cumprimente novos contatos, capture nome + e-mail + empresa e depois transfira para vendas com as respostas na nota."
+ }
+ },
+ "AutomationTemplates": {
+ "welcome_message": {
+ "name": "Mensagem de boas-vindas",
+ "description": "Responder automaticamente com uma saudação a contatos de primeira vez."
+ },
+ "out_of_office": {
+ "name": "Fora do expediente",
+ "description": "Responder automaticamente fora do horário para que ninguém fique sem resposta."
+ },
+ "lead_qualifier": {
+ "name": "Qualificador de leads",
+ "description": "Fazer perguntas de qualificação para filtrar leads recebidos."
+ },
+ "follow_up_reminder": {
+ "name": "Lembrete de acompanhamento",
+ "description": "Enviar um lembrete se um contato não responder em 24 horas."
+ }
+ },
+ "Themes": {
+ "violet": {
+ "name": "Violeta",
+ "description": "O padrão — confiante e um pouco descontraído."
+ },
+ "emerald": {
+ "name": "Esmeralda",
+ "description": "Com clima de crescimento, remete a mensagens sem copiar o verde do WhatsApp."
+ },
+ "cobalt": {
+ "name": "Cobalto",
+ "description": "Azul limpo de SaaS B2B — calmo e com cara de produto."
+ },
+ "amber": {
+ "name": "Âmbar",
+ "description": "Quente e amigável — combina com equipes de pequenas e médias empresas."
+ },
+ "rose": {
+ "name": "Rosa",
+ "description": "Ousado e moderno — D2C, economia de criadores, lifestyle."
+ }
+ },
+ "Common": {
+ "loading": "Carregando..."
+ }
+}
diff --git a/src/app/(auth)/forgot-password/page.tsx b/src/app/(auth)/forgot-password/page.tsx
index d2a1784fb7..8a123c1905 100644
--- a/src/app/(auth)/forgot-password/page.tsx
+++ b/src/app/(auth)/forgot-password/page.tsx
@@ -14,8 +14,10 @@ import {
CardTitle,
} from "@/components/ui/card";
import { MessageSquare, CheckCircle, ArrowLeft } from "lucide-react";
+import { useTranslations } from "next-intl";
export default function ForgotPasswordPage() {
+ const t = useTranslations("ForgotPassword");
const [email, setEmail] = useState("");
const [error, setError] = useState- Already have an account?{" "} + {t("alreadyHaveAccount")}{" "} - Sign in + {t("signIn")}
diff --git a/src/app/(dashboard)/agents/page.tsx b/src/app/(dashboard)/agents/page.tsx index c3774849a4..35cf1f9bd3 100644 --- a/src/app/(dashboard)/agents/page.tsx +++ b/src/app/(dashboard)/agents/page.tsx @@ -1,6 +1,7 @@ 'use client'; import { useEffect, useState } from 'react'; +import { useTranslations } from 'next-intl'; import { Bot, Sparkles, Settings2, BarChart3 } from 'lucide-react'; import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; import { AiPlayground } from '@/components/agents/ai-playground'; @@ -12,6 +13,7 @@ import { canEditSettings } from '@/lib/auth/roles'; type Tab = 'playground' | 'setup' | 'usage'; export default function AgentsPage() { + const t = useTranslations('Agents'); const { accountRole } = useAuth(); const canViewUsage = accountRole ? canEditSettings(accountRole) : false; const [tab, setTab] = useState- Your bring-your-own-key AI agent — set it up, then test it in the - playground before it replies to customers in the inbox. + {t('subtitle')}
{decided && ( @@ -57,14 +58,14 @@ export default function AgentsPage() { >{t.description}
+{tmplT(`${slug}.description`)}
) })} @@ -299,7 +299,7 @@ function AutomationCard({ {automation.name} {automation.is_active && ( - + @@ -336,7 +336,7 @@ function AutomationCard({Loading...
+{t("loading")}
{error}
- Conversations other teammates assign to you show up here. + {t("subtitle")}
- No notifications yet + {t("emptyTitle")}
- You'll see an alert here when someone assigns you a - conversation. + {t("emptyBody")}
Verifying invitation…
+{t('verifying')}
- Accepting moves your login into{' '} - {peek.account_name}. Your - empty personal account from signup will be cleaned up. + {t('acceptHelpBefore')}{' '} + {peek.account_name} + {t('acceptHelpAfter')}
@@ -363,7 +340,7 @@ export default function JoinPage() {- To join{' '} - {peek.account_name}, - sign out and sign up again with a different email address. - The invite link stays valid as long as it hasn't - expired. + {t('conflictHelpBefore')}{' '} + {peek.account_name} + {t('conflictHelpAfter')}
Send a message to see how your agent would reply.
+{tr('emptyTitle')}
- It uses your knowledge base and behaves exactly like the - auto-reply bot — including handoff. + {tr('emptyDescription')}
{onGoToSetup && ( )}