Files
LambdaMail/services/webmail/messages/es.json
T
Lucas RayanandClaude Opus 5 ee240ae227 #23: show real data, unify the surfaces and make enrolment scannable
The interface was reporting things that were not true. Several screens were
mockups wired to nothing, and a reader with the console in Portuguese was
served a mixture of two languages.

Fabricated data, removed:

- The outbound queue was two invented jobs held in component state. Retry and
  Freeze only edited that local array, so the screen showed the same two rows
  on every deployment and reported success for actions that never happened.
  "Freeze" named an operation the backend has never implemented. It now reads
  /api/v1/admin/queue, which was already serving the real thing, and offers
  retry and cancel, which exist.
- Every dashboard KPI fell back to an invented constant (1420 received, 890
  sent, 3 queued, 18.4% disk), so an unreachable API produced a dashboard of
  plausible traffic for a server that might have delivered nothing. Two of
  those fields were never returned by the endpoint at all, so the fake disk
  figure was what everyone always saw. DMARC did the same with 1250/98%/97%.
- The domains screen showed thirteen DNS records for example.com, all marked
  VERIFIED, and posted {domain_id: "default-domain"} to endpoints expecting a
  real id. DKIM rotation sends "domain", not "domain_id", so its 400 was
  swallowed and a made-up TXT record displayed as though a key had been
  issued: rotation had never once worked from this screen.
- The TLS panel asserted a Let's Encrypt RSA 4096 certificate and verified
  DANE from static markup, on a deployment currently serving a self-signed
  one. It now reads the cert watcher via /api/v1/admin/tls.
- The readiness scorecard printed "10 / 10 all checks passed" regardless of
  what preflight reported, including failures.
- A message trace that found nothing invented a five-step delivery - TLS 1.3
  accepted, SPF pass, spam score 0.8 - for a message that does not exist.
- Both sidebars showed a fixed admin@lambdamail.local with a hardcoded
  "SUPER_ADMIN (2FA)", claiming a second factor whether or not one existed.
- Settings seeded a "[Boletim]" Sieve rule. Saving posts the whole list, so
  the first edit wrote that invented filter into the account's real script.

The reconcile endpoint itself answered {records_verified: 13, status:
"VERIFIED"} for any domain id, including one that does not exist, without
resolving a name. It now reports what it does, which is record the request.

Surfaces:

The root was a chooser listing webmail and the console side by side, which
asked visitors a question they should not have to answer and advertised cookie
names and audiences to anonymous readers. It now redirects into the mail
client. Accounts that may administer the server get a link to the console from
inside the app - a link to /admin/login, so crossing over still costs the
second factor the admin audience requires - and the console gets a plain link
back, since the webmail session was never given up to get there.

Enrolment:

Both enrolment screens printed the base32 secret as text and left the operator
to type 32 characters into their phone. The enrol endpoint already returned an
otpauth:// URI; it simply was not drawn. Added a shared component that renders
it as a QR locally - the seed is already in the page, and sending it to an
image service would put it in another request log for nothing.

The recovery-code step rendered its own "sign in" button while the form's
submit button stayed visible below it: two identical buttons, and no way to
copy the codes it insisted you save. It is now terminal, with copy and
continue.

Language:

translate() had no interpolation, so "Undo Send ({seconds}s remaining)" showed
the placeholder and a second hardcoded countdown was appended after it. It now
substitutes, leaving an unmatched token visible rather than blanking it.

The pt-BR bundle had lost its diacritics - "Destinatario", "Ultimo erro",
"Acoes" - from the ASCII-source rule being applied to the translations, which
are data. Restored, and the three bundles are back in key parity at 270 each,
with roughly 120 strings that were hardcoded in the source now keyed.

Healthchecks:

web had none, despite being the only service users reach directly: a wedged
Next process kept its container running and Traefik kept routing to it. Added,
using node's own fetch since the image ships no curl. rspamd and clamav gained
the timeouts and start_periods whose absence would fail them during startup.
migrate stays without one and says why: it is a one-shot job, and a probe
would report unhealthy exactly when it has succeeded.

Verified: 36 webmail tests and 41 auth tests against a real Postgres, both new
admin/me cases confirmed to fail without the route (404). lang-lint clean,
production build clean, 0 vulnerabilities, compose validates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 19:13:53 -03:00

287 lines
12 KiB
JSON

{
"admin": {
"addAlias": "Añadir apelido",
"aliasesTitle": "Alias",
"auditLog": "Registro de auditoría",
"backToWebmail": "Volver al webmail",
"cancelJob": "Cancelar",
"certificateState": "Certificado",
"checksPassed": "{passed} de {total} aprobadas",
"createAccount": "Crear cuenta",
"createAlias": "Crear un alias de enrutamiento",
"csvPreview": "Vista previa",
"dashboardSubtitle": "Cifras en vivo leídas de la base de datos.",
"dashboardTitle": "Resumen",
"dkimAlgorithm": "Tipo de clave",
"dkimOverlap": "Ambas claves firman el correo saliente durante {days} días para que nada falle mientras el DNS se propaga.",
"dkimPublishRecord": "Publique este registro en DNS:",
"dkimRotate": "Generar una nueva clave",
"dkimSelector": "Selector",
"dkimTitle": "Rotación de clave DKIM",
"dmarcSubtitle": "Desglose de los informes XML agregados procesados.",
"dmarcTitle": "Informes DMARC",
"dnsRecordsFor": "Registros DNS de {domain}",
"dnsStatusDrift": "Divergente",
"dnsStatusPartial": "Parcial",
"dnsStatusVerified": "Verificado",
"domainName": "Nombre del dominio",
"domainsTitle": "Dominios",
"expiresInDays": "Caduca en {days} días",
"freezeDomain": "Congelar dominio",
"greylistScore": "Puntuación de greylist",
"headerScore": "Puntuación de etiquetado de cabecera",
"jobCancelled": "El trabajo {id} fue cancelado.",
"jobRetried": "El trabajo {id} se volvió a poner en cola para otro intento.",
"lastChecked": "Última comprobación: {when}",
"lastReload": "Última recarga",
"mailHost": "Host de correo",
"mailboxCount": "{count} buzones",
"mailboxesSubtitle": "Cuentas, alias, importación CSV y la política de segundo factor.",
"mailboxesTitle": "Buzones",
"mfaAdmins": "Obligatorio para administradores",
"mfaEveryone": "Obligatorio para todos",
"mfaOptional": "Opcional",
"mfaPolicyIntro": "Elija con qué rigor este dominio exige un segundo factor.",
"mfaPolicyTitle": "Requisito de segundo factor",
"noCertificate": "No hay certificado cargado para este host.",
"noChecks": "No se informaron verificaciones.",
"noDomains": "Aún no se ha dado de alta ningún dominio.",
"onboardIntro": "Crea el dominio y sus alias estándar RFC 2142, apuntados a su dirección.",
"onboardTitle": "Añadir un dominio",
"openAdmin": "Consola de administración",
"preflightTitle": "Verificaciones de preparación",
"queueEmpty": "La cola de salida está vacía.",
"queueSubtitle": "Inspeccione la cola de salida, reintente un trabajo o cancele uno.",
"queueTitle": "Cola de salida",
"readinessIntro": "Verificaciones que el servidor informa sobre sí mismo antes de transportar correo en producción.",
"reconcileDns": "Reconciliar DNS",
"reconcileNotImplemented": "La verificación de registros DNS individuales aún no está implementada: esto registra la solicitud y relee el estado almacenado, no consulta un resolutor.",
"rejectScore": "Puntuación de rechazo",
"retryJob": "Reintentar",
"rspamdIntro": "Puntuaciones que activan greylisting, etiquetado de cabecera y rechazo.",
"rspamdSaved": "Umbrales guardados.",
"saveThresholds": "Guardar umbrales",
"securitySubtitle": "Verificaciones de preparación, estado TLS, umbrales de spam y el registro de auditoría.",
"securityTitle": "Seguridad",
"tabAudit": "Registro de auditoría",
"tabReadiness": "Preparación",
"tabRspamd": "Umbrales de spam",
"tabTls": "TLS",
"tlsMode": "Modo TLS",
"tlsTitle": "Certificado y transporte",
"traceNoResults": "No se encontró rastro para ese ID de cola.",
"tracePlaceholder": "ID de la cola",
"traceTitle": "Rastrear un mensaje",
"unknownSni": "Solicitudes SNI desconocidas",
"watcherHealthy": "Monitor de certificado"
},
"auth": {
"adminLoginTitle": "Consola de administración",
"adminStepUpNote": "La consola de administración vuelve a pedir su segundo factor, aunque ya haya iniciado sesión en el webmail.",
"authFailed": "Fallo en la autenticación",
"cantScanQr": "¿No puede escanear? Introduzca esta clave manualmente:",
"emailLabel": "Dirección de correo",
"enrolmentFailed": "No se pudo iniciar la configuración del segundo factor",
"enrolmentIntro": "La consola de administración requiere un segundo factor. Configure uno ahora para continuar.",
"genericError": "Algo salió mal",
"invalidCredentials": "Correo o contraseña inválidos",
"mfaRequired": "Introduzca el código de seis dígitos de su aplicación de autenticación.",
"passwordLabel": "Contraseña",
"qrCodeAlt": "Código QR para configurar la verificación en dos pasos",
"scanQr": "Escanee este código con Google Authenticator, Aegis, Authy o 1Password.",
"signInButton": "Iniciar sesión",
"signOutOfAdmin": "Salir de administración",
"totpCodeLabel": "Código de autenticación",
"userLoginTitle": "Acceda a su buzón",
"verificationFailed": "Fallo en la verificación",
"verifyCodeButton": "Verificar código"
},
"common": {
"actions": "Acciones",
"add": "Añadir",
"adminPortal": "Administración",
"appName": "LambdaMail",
"back": "Volver",
"cancel": "Cancelar",
"confirm": "Confirmar",
"continue": "Continuar",
"copied": "Copiado",
"copy": "Copiar",
"delete": "Eliminar",
"loading": "Cargando...",
"logout": "Cerrar sesión",
"never": "Nunca",
"none": "Ninguno",
"refresh": "Actualizar",
"retry": "Reintentar",
"save": "Guardar",
"search": "Buscar",
"status": "Estado",
"unavailable": "No disponible",
"userPortal": "Webmail"
},
"errors": {
"forbidden": "No tiene acceso a esto",
"loadFailed": "No se pudieron cargar los datos",
"serverError": "Algo salió mal en el servidor",
"unauthorized": "Inicie sesión de nuevo"
},
"mail": {
"addFiles": "Añadir archivos...",
"allMessages": "Todas",
"archive": "Archivo",
"attachments": "Adjuntos ({count})",
"attachmentsFilter": "Con adjuntos",
"attachmentsUnsupported": "Los adjuntos se listan solo por nombre; la subida de archivos aún no está implementada.",
"backToList": "Volver a la lista de mensajes",
"bold": "Negrita",
"bulletList": "Lista con viñetas",
"compose": "Redactar",
"discard": "Descartar",
"draftSaved": "Borrador guardado automáticamente",
"drafts": "Borradores",
"forward": "Reenviar",
"hideCcBcc": "- Ocultar Cc/Cco",
"inbox": "Bandeja de entrada",
"insertLink": "Insertar enlace",
"insertUrl": "Introduzca la URL:",
"italic": "Cursiva",
"junk": "Spam",
"loadImages": "Cargar imágenes",
"noMessages": "Sin mensajes",
"numberedList": "Lista numerada",
"reply": "Responder",
"sendMessage": "Enviar mensaje",
"sending": "Enviando...",
"sent": "Enviados",
"showCcBcc": "+ Añadir Cc/Cco",
"strikethrough": "Tachado",
"trash": "Papelera",
"underline": "Subrayado",
"undoSend": "Enviando en {seconds}s",
"undoSendAction": "Deshacer",
"unreadCount": "{count} sin leer",
"unreadFilter": "Sin leer"
},
"settings": {
"actionDiscard": "Descartar",
"actionFlag": "Marcar mensaje",
"actionMove": "Mover al Archivo",
"addRule": "Añadir regla",
"appPasswordPlaceholder": "Thunderbird / Outlook Mobile",
"appPasswords": "Contraseñas de aplicación",
"autoReplySaveFailed": "No se pudo guardar la respuesta automática",
"enableMfa": "Activar verificación en dos pasos",
"fieldFrom": "De",
"fieldHeader": "Cabecera",
"fieldSubject": "Asunto",
"generateAppPassword": "Generar",
"langEn": "English",
"langEs": "Español",
"langPtBR": "Português (Brasil)",
"language": "Idioma",
"matchContains": "contiene",
"matchEquals": "es exactamente",
"matchRegex": "coincide con regex",
"mfaDisabled": "Desactivada",
"mfaEnabled": "Activada",
"mfaStatus": "Estado de la verificación en dos pasos",
"recoveryCodesTitle": "Códigos de recuperación",
"ruleIf": "SI",
"ruleThen": "ENTONCES",
"saveAutoReply": "Guardar respuesta automática",
"saveRecoveryCodes": "Guárdelos en un lugar seguro. Cada uno funciona una sola vez y solo se muestran ahora.",
"security": "Seguridad",
"sessions": "Sesiones",
"settingsSaved": "Configuración guardada.",
"sieveIntro": "Reglas que organizan el correo entrante automáticamente.",
"sieveTitle": "Filtros (Sieve)",
"signOut": "Cerrar sesión",
"signatureIntro": "Se añade automáticamente a los mensajes que redacta.",
"signaturePlaceholder": "Saludos cordiales,\nSu nombre\nSu cargo",
"signatureSaveFailed": "No se pudo guardar la firma",
"signatureSaved": "Firma guardada.",
"signatureTitle": "Firma de correo",
"sixDigitCode": "Código de seis dígitos",
"subtitle": "Verificación en dos pasos, filtros, respuesta automática y su firma.",
"title": "Configuración",
"twoFactorIntro": "Proteja su cuenta con Google Authenticator, Aegis, Authy o 1Password.",
"vacationBodyLabel": "Mensaje de la respuesta",
"vacationDefaultBody": "Gracias por su mensaje. Estoy ausente en este momento y responderé a mi regreso.",
"vacationDefaultSubject": "Fuera de la oficina",
"vacationIntro": "Responde automáticamente al correo entrante mientras esté ausente.",
"vacationSubjectLabel": "Asunto de la respuesta",
"vacationTitle": "Respuesta automática de ausencia",
"valuePlaceholder": "Valor a coincidir..."
},
"ui": {
"accountStatus": "Estado de la cuenta",
"actions": "Acciones",
"active": "Activo",
"activeSessions": "Sesiones activas",
"actor": "Autor",
"actualRecord": "Valor actual",
"allChecksPassed": "Todas las verificaciones pasaron",
"appPasswordGenerated": "Contraseña de aplicación generada",
"appPasswordsSection": "Contraseñas de aplicación",
"attempts": "Intentos",
"bounceRate": "Tasa de rebote",
"changePassword": "Cambiar contraseña",
"clientIp": "IP del cliente",
"copyPasswordNow": "Cópiela ahora. No se mostrará de nuevo.",
"coreInfra": "Servicios principales",
"currentPassword": "Contraseña actual",
"currentSession": "Este dispositivo",
"daneVerified": "DANE verificado",
"destination": "Destino",
"diskUsed": "Almacenamiento usado",
"dkimAlignment": "Alineación DKIM",
"dkimResult": "DKIM",
"dmarcEnforcement": "Política DMARC",
"domainVerification": "Verificación de dominio",
"domainsVerified": "Dominios verificados",
"emailAddress": "Dirección de correo",
"eventAction": "Acción",
"expectedValue": "Valor esperado",
"healthy": "Correcto",
"imapEngine": "Servicio IMAP",
"inboundVolume": "Recibidas (24h)",
"jobId": "Trabajo",
"lastError": "Último error",
"liveMetrics": "Métricas en vivo",
"localDisk": "Disco local",
"mailboxesActive": "Buzones activos",
"messageBody": "Mensaje",
"messageVolume": "Mensajes",
"newPassword": "Nueva contraseña",
"noAppPasswords": "Aún no hay contraseñas de aplicación.",
"noData": "Aún sin datos",
"online": "En línea",
"outboundDelivered": "Enviadas (24h)",
"passwordChanged": "Contraseña cambiada.",
"postgresRunner": "Cola basada en Postgres",
"preflightTitle": "Preparación",
"provisionMailbox": "Crear buzón",
"queueDepth": "Tamaño de la cola",
"recipient": "Destinatario",
"recordName": "Registro",
"reportingOrg": "Organización informante",
"scanners": "Análisis de spam y virus",
"sender": "Remitente",
"signOutOthers": "Cerrar sesión en otros dispositivos",
"smtpListener": "Servicio SMTP",
"sourceIp": "IP de origen",
"spfRatio": "Tasa de aprobación SPF",
"spfResult": "SPF",
"storageQuota": "Cuota de almacenamiento",
"subject": "Asunto",
"targetObject": "Objetivo",
"timestamp": "Hora",
"toRecipients": "Para",
"toggleMenu": "Alternar menú",
"totalEvaluated": "Mensajes evaluados",
"twoFactorSection": "Verificación en dos pasos",
"watching": "Vigilando"
}
}