From 7d154ae06ac9fb17aafb5d3130c8e89487e77910 Mon Sep 17 00:00:00 2001 From: hreyes Date: Tue, 21 Apr 2026 12:58:35 -0600 Subject: [PATCH] fix/idioma-bitacota --- frontend/src/lib/utils/audit-log-i18n.ts | 252 ++++++++++++++++++ .../dashboard/audit_logs/bitacora-tab.svelte | 76 +++--- .../dashboard/audit_logs/tasks-tab.svelte | 106 ++++---- 3 files changed, 356 insertions(+), 78 deletions(-) create mode 100644 frontend/src/lib/utils/audit-log-i18n.ts diff --git a/frontend/src/lib/utils/audit-log-i18n.ts b/frontend/src/lib/utils/audit-log-i18n.ts new file mode 100644 index 00000000..213252f4 --- /dev/null +++ b/frontend/src/lib/utils/audit-log-i18n.ts @@ -0,0 +1,252 @@ +import { getLocale } from '$lib/paraglide/runtime'; + +type SupportedLocale = 'en' | 'es'; +type LocalizedText = Record; + +const PROCEDURE_TRANSLATIONS: Record = { + 'IMPORT INVOICE BROWSE': { en: 'Import invoice lookup', es: 'Consulta de factura de importación' }, + 'IMPORT INVOICE UPDATE': { en: 'Import invoice update', es: 'Actualización de factura de importación' }, + 'PEDIMENTO BROWSE': { en: 'Pedimento lookup', es: 'Consulta de pedimento' }, + 'SYSTEM SCAF': { en: 'SCAF system', es: 'Sistema SCAF' }, + 'SYSTEM AUTH': { en: 'System authentication', es: 'Autenticación del sistema' }, + CATALOGS: { en: 'Catalogs', es: 'Catálogos' }, + 'ELECTRONIC NOTICES': { en: 'Electronic notices', es: 'Avisos electrónicos' }, + DODA: { en: 'DODA', es: 'DODA' } +}; + +const MOVEMENT_TRANSLATIONS: Record = { + 'ADD IMPORT_INVOICE': { en: 'Add import invoice', es: 'Agregar factura de importación' }, + 'EDIT IMPORT_INVOICE': { en: 'Edit import invoice', es: 'Editar factura de importación' }, + 'DELETE IMPORT_INVOICE': { en: 'Delete import invoice', es: 'Eliminar factura de importación' }, + 'ADD IMPORT_INVOICE_ITEM': { en: 'Add import invoice item', es: 'Agregar partida de factura de importación' }, + 'EDIT IMPORT_INVOICE_ITEM': { en: 'Edit import invoice item', es: 'Editar partida de factura de importación' }, + 'DELETE IMPORT_INVOICE_ITEM': { en: 'Delete import invoice item', es: 'Eliminar partida de factura de importación' }, + 'ADD PEDIMENTO': { en: 'Add pedimento', es: 'Agregar pedimento' }, + 'EDIT PEDIMENTO': { en: 'Edit pedimento', es: 'Editar pedimento' }, + 'DELETE PEDIMENTO': { en: 'Delete pedimento', es: 'Eliminar pedimento' }, + 'SYSTEM LOGIN': { en: 'System login', es: 'Inicio de sesión del sistema' }, + 'SYSTEM LOGOUT': { en: 'System logout', es: 'Cierre de sesión del sistema' }, + 'ADD CLASS': { en: 'Add class', es: 'Agregar clase' }, + 'EDIT CLASS': { en: 'Edit class', es: 'Editar clase' }, + 'DELETE CLASS': { en: 'Delete class', es: 'Eliminar clase' }, + 'ADD DODA': { en: 'Add DODA', es: 'Agregar DODA' }, + 'EDIT DODA': { en: 'Edit DODA', es: 'Editar DODA' }, + 'DELETE DODA': { en: 'Delete DODA', es: 'Eliminar DODA' }, + 'ADD COMPANY': { en: 'Add company', es: 'Agregar empresa' }, + 'EDIT COMPANY': { en: 'Edit company', es: 'Editar empresa' }, + 'DELETE COMPANY': { en: 'Delete company', es: 'Eliminar empresa' } +}; + +const ENTITY_TRANSLATIONS: Record = { + 'IMPORT INVOICE ITEM': { en: 'import invoice item', es: 'partida de factura de importación' }, + 'IMPORT INVOICE': { en: 'import invoice', es: 'factura de importación' }, + 'UNIT CONVERSIONS': { en: 'unit conversions', es: 'conversiones de unidades' }, + UNITS: { en: 'units', es: 'unidades' }, + CONVERSIONS: { en: 'conversions', es: 'conversiones' }, + PEDIMENTO: { en: 'pedimento', es: 'pedimento' }, + CLASS: { en: 'class', es: 'clase' }, + COMPANY: { en: 'company', es: 'empresa' }, + USER: { en: 'user', es: 'usuario' }, + USERS: { en: 'users', es: 'usuarios' }, + SESSION: { en: 'session', es: 'sesión' }, + SESSIONS: { en: 'sessions', es: 'sesiones' }, + ITEM: { en: 'item', es: 'artículo' }, + ITEMS: { en: 'items', es: 'artículos' }, + CLIENT: { en: 'client', es: 'cliente' }, + CLIENTS: { en: 'clients', es: 'clientes' }, + PROVIDER: { en: 'provider', es: 'proveedor' }, + PROVIDERS: { en: 'providers', es: 'proveedores' }, + CATALOGS: { en: 'catalogs', es: 'catálogos' }, + 'ELECTRONIC NOTICES': { en: 'electronic notices', es: 'avisos electrónicos' }, + DODA: { en: 'DODA', es: 'DODA' }, + 'SYSTEM SCAF': { en: 'SCAF system', es: 'sistema SCAF' }, + 'SYSTEM AUTH': { en: 'system authentication', es: 'autenticación del sistema' } +}; + +const VERB_TRANSLATIONS: Record = { + ADD: { en: 'Add', es: 'Agregar' }, + EDIT: { en: 'Edit', es: 'Editar' }, + DELETE: { en: 'Delete', es: 'Eliminar' }, + CREATE: { en: 'Create', es: 'Crear' }, + UPDATE: { en: 'Update', es: 'Actualizar' } +}; + +const TOKEN_TRANSLATIONS: Record = { + IMPORT: { en: 'import', es: 'importación' }, + INVOICE: { en: 'invoice', es: 'factura' }, + ITEM: { en: 'item', es: 'artículo' }, + ITEMS: { en: 'items', es: 'artículos' }, + PEDIMENTO: { en: 'pedimento', es: 'pedimento' }, + SYSTEM: { en: 'system', es: 'sistema' }, + AUTH: { en: 'authentication', es: 'autenticación' }, + CATALOGS: { en: 'catalogs', es: 'catálogos' }, + ELECTRONIC: { en: 'electronic', es: 'electrónicos' }, + NOTICES: { en: 'notices', es: 'avisos' }, + UNIT: { en: 'unit', es: 'unidad' }, + UNITS: { en: 'units', es: 'unidades' }, + CONVERSIONS: { en: 'conversions', es: 'conversiones' }, + COMPANY: { en: 'company', es: 'empresa' }, + CLASS: { en: 'class', es: 'clase' }, + USER: { en: 'user', es: 'usuario' }, + USERS: { en: 'users', es: 'usuarios' }, + SESSION: { en: 'session', es: 'sesión' }, + SESSIONS: { en: 'sessions', es: 'sesiones' }, + CLIENT: { en: 'client', es: 'cliente' }, + CLIENTS: { en: 'clients', es: 'clientes' }, + PROVIDER: { en: 'provider', es: 'proveedor' }, + PROVIDERS: { en: 'providers', es: 'proveedores' } +}; + +function normalizeKey(value: string) { + return value.trim().replace(/_/g, ' ').replace(/\s+/g, ' ').toUpperCase(); +} + +function currentLocale(): SupportedLocale { + return getLocale() === 'es' ? 'es' : 'en'; +} + +function capitalize(value: string) { + return value.charAt(0).toUpperCase() + value.slice(1); +} + +function translateEntity(value: string) { + const locale = currentLocale(); + const normalized = normalizeKey(value); + const exact = ENTITY_TRANSLATIONS[normalized]; + if (exact) return exact[locale]; + + return normalized + .split(' ') + .map((token) => TOKEN_TRANSLATIONS[token]?.[locale] ?? token.toLowerCase()) + .join(' '); +} + +export function translateAuditProcedure(value: string) { + if (!value) return value; + + const locale = currentLocale(); + const normalized = normalizeKey(value); + const exact = PROCEDURE_TRANSLATIONS[normalized]; + if (exact) return exact[locale]; + + if (normalized.endsWith(' BROWSE')) { + const entity = translateEntity(normalized.slice(0, -' BROWSE'.length)); + return locale === 'es' ? `Consulta de ${entity}` : `${capitalize(entity)} lookup`; + } + + if (normalized.endsWith(' UPDATE')) { + const entity = translateEntity(normalized.slice(0, -' UPDATE'.length)); + return locale === 'es' ? `Actualización de ${entity}` : `${capitalize(entity)} update`; + } + + const fallback = translateEntity(normalized); + return capitalize(fallback); +} + +export function translateAuditMovement(value: string) { + if (!value) return value; + + const locale = currentLocale(); + const normalized = normalizeKey(value); + const exact = MOVEMENT_TRANSLATIONS[normalized]; + if (exact) return exact[locale]; + + const [verb, ...rest] = normalized.split(' '); + const translatedVerb = VERB_TRANSLATIONS[verb]; + if (!translatedVerb || rest.length === 0) { + return capitalize(translateEntity(normalized)); + } + + return `${translatedVerb[locale]} ${translateEntity(rest.join(' '))}`; +} + +// ── Tareas en segundo plano (Celery) ────────────────────────────────────── + +const TASK_GROUP_TRANSLATIONS: Record = { + factura_cove: { en: 'Invoice COVE', es: 'COVE de factura' }, + layouts_csv: { en: 'CSV import', es: 'Importación CSV' }, + reports: { en: 'Reports', es: 'Reportes' }, + invoices: { en: 'Invoices', es: 'Facturas' } +}; + +const TASK_NAME_TRANSLATIONS: Record = { + // invoices + process_invoice_task: { en: 'Process import invoice', es: 'Procesar factura de importación' }, + revert_import_invoice_task: { en: 'Revert import invoice', es: 'Revertir factura de importación' }, + revert_invoice_task: { en: 'Revert import invoice', es: 'Revertir factura de importación' }, + process_export_invoice_task: { en: 'Process export invoice', es: 'Procesar factura de exportación' }, + revert_export_invoice_task: { en: 'Revert export invoice', es: 'Revertir factura de exportación' }, + // factura_cove + factura_cove_generate: { en: 'Generate invoice COVE', es: 'Generar COVE de factura' }, + // reports + generate_invoice_movements_async: { en: 'Generate invoice movements', es: 'Generar movimientos de facturas' }, + generate_saldos_temporales_async: { en: 'Generate temporary balances', es: 'Generar saldos temporales' }, + generate_vencimiento_csv_async: { en: 'Generate expiration CSV', es: 'Generar CSV de vencimiento' }, + generar_packing_list_async: { en: 'Generate packing list', es: 'Generar packing list' }, + generar_pdf_consolidado_async: { en: 'Generate consolidated PDF', es: 'Generar PDF consolidado' }, + generar_pdf_factura_async: { en: 'Generate invoice PDF', es: 'Generar PDF de factura' }, + generate_pedimentos_winsaai_task: { en: 'Generate WinSAAI pedimentos', es: 'Generar pedimentos WinSAAI' }, + generar_transmission_definitiva_async: { en: 'Generate definitive transmission', es: 'Generar transmisión definitiva' }, + generar_transmission_temporal_async: { en: 'Generate temporary transmission', es: 'Generar transmisión temporal' }, + generate_descarga_pdf_task: { en: 'Generate discharge PDF', es: 'Generar PDF de descarga' }, + generate_winsaai_task: { en: 'Generate WinSAAI file', es: 'Generar archivo WinSAAI' }, + generar_pdf_aviso_consolidado_exp_async: { en: 'Generate export consolidated notice PDF', es: 'Generar PDF aviso consolidado exportación' }, + generar_transmission_file_async: { en: 'Generate transmission file', es: 'Generar archivo de transmisión' }, + // layouts_csv + vehicles_scan_file: { en: 'Scan vehicles CSV file', es: 'Escanear archivo de vehículos CSV' }, + classes_scan_file: { en: 'Scan classes CSV file', es: 'Escanear archivo de clases CSV' }, + classes_insert_valid_rows: { en: 'Import valid classes CSV rows', es: 'Importar clases válidas CSV' }, + customs_brokers_scan_file: { en: 'Scan customs brokers CSV file', es: 'Escanear archivo de agentes aduanales CSV' }, + customs_brokers_insert_valid_rows: { en: 'Import valid customs brokers CSV rows', es: 'Importar agentes aduanales válidos CSV' }, + trailers_scan_file: { en: 'Scan trailers CSV file', es: 'Escanear archivo de remolques CSV' }, + exchange_rate_scan_file: { en: 'Scan exchange rate CSV file', es: 'Escanear archivo de tipo de cambio CSV' }, + exchange_rate_insert_valid_rows: { en: 'Import valid exchange rate CSV rows', es: 'Importar tipo de cambio válido CSV' }, + exportacion_scan_file: { en: 'Scan export CSV file', es: 'Escanear archivo de exportación CSV' }, + exportacion_insert_valid_rows: { en: 'Import valid export CSV rows', es: 'Importar exportación válida CSV' }, + boms_scan_file: { en: 'Scan BOM CSV file', es: 'Escanear archivo de listas de materiales CSV' }, + boms_insert_valid_rows: { en: 'Import valid BOM CSV rows', es: 'Importar listas de materiales válidas CSV' }, + clients_and_providers_scan_file: { en: 'Scan clients and providers CSV file', es: 'Escanear archivo de clientes y proveedores CSV' }, + clients_and_providers_insert_valid_rows: { en: 'Import valid clients and providers CSV rows', es: 'Importar clientes y proveedores válidos CSV' }, + pedmientos_scan_file: { en: 'Scan pedimentos CSV file', es: 'Escanear archivo de pedimentos CSV' }, + pedmientos_insert_valid_rows: { en: 'Import valid pedimentos CSV rows', es: 'Importar pedimentos válidos CSV' }, + us_tariff_fractions_scan_file: { en: 'Scan US tariff fractions CSV file', es: 'Escanear archivo de fracciones arancelarias EUA CSV' }, + us_tariff_fractions_insert_valid_rows: { en: 'Import valid US tariff fractions CSV rows', es: 'Importar fracciones arancelarias EUA válidas CSV' }, + parts_scan_file: { en: 'Scan parts CSV file', es: 'Escanear archivo de partes CSV' }, + parts_insert_valid_rows: { en: 'Import valid parts CSV rows', es: 'Importar partes válidas CSV' }, + cambio_regimen_regularizacion_scan_file: { en: 'Scan regime change CSV file', es: 'Escanear archivo de cambio de régimen CSV' }, + cambio_regimen_regularizacion_insert_valid_rows: { en: 'Import valid regime change CSV rows', es: 'Importar cambio de régimen válido CSV' }, + facturas_scan_file: { en: 'Scan invoices CSV file', es: 'Escanear archivo de facturas CSV' }, + facturas_insert_valid_rows: { en: 'Import valid invoices CSV rows', es: 'Importar facturas válidas CSV' }, + transportistas_scan_file: { en: 'Scan carriers CSV file', es: 'Escanear archivo de transportistas CSV' }, + cleanup_orphan_layout_imports: { en: 'Clean orphan CSV imports', es: 'Limpiar importaciones CSV huérfanas' }, + // expediente archivos + expediente_archivos_digitalizar: { en: 'Digitize expediente file', es: 'Digitalizar archivo de expediente' } +}; + +const CELERY_STATE_TRANSLATIONS: Record = { + SUCCESS: { en: 'Succeeded', es: 'Exitoso' }, + FAILURE: { en: 'Failed', es: 'Fallido' }, + PENDING: { en: 'Pending', es: 'Pendiente' }, + STARTED: { en: 'Started', es: 'Iniciado' }, + RETRY: { en: 'Retrying', es: 'Reintentando' }, + REVOKED: { en: 'Revoked', es: 'Cancelado' }, + PROGRESS: { en: 'In progress', es: 'En progreso' } +}; + +export function translateTaskGroup(value: string): string { + if (!value) return value; + const locale = currentLocale(); + return TASK_GROUP_TRANSLATIONS[value]?.[locale] ?? value; +} + +export function translateTaskName(value: string): string { + if (!value) return value; + const locale = currentLocale(); + return TASK_NAME_TRANSLATIONS[value]?.[locale] ?? value.replace(/_/g, ' '); +} + +export function translateCeleryState(value: string): string { + if (!value) return value; + const locale = currentLocale(); + return CELERY_STATE_TRANSLATIONS[value.toUpperCase()]?.[locale] ?? value; +} diff --git a/frontend/src/routes/dashboard/audit_logs/bitacora-tab.svelte b/frontend/src/routes/dashboard/audit_logs/bitacora-tab.svelte index 0269e9e3..4b02f35a 100644 --- a/frontend/src/routes/dashboard/audit_logs/bitacora-tab.svelte +++ b/frontend/src/routes/dashboard/audit_logs/bitacora-tab.svelte @@ -1,5 +1,6 @@