diff --git a/frontend/components/tabs/Law10Tab.tsx b/frontend/components/tabs/Law10Tab.tsx
index 89a89e2..4504fa0 100644
--- a/frontend/components/tabs/Law10Tab.tsx
+++ b/frontend/components/tabs/Law10Tab.tsx
@@ -1209,7 +1209,7 @@ function Law10SummaryRoadmap({
- Resumen de Cumplimiento - Todos los Requisitos
+ {t('law10.summary.title')}
{/* Scorecard con todos los requisitos */}
diff --git a/frontend/utils/backendMapper.ts b/frontend/utils/backendMapper.ts
index fc240ac..2901010 100644
--- a/frontend/utils/backendMapper.ts
+++ b/frontend/utils/backendMapper.ts
@@ -514,18 +514,18 @@ function buildComplexityPredictabilityDimension(
if (!op) return undefined;
// KPI principal: CV AHT (industry standard for predictability/WFM)
- // CV AHT = (P90 - P50) / P50 como proxy de coeficiente de variación
+ // CV AHT = (P90 - P50) / P50 as a proxy for coefficient of variation
const ahtP50 = safeNumber(op.aht_distribution?.p50, 0);
const ahtP90 = safeNumber(op.aht_distribution?.p90, 0);
- // Calcular CV AHT como (P90-P50)/P50 (proxy del coeficiente de variación real)
+ // Calculate CV AHT as (P90-P50)/P50 (proxy for the actual coefficient of variation)
let cvAht = 0;
if (ahtP50 > 0 && ahtP90 > 0) {
cvAht = (ahtP90 - ahtP50) / ahtP50;
}
const cvAhtPercent = Math.round(cvAht * 100);
- // Hold Time como métrica secundaria de complejidad
+ // Hold Time as a secondary metric for complexity
const talkHoldAcw = op.talk_hold_acw_p50_by_skill;
let avgHoldP50 = 0;
if (Array.isArray(talkHoldAcw) && talkHoldAcw.length > 0) {
@@ -604,7 +604,7 @@ function buildSatisfactionDimension(
const hasCSATData = Number.isFinite(csatGlobalRaw) && csatGlobalRaw > 0;
- // Si no hay CSAT, mostrar dimensión con "Not available"
+ // If no CSAT, show dimension with "Not available"
const dimension: DimensionAnalysis = {
id: 'customer_satisfaction',
name: 'customer_satisfaction',
@@ -702,7 +702,7 @@ function buildEconomyDimension(
return dimension;
}
-// ==== Agentic Readiness como dimensión (v3.0) ====
+// ==== Agentic Readiness as a dimension (v3.0) ====
function buildAgenticReadinessDimension(
raw: BackendRawResults,
@@ -720,7 +720,7 @@ function buildAgenticReadinessDimension(
if (ar) {
score0_10 = safeNumber(ar.final_score, 5);
} else {
- // Calcular aproximado desde métricas disponibles
+ // Calculate approximation from available metrics
const ahtP50 = safeNumber(op?.aht_distribution?.p50, 0);
const ahtP90 = safeNumber(op?.aht_distribution?.p90, 0);
const ratio = ahtP50 > 0 ? ahtP90 / ahtP50 : 2;
@@ -870,7 +870,7 @@ function buildEconomicModel(raw: BackendRawResults): EconomicModelData {
};
}
-// buildEconomyDimension eliminado en v3.0 - economía integrada en otras dimensiones y modelo económico
+// buildEconomyDimension removed in v3.0 - economy integrated into other dimensions and economic model
/**
* Transforma el JSON del backend (results) al AnalysisData
@@ -957,19 +957,19 @@ export function mapBackendResultsToAnalysisData(
// Summary KPIs (the first 4 are shown in "Contact Metrics")
const summaryKpis: Kpi[] = [];
- // 1) Interacciones Totales (volumen backend)
+ // 1) Total Interactions (backend volume)
summaryKpis.push({
- label: 'Interacciones Totales',
+ label: 'Total Interactions',
value:
totalVolume > 0
? totalVolume.toLocaleString('es-ES')
: 'N/D',
});
- // 2) AHT Promedio (P50 de distribución de AHT)
+ // 2) Average AHT (P50 of AHT distribution)
const ahtP50 = safeNumber(op?.aht_distribution?.p50, 0);
summaryKpis.push({
- label: 'AHT Promedio',
+ label: 'Average AHT',
value: ahtP50
? `${Math.round(ahtP50)}s`
: 'N/D',
@@ -1014,7 +1014,7 @@ export function mapBackendResultsToAnalysisData(
value: `${arScore.toFixed(1)}/10`,
});
- // KPIs de economía (backend)
+ // Economy KPIs (backend)
const econ = raw?.economy_costs;
const totalAnnual = safeNumber(
econ?.cost_breakdown?.total_annual,
@@ -1047,7 +1047,7 @@ export function mapBackendResultsToAnalysisData(
const findings: Finding[] = [];
const recommendations: Recommendation[] = [];
- // Extraer offHoursPct de la dimensión de volumetría
+ // Extract offHoursPct from the volumetry dimension
const offHoursPct = volumetryDimension?.distribution_data?.off_hours_pct ?? 0;
const offHoursPctValue = offHoursPct * 100; // Convert from 0-1 a 0-100
@@ -1070,7 +1070,7 @@ export function mapBackendResultsToAnalysisData(
text: `Deploy virtual agent to handle ${offHoursPctValue.toFixed(0)}% of off-hours interactions`,
description: `${offHoursVolume.toLocaleString()} interactions occur outside business hours (19:00-08:00). A virtual agent can resolve ~${estimatedContainment}% of these queries automatically.`,
dimensionId: 'volumetry_distribution',
- impact: `Containment potential: ${estimatedSavings.toLocaleString()} interacciones/período`,
+ impact: `Containment potential: ${estimatedSavings.toLocaleString()} interactions/period`,
timeline: '1-3 months'
});
}
@@ -1153,8 +1153,8 @@ export function buildHeatmapFromBackend(
const abandonmentRateBackend = safeNumber(op?.abandonment_rate, 0);
// ========================================================================
- // NUEVO: Métricas REALES por skill (transfer, abandonment, FCR)
- // Esto elimina la estimación de transfer rate basada en CV y hold time
+ // NEW: REAL metrics per skill (transfer, abandonment, FCR)
+ // This eliminates the transfer rate estimation based on CV and hold time
// ========================================================================
const metricsBySkillRaw = Array.isArray(op?.metrics_by_skill)
? op.metrics_by_skill
@@ -1251,7 +1251,7 @@ export function buildHeatmapFromBackend(
if (!skillLabels.length) return [];
- // Para normalizar la repetitividad según volumen
+ // To normalize repetitiveness according to volume
const volumesForNorm = skillVolumes.filter((v) => v > 0);
const minVol =
volumesForNorm.length > 0
@@ -1268,13 +1268,13 @@ export function buildHeatmapFromBackend(
const skill = skillLabels[i];
const volume = safeNumber(skillVolumes[i], 0);
- // Buscar P50s por nombre de skill (no por índice)
+ // Search for P50s by skill name (not by index)
const talkHold = talkHoldAcwMap.get(skill);
const talk_p50 = talkHold?.talk_p50 ?? 0;
const hold_p50 = talkHold?.hold_p50 ?? 0;
const acw_p50 = talkHold?.acw_p50 ?? 0;
- // Buscar métricas REALES del backend (metrics_by_skill)
+ // Search for REAL metrics from backend (metrics_by_skill)
const realSkillMetrics = metricsBySkillMap.get(skill);
// AHT: Use ONLY aht_mean from backend metrics_by_skill
@@ -1284,7 +1284,7 @@ export function buildHeatmapFromBackend(
: 0;
// AHT Total: AHT calculado con TODAS las filas (incluye NOISE/ZOMBIE/ABANDON)
- // Solo para información/comparación - no se usa en cálculos
+ // Only for information/comparison - not used in calculations
const aht_total = (realSkillMetrics && Number.isFinite(realSkillMetrics.aht_total) && realSkillMetrics.aht_total > 0)
? realSkillMetrics.aht_total
: aht_mean; // fallback to aht_mean if not available
@@ -1299,7 +1299,7 @@ export function buildHeatmapFromBackend(
annual_volume * aht_mean * COST_PER_SECOND
);
- // Buscar inefficiency data por nombre de skill (no por índice)
+ // Search for inefficiency data by skill name (not by index)
const ineff = ineffBySkillMap.get(skill);
const aht_p50_backend = ineff?.aht_p50 ?? aht_mean;
const aht_p90_backend = ineff?.aht_p90 ?? aht_mean;
@@ -1311,7 +1311,7 @@ export function buildHeatmapFromBackend(
(aht_p90_backend - aht_p50_backend) / aht_p50_backend;
}
- // Dimensiones agentic similares a las que tenías en generateHeatmapData,
+ // Agentic dimensions similar to those you had in generateHeatmapData,
// pero usando valores reales en lugar de aleatorios.
// 1) Predictability (lower CV => higher score)
@@ -1324,8 +1324,8 @@ export function buildHeatmapFromBackend(
);
// 2) Transfer rate POR SKILL
- // PRIORIDAD 1: Usar métricas REALES del backend (metrics_by_skill)
- // PRIORIDAD 2: Fallback a estimación basada en CV y hold time
+ // PRIORITY 1: Use REAL metrics from backend (metrics_by_skill)
+ // PRIORITY 2: Fallback to estimation based on CV and hold time
let skillTransferRate: number;
let skillAbandonmentRate: number;
@@ -1333,7 +1333,7 @@ export function buildHeatmapFromBackend(
let skillFcrReal: number;
if (realSkillMetrics && Number.isFinite(realSkillMetrics.transfer_rate)) {
- // Usar métricas REALES del backend
+ // Use REAL metrics from backend
skillTransferRate = realSkillMetrics.transfer_rate;
skillAbandonmentRate = Number.isFinite(realSkillMetrics.abandonment_rate)
? realSkillMetrics.abandonment_rate
diff --git a/frontend/utils/dataTransformation.ts b/frontend/utils/dataTransformation.ts
index dba39a1..4569710 100644
--- a/frontend/utils/dataTransformation.ts
+++ b/frontend/utils/dataTransformation.ts
@@ -294,7 +294,7 @@ export function generateTransformationSummary(
const assistCount = agenticReadiness.filter(s => s.readiness_category === 'assist_copilot').length;
const optimizeCount = agenticReadiness.filter(s => s.readiness_category === 'optimize_first').length;
- // Validar que skillsCount no sea 0 para evitar división por cero
+ // Validate that skillsCount is not 0 to avoid division by zero
const automatePercent = skillsCount > 0 ? ((automateCount/skillsCount)*100).toFixed(0) : '0';
const assistPercent = skillsCount > 0 ? ((assistCount/skillsCount)*100).toFixed(0) : '0';
const optimizePercent = skillsCount > 0 ? ((optimizeCount/skillsCount)*100).toFixed(0) : '0';