diff --git a/frontend/components/tabs/Law10Tab.tsx b/frontend/components/tabs/Law10Tab.tsx
index 9c8d5c3..89a89e2 100644
--- a/frontend/components/tabs/Law10Tab.tsx
+++ b/frontend/components/tabs/Law10Tab.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { useTranslation } from 'react-i18next';
import {
Scale,
Clock,
@@ -65,7 +66,7 @@ const LAW_10_2025 = {
// FUNCIONES DE EVALUACION DE COMPLIANCE
// ============================================
-function evaluateLaw07Compliance(data: AnalysisData): ComplianceResult {
+function evaluateLaw07Compliance(data: AnalysisData, t: (key: string, options?: any) => string): ComplianceResult {
// Evaluar cobertura horaria basado en off_hours_pct
const volumetryDim = data.dimensions.find(d => d.name === 'volumetry_distribution');
const offHoursPct = volumetryDim?.distribution_data?.off_hours_pct ?? null;
@@ -74,39 +75,39 @@ function evaluateLaw07Compliance(data: AnalysisData): ComplianceResult {
return {
status: 'SIN_DATOS',
score: 0,
- gap: 'Sin datos de distribucion horaria',
- details: ['No se encontraron datos de distribucion horaria en el analisis'],
+ gap: t('law10.compliance.law07.noData'),
+ details: [t('law10.compliance.law07.noDataDetails')],
};
}
const details: string[] = [];
- details.push(`${offHoursPct.toFixed(1)}% de interacciones fuera de horario laboral`);
+ details.push(t('law10.compliance.law07.offHoursPercent', { percent: offHoursPct.toFixed(1) }));
if (offHoursPct < 5) {
return {
status: 'CUMPLE',
score: 100,
gap: '-',
- details: [...details, 'Cobertura horaria adecuada'],
+ details: [...details, t('law10.compliance.law07.adequateCoverage')],
};
} else if (offHoursPct <= 15) {
return {
status: 'PARCIAL',
score: Math.round(100 - ((offHoursPct - 5) / 10) * 50),
- gap: `${(offHoursPct - 5).toFixed(1)}pp sobre optimo`,
- details: [...details, 'Cobertura horaria mejorable - considerar ampliar horarios'],
+ gap: t('law10.compliance.law07.gapOverOptimal', { gap: (offHoursPct - 5).toFixed(1) }),
+ details: [...details, t('law10.compliance.law07.improvableCoverage')],
};
} else {
return {
status: 'NO_CUMPLE',
score: Math.max(0, Math.round(50 - ((offHoursPct - 15) / 10) * 50)),
- gap: `${(offHoursPct - 15).toFixed(1)}pp sobre limite`,
- details: [...details, 'Cobertura horaria insuficiente - requiere accion inmediata'],
+ gap: t('law10.compliance.law07.gapOverLimit', { gap: (offHoursPct - 15).toFixed(1) }),
+ details: [...details, t('law10.compliance.law07.insufficientCoverage')],
};
}
}
-function evaluateLaw01Compliance(data: AnalysisData): ComplianceResult {
+function evaluateLaw01Compliance(data: AnalysisData, t: (key: string, options?: any) => string): ComplianceResult {
// Evaluar tiempo de espera (hold_time) vs limite de 180 segundos
const totalVolume = data.heatmapData.reduce((sum, h) => sum + h.volume, 0);
@@ -114,8 +115,8 @@ function evaluateLaw01Compliance(data: AnalysisData): ComplianceResult {
return {
status: 'SIN_DATOS',
score: 0,
- gap: 'Sin datos de tiempos de espera',
- details: ['No se encontraron datos de hold_time en el analisis'],
+ gap: t('law10.compliance.law01.noData'),
+ details: [t('law10.compliance.law01.noDataDetails')],
};
}
@@ -135,35 +136,35 @@ function evaluateLaw01Compliance(data: AnalysisData): ComplianceResult {
const pctDentroLimite = (volDentroLimite / totalVolume) * 100;
const details: string[] = [];
- details.push(`Tiempo de espera promedio: ${Math.round(avgHoldTime)}s (limite: 180s)`);
- details.push(`${pctDentroLimite.toFixed(1)}% de interacciones dentro del limite`);
- details.push(`${colasExceden.length} de ${data.heatmapData.length} colas exceden el limite`);
+ details.push(t('law10.compliance.law01.avgHoldTime', { time: Math.round(avgHoldTime) }));
+ details.push(t('law10.compliance.law01.withinLimit', { percent: pctDentroLimite.toFixed(1) }));
+ details.push(t('law10.compliance.law01.queuesExceedLimit', { count: colasExceden.length, total: data.heatmapData.length }));
if (avgHoldTime < 180 && pctColasExceden < 10) {
return {
status: 'CUMPLE',
score: 100,
- gap: `-${Math.round(180 - avgHoldTime)}s`,
+ gap: t('law10.compliance.law01.gapNegative', { gap: Math.round(180 - avgHoldTime) }),
details,
};
} else if (avgHoldTime < 180) {
return {
status: 'PARCIAL',
score: Math.round(90 - pctColasExceden),
- gap: `${colasExceden.length} colas fuera`,
+ gap: t('law10.compliance.law01.queuesOutside', { count: colasExceden.length }),
details,
};
} else {
return {
status: 'NO_CUMPLE',
score: Math.max(0, Math.round(50 - ((avgHoldTime - 180) / 60) * 25)),
- gap: `+${Math.round(avgHoldTime - 180)}s`,
+ gap: t('law10.compliance.law01.gapPositive', { gap: Math.round(avgHoldTime - 180) }),
details,
};
}
}
-function evaluateLaw02Compliance(data: AnalysisData): ComplianceResult {
+function evaluateLaw02Compliance(data: AnalysisData, t: (key: string, options?: any) => string): ComplianceResult {
// Evaluar FCR y tasa de transferencia
const totalVolume = data.heatmapData.reduce((sum, h) => sum + h.volume, 0);
@@ -171,8 +172,8 @@ function evaluateLaw02Compliance(data: AnalysisData): ComplianceResult {
return {
status: 'SIN_DATOS',
score: 0,
- gap: 'Sin datos de resolucion',
- details: ['No se encontraron datos de FCR o transferencias'],
+ gap: t('law10.compliance.law02.noData'),
+ details: [t('law10.compliance.law02.noDataDetails')],
};
}
@@ -187,13 +188,13 @@ function evaluateLaw02Compliance(data: AnalysisData): ComplianceResult {
) / totalVolume;
const details: string[] = [];
- details.push(`FCR Tecnico: ${avgFCR.toFixed(1)}% (objetivo: >75%)`);
- details.push(`Tasa de transferencia: ${avgTransfer.toFixed(1)}% (objetivo: <15%)`);
+ details.push(t('law10.compliance.law02.fcrTechnical', { fcr: avgFCR.toFixed(1) }));
+ details.push(t('law10.compliance.law02.transferRate', { rate: avgTransfer.toFixed(1) }));
// Colas con alto transfer
const colasAltoTransfer = data.heatmapData.filter(h => h.metrics.transfer_rate > 25);
if (colasAltoTransfer.length > 0) {
- details.push(`${colasAltoTransfer.length} colas con transfer >25%`);
+ details.push(t('law10.compliance.law02.highTransferQueues', { count: colasAltoTransfer.length }));
}
const cumpleFCR = avgFCR >= 75;
@@ -205,7 +206,7 @@ function evaluateLaw02Compliance(data: AnalysisData): ComplianceResult {
return {
status: 'CUMPLE',
score: 100,
- gap: '-',
+ gap: t('law10.compliance.law02.gapDash'),
details,
};
} else if (parcialFCR && parcialTransfer) {
@@ -213,31 +214,33 @@ function evaluateLaw02Compliance(data: AnalysisData): ComplianceResult {
(Math.min(avgFCR, 75) / 75 * 50) +
(Math.max(0, 25 - avgTransfer) / 25 * 50)
);
+ const fcrGap = avgFCR < 75 ? t('law10.compliance.law02.gapNegative', { gap: (75 - avgFCR).toFixed(0) }) : t('law10.compliance.law02.gapOk');
+ const transferGap = avgTransfer > 15 ? t('law10.compliance.law02.gapPositive', { gap: (avgTransfer - 15).toFixed(0) }) : t('law10.compliance.law02.gapOk');
return {
status: 'PARCIAL',
score,
- gap: `FCR ${avgFCR < 75 ? `-${(75 - avgFCR).toFixed(0)}pp` : 'OK'}, Transfer ${avgTransfer > 15 ? `+${(avgTransfer - 15).toFixed(0)}pp` : 'OK'}`,
+ gap: t('law10.compliance.law02.gapFcr', { fcrGap, transferGap }),
details,
};
} else {
return {
status: 'NO_CUMPLE',
score: Math.max(0, Math.round((avgFCR / 75 * 30) + ((30 - avgTransfer) / 30 * 20))),
- gap: `FCR -${(75 - avgFCR).toFixed(0)}pp, Transfer +${(avgTransfer - 15).toFixed(0)}pp`,
+ gap: `FCR ${t('law10.compliance.law02.gapNegative', { gap: (75 - avgFCR).toFixed(0) })}, Transfer ${t('law10.compliance.law02.gapPositive', { gap: (avgTransfer - 15).toFixed(0) })}`,
details,
};
}
}
-function evaluateLaw09Compliance(_data: AnalysisData): ComplianceResult {
+function evaluateLaw09Compliance(_data: AnalysisData, t: (key: string, options?: any) => string): ComplianceResult {
// Los datos de idioma no estan disponibles en el modelo actual
return {
status: 'SIN_DATOS',
score: 0,
- gap: 'Requiere datos',
+ gap: t('law10.compliance.law09.noData'),
details: [
- 'No se dispone de datos de idioma en las interacciones',
- 'Para evaluar este requisito se necesita el campo "language" en el CSV',
+ t('law10.compliance.law09.noLanguageData'),
+ t('law10.compliance.law09.needsLanguageField'),
],
};
}
@@ -273,12 +276,12 @@ function getStatusBadgeVariant(status: ComplianceStatus): 'success' | 'warning'
}
}
-function getStatusLabel(status: ComplianceStatus): string {
+function getStatusLabel(status: ComplianceStatus, t: (key: string) => string): string {
switch (status) {
- case 'CUMPLE': return 'Cumple';
- case 'PARCIAL': return 'Parcial';
- case 'NO_CUMPLE': return 'No Cumple';
- default: return 'Sin Datos';
+ case 'CUMPLE': return t('law10.status.CUMPLE');
+ case 'PARCIAL': return t('law10.status.PARCIAL');
+ case 'NO_CUMPLE': return t('law10.status.NO_CUMPLE');
+ default: return t('law10.status.SIN_DATOS');
}
}
@@ -288,6 +291,7 @@ function Law10HeaderCountdown({
}: {
complianceResults: { law07: ComplianceResult; law01: ComplianceResult; law02: ComplianceResult; law09: ComplianceResult };
}) {
+ const { t } = useTranslation();
const now = new Date();
const deadline = LAW_10_2025.deadline;
const diffTime = deadline.getTime() - now.getTime();
@@ -314,18 +318,14 @@ function Law10HeaderCountdown({
Ley 10/2025 de Atencion al Cliente
+{t('law10.header.lawTitle')}
- Este modulo conecta tus metricas operacionales actuales con los requisitos de la - Ley 10/2025. No mide compliance directamente (requeriria datos adicionales), pero SI - identifica patrones que impactan en tu capacidad de cumplir con la normativa. -
+Deadline de cumplimiento
-28 Diciembre 2026
-{diffDays} dias restantes
+{t('law10.header.complianceDeadline')}
+{t('law10.header.december282026')}
+{t('law10.header.daysRemaining', { days: diffDays })}
Requisitos evaluados
-{cumplidos} de {total} cumplen
-Basado en datos disponibles
+{t('law10.header.requirementsEvaluated')}
+{t('law10.header.requirementsMet', { met: cumplidos, total })}
+{t('law10.header.basedOnData')}
Estado general
+{t('law10.header.overallStatus')}
- {getStatusLabel(overallStatus)} + {getStatusLabel(overallStatus, t)}
- {overallStatus === 'CUMPLE' ? 'Buen estado' : - overallStatus === 'PARCIAL' ? 'Requiere atencion' : 'Accion urgente'} + {overallStatus === 'CUMPLE' ? t('law10.header.goodState') : + overallStatus === 'PARCIAL' ? t('law10.header.requiresAttention') : t('law10.header.urgentAction')}
Relacionado con Art. 14 - Servicios basicos 24/7
+{t('law10.timeCoverage.article')}
HEATMAP VOLUMETRICO 24x7
+{t('law10.timeCoverage.heatmap247')}
{/* Header de horas */}Hallazgos operacionales:
+{t('law10.timeCoverage.operationalFindings')}
- Transporte aereo = Servicio basico
- → Art. 14 requiere atencion 24/7 para incidencias
+ {t('law10.timeCoverage.basicServiceRequirement')}
+ {t('law10.timeCoverage.article14Requirement')}
Gap identificado:
+{t('law10.timeCoverage.gapIdentified')}
1. Clasificar volumen nocturno por tipo:
+{t('law10.timeCoverage.classifyNightVolume')}
2. Opciones de cobertura:
+{t('law10.timeCoverage.coverageOptions')}
Relacionado con Art. 8.2 - 95% llamadas <3min
+{t('law10.responseSpeed.article')}
{abandonRate.toFixed(1)}%
-Tasa abandono
+{t('law10.responseSpeed.abandonmentRate')}
{Math.round(ahtP50)}s
-AHT P50 ({Math.floor(ahtP50 / 60)}m {Math.round(ahtP50 % 60)}s)
+{t('law10.responseSpeed.ahtP50', { min: Math.floor(ahtP50 / 60), sec: Math.round(ahtP50 % 60) })}
{Math.round(ahtP90)}s
-AHT P90 ({Math.floor(ahtP90 / 60)}m {Math.round(ahtP90 % 60)}s)
+{t('law10.responseSpeed.ahtP90', { min: Math.floor(ahtP90 / 60), sec: Math.round(ahtP90 % 60) })}
Ratio P90/P50 {ahtRatio > 2 && '(elevado)'}
+{t('law10.responseSpeed.ratioP90P50', { elevated: ahtRatio > 2 ? t('law10.responseSpeed.elevated') : '' })}
DISTRIBUCION DE ABANDONOS POR HORA
+{t('law10.responseSpeed.abandonmentByHour')}
Patrones observados:
+{t('law10.responseSpeed.patternsObserved')}
- Art. 8.2 requiere: "95% de llamadas atendidas en <3 minutos" -
+
- Tu CDR actual NO incluye ASA (tiempo en cola antes de responder), - por lo que NO podemos medir este requisito directamente. + {t('law10.responseSpeed.noAsaData')}
PERO SI sabemos:
+{t('law10.responseSpeed.butWeKnow')}
Estimacion conservadora (±10% margen error):
-- → ~{estimatedFastResponse.toFixed(0)}% de llamadas probablemente atendidas "rapido" -
+{t('law10.responseSpeed.conservativeEstimate')}
+0 ? 'text-red-600' : 'text-emerald-600' - )}> - → Gap vs 95% requerido: {gapVs95 > 0 ? '-' : '+'}{Math.abs(gapVs95).toFixed(0)} puntos porcentuales -
+ )} dangerouslySetInnerHTML={{ __html: t('law10.responseSpeed.gapVs95', { operator: gapVs95 > 0 ? '-' : '+', gap: Math.abs(gapVs95).toFixed(0) }) }} />1. CORTO PLAZO: Reducir AHT para aumentar capacidad
+{t('law10.responseSpeed.shortTerm')}
2. MEDIO PLAZO: Implementar tracking ASA real
+{t('law10.responseSpeed.mediumTerm')}
Beneficio: Medicion precisa para auditoria ENAC
+{t('law10.responseSpeed.benefit')}
Relacionado con Art. 17 - Resolucion en 15 dias
+{t('law10.resolutionQuality.article')}
FCR Real (fcr_real_flag)
+{t('law10.resolutionQuality.fcrReal')}
{recontactRate7d.toFixed(0)}%
-Tasa recontacto 7 dias
+{t('law10.resolutionQuality.recontactRate7d')}
{repeatCallsPct.toFixed(0)}%
-Llamadas repetidas
+{t('law10.resolutionQuality.repeatCalls')}
FCR POR SKILL/QUEUE
+{t('law10.resolutionQuality.fcrBySkill')}
Top skills con FCR bajo:
+{t('law10.resolutionQuality.topLowFcr')}
- Art. 17 requiere: "Resolucion de reclamaciones ≤15 dias" -
+
- Tu CDR solo registra interacciones individuales, NO casos multi-touch - ni tiempo total de resolucion. + {t('law10.resolutionQuality.noCaseTracking')}
PERO SI sabemos:
+{t('law10.resolutionQuality.butWeKnow')}
Senal de alerta:
+{t('law10.resolutionQuality.alertSignal')}
- Si los clientes recontactan multiples veces por el mismo tema, es probable - que el tiempo TOTAL de resolucion supere los 15 dias requeridos por ley. + {t('law10.resolutionQuality.resolutionTimeRisk')}
1. DIAGNOSTICO: Implementar sistema de casos/tickets
+{t('law10.resolutionQuality.diagnosis')}
2. MEJORA OPERATIVA: Aumentar FCR
+{t('law10.resolutionQuality.operationalImprovement')}
- Factibilidad (Score) vs Impacto Económico (Ahorro TCO) • Tamaño = Volumen • Color = Tier + {t('roadmap.opportunityMapSubtitle')}
- Interpretación: Las burbujas en el cuadrante superior derecho (Score alto + Ahorro alto) - son Quick Wins para automatización. El tamaño indica volumen de interacciones. + {t('roadmap.interpretation')} {t('roadmap.opportunityMapInterpretation')}
- Score Agentic Readiness calculado con 5 factores ponderados: + {t('roadmap.axisXFactibilityDesc')}
- Ahorro TCO calculado según tier con CPI diferencial: + {t('roadmap.axisYEconomicImpactDesc')}
@@ -778,49 +780,49 @@ function OpportunityBubbleChart({ {/* Fórmulas por Tier */}
AUTOMATE (Score ≥ 7.5)
+{t('roadmap.formulaAutomate')}
- Ahorro = Vol × 12 × 70% × (€2.33 - €0.15) + {t('roadmap.formulaAutomateCalc')}
-= Vol × 12 × 0.70 × €2.18
+{t('roadmap.formulaAutomateResult')}
ASSIST (Score ≥ 5.5)
+{t('roadmap.formulaAssist')}
- Ahorro = Vol × 12 × 30% × (€2.33 - €1.50) + {t('roadmap.formulaAssistCalc')}
-= Vol × 12 × 0.30 × €0.83
+{t('roadmap.formulaAssistResult')}
AUGMENT (Score ≥ 3.5)
+{t('roadmap.formulaAugment')}
- Ahorro = Vol × 12 × 15% × (€2.33 - €2.00) + {t('roadmap.formulaAugmentCalc')}
-= Vol × 12 × 0.15 × €0.33
+{t('roadmap.formulaAugmentResult')}
HUMAN-ONLY (Score < 3.5 o Red Flags)
+{t('roadmap.formulaHumanOnly')}
- Ahorro = €0 + {t('roadmap.formulaHumanOnlyCalc')}
-Requiere estandarización previa
+{t('roadmap.formulaHumanOnlyRequires')}
AUTOMATE
@@ -871,9 +873,7 @@ function OpportunityBubbleChart({ {/* Nota metodológica */}- Nota: El tamaño de las burbujas representa el volumen de interacciones. - Las colas clasificadas como HUMAN-ONLY no aparecen en el gráfico (ahorro = €0). - Los ahorros son proyecciones basadas en benchmarks de industria y deben validarse con pilotos. + {t('roadmap.methodologicalNote')} {t('roadmap.methodologicalNoteText')}
🎯 Por qué es necesario:
+🎯 {t('roadmap.whyNecessary')}
{wave.porQueNecesario}
- {totalQueues} colas clasificadas en 4 Tiers según su preparación para IA • {totalVolume.toLocaleString()} interacciones/mes + {t('roadmap.queuesClassifiedDescription', { count: totalQueues, volume: totalVolume.toLocaleString() })}
TIER 1
+{t('roadmap.tier1')}
AUTOMATE
{tierCounts.AUTOMATE.length}
- {tierVolumes.AUTOMATE.toLocaleString()} int/mes + {tierVolumes.AUTOMATE.toLocaleString()} {t('roadmap.intPerMonth')}
- ({Math.round((tierVolumes.AUTOMATE / totalVolume) * 100)}% volumen) + {t('roadmap.volumePercentage', { pct: Math.round((tierVolumes.AUTOMATE / totalVolume) * 100) })}
- {formatCurrency(potentialSavings.AUTOMATE)}/año + {formatCurrency(potentialSavings.AUTOMATE)}{t('roadmap.perYear')}
TIER 2
+{t('roadmap.tier2')}
ASSIST
{tierCounts.ASSIST.length}
- {tierVolumes.ASSIST.toLocaleString()} int/mes + {tierVolumes.ASSIST.toLocaleString()} {t('roadmap.intPerMonth')}
- ({Math.round((tierVolumes.ASSIST / totalVolume) * 100)}% volumen) + {t('roadmap.volumePercentage', { pct: Math.round((tierVolumes.ASSIST / totalVolume) * 100) })}
- {formatCurrency(potentialSavings.ASSIST)}/año + {formatCurrency(potentialSavings.ASSIST)}{t('roadmap.perYear')}
TIER 3
+{t('roadmap.tier3')}
AUGMENT
{tierCounts.AUGMENT.length}
- {tierVolumes.AUGMENT.toLocaleString()} int/mes + {tierVolumes.AUGMENT.toLocaleString()} {t('roadmap.intPerMonth')}
- ({Math.round((tierVolumes.AUGMENT / totalVolume) * 100)}% volumen) + {t('roadmap.volumePercentage', { pct: Math.round((tierVolumes.AUGMENT / totalVolume) * 100) })}
- {formatCurrency(potentialSavings.AUGMENT)}/año + {formatCurrency(potentialSavings.AUGMENT)}{t('roadmap.perYear')}
TIER 4
+{t('roadmap.tier4')}
HUMAN-ONLY
{tierCounts['HUMAN-ONLY'].length}
- {tierVolumes['HUMAN-ONLY'].toLocaleString()} int/mes + {tierVolumes['HUMAN-ONLY'].toLocaleString()} {t('roadmap.intPerMonth')}
- ({Math.round((tierVolumes['HUMAN-ONLY'] / totalVolume) * 100)}% volumen) + {t('roadmap.volumePercentage', { pct: Math.round((tierVolumes['HUMAN-ONLY'] / totalVolume) * 100) })}
- €0/año (Red flags) + {t('roadmap.noSavingsRedFlags')}
Distribución del volumen por tier:
+{t('roadmap.volumeDistributionByTier')}
¿Qué significa Foundation?
+{t('roadmap.whatIsFoundation')}
- La operación actual no tiene colas listas para automatizar directamente. - Foundation es la fase de preparación: estandarizar procesos, reducir variabilidad - y mejorar la calidad de datos para que la automatización posterior sea efectiva. + {t('roadmap.foundationExplanation')}
- {tierCounts.ASSIST.length} colas ASSIST ({Math.round(assistPct)}% del volumen) - pueden elevarse a Tier AUTOMATE tras completar Wave 1-2. + {t('roadmap.assistQueuesCanElevate', { count: tierCounts.ASSIST.length, pct: Math.round(assistPct) })}
Inversión
+{t('roadmap.investment')}
{formatCurrency(wave1Setup + wave2Setup)}
Timeline
-6-9 meses
+{t('roadmap.timeline')}
+6-9 {t('roadmap.months', { count: 6 }).toLowerCase()}
Ahorro habilitado
-{formatCurrency(potentialSavings.ASSIST)}/año
+{t('roadmap.enabledSavings')}
+{formatCurrency(potentialSavings.ASSIST)}{t('roadmap.perYear')}
¿Por qué estandarización primero?
+{t('roadmap.whyStandardizationFirst')}
- Se han detectado "red flags" operativos críticos (alta variabilidad, muchas transferencias) - que harían fracasar cualquier proyecto de automatización. Invertir en IA ahora sería - malgastar recursos. Primero hay que estabilizar la operación. + {t('roadmap.standardizationExplanation')}
- {Math.round(humanOnlyPct + augmentPct)}% del volumen presenta red flags (CV >75%, Transfer >20%). - Wave 1 es una inversión habilitadora sin retorno directo inmediato. + {t('roadmap.volumeWithRedFlags', { pct: Math.round(humanOnlyPct + augmentPct) })}
Inversión Wave 1
+{t('roadmap.investmentWave1')}
{formatCurrency(wave1Setup)}
Timeline
-3-4 meses
+{t('roadmap.timeline')}
+3-4 {t('roadmap.months', { count: 3 }).toLowerCase()}
Ahorro directo
-€0 (habilitador)
+{t('roadmap.directSavings')}
+{t('roadmap.enablingNoDirectSavings')}
Siguiente paso recomendado:
+{t('roadmap.nextRecommendedStep')}
{recType === 'DUAL' && ( - <>Iniciar piloto de automatización con las {pilotQueues.length} colas AUTOMATE, mientras se ejecuta Wave 1 (Foundation) en paralelo para preparar el resto.> + t('roadmap.nextStepDual', { count: pilotQueues.length }) )} {recType === 'FOUNDATION' && ( - <>Comenzar Wave 1 focalizando en las {Math.min(10, tierCounts['HUMAN-ONLY'].length)} colas de mayor volumen. Medir progreso mensual en CV y Transfer.> + t('roadmap.nextStepFoundation', { count: Math.min(10, tierCounts['HUMAN-ONLY'].length) }) )} {recType === 'STANDARDIZATION' && ( - <>Realizar workshop de diagnóstico operacional para identificar las causas raíz de los red flags antes de planificar inversiones.> + t('roadmap.nextStepStandardization') )}
Iniciativas, criterios de entrada/salida, inversión por fase
+{t('roadmap.waveDetailDescription')}