From 3a6652fdce0ae8dc75525f1245fa55086686e641 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 8 Feb 2026 14:22:00 +0000 Subject: [PATCH] feat: complete OpportunityPrioritizer translation to English - Add 40+ new translation keys for all remaining Spanish text - Update TIER_CONFIG to use translation keys for labels and descriptions - Translate dynamically generated whyPrioritized and nextSteps content - Convert all hardcoded Spanish strings to i18n translation calls - Fix malformed t() call on line 402 - Add proper translations for error messages, buttons, and methodology All OpportunityPrioritizer content is now fully bilingual (en/es) https://claude.ai/code/session_01GNbnkFoESkRcnPr3bLCYDg --- .../components/OpportunityPrioritizer.tsx | 112 ++++++++---------- frontend/locales/en.json | 36 +++++- frontend/locales/es.json | 36 +++++- 3 files changed, 122 insertions(+), 62 deletions(-) diff --git a/frontend/components/OpportunityPrioritizer.tsx b/frontend/components/OpportunityPrioritizer.tsx index 2b3f5dd..aa5c29e 100644 --- a/frontend/components/OpportunityPrioritizer.tsx +++ b/frontend/components/OpportunityPrioritizer.tsx @@ -58,56 +58,56 @@ interface EnrichedOpportunity extends Opportunity { annualCost?: number; } -// Tier configuration +// Tier configuration - labels and descriptions will be translated at usage time const TIER_CONFIG: Record = { 'AUTOMATE': { icon: , - label: 'Automatizar', + labelKey: 'opportunityPrioritizer.tierLabels.automate', color: 'text-emerald-700', bgColor: 'bg-emerald-50', borderColor: 'border-emerald-300', savingsRate: '70%', - timeline: '3-6 meses', - description: 'Automatización completa con agentes IA' + timelineKey: 'opportunityPrioritizer.timelines.automate', + descriptionKey: 'opportunityPrioritizer.tierDescriptions.automate' }, 'ASSIST': { icon: , - label: 'Asistir', + labelKey: 'opportunityPrioritizer.tierLabels.assist', color: 'text-blue-700', bgColor: 'bg-blue-50', borderColor: 'border-blue-300', savingsRate: '30%', - timeline: '6-9 meses', - description: 'Copilot IA para agentes humanos' + timelineKey: 'opportunityPrioritizer.timelines.assist', + descriptionKey: 'opportunityPrioritizer.tierDescriptions.assist' }, 'AUGMENT': { icon: , - label: 'Optimizar', + labelKey: 'opportunityPrioritizer.tierLabels.augment', color: 'text-amber-700', bgColor: 'bg-amber-50', borderColor: 'border-amber-300', savingsRate: '15%', - timeline: '9-12 meses', - description: 'Estandarización y mejora de procesos' + timelineKey: 'opportunityPrioritizer.timelines.augment', + descriptionKey: 'opportunityPrioritizer.tierDescriptions.augment' }, 'HUMAN-ONLY': { icon: , - label: 'Humano', + labelKey: 'opportunityPrioritizer.tierLabels.human', color: 'text-slate-600', bgColor: 'bg-slate-50', borderColor: 'border-slate-300', savingsRate: '0%', - timeline: 'N/A', - description: 'Requiere intervención humana' + timelineKey: 'N/A', + descriptionKey: 'opportunityPrioritizer.tierDescriptions.humanOnly' } }; @@ -177,29 +177,23 @@ const OpportunityPrioritizer: React.FC = ({ // Timeline based on tier const timelineMonths = tier === 'AUTOMATE' ? 4 : tier === 'ASSIST' ? 7 : 10; - // Generate "why" explanation - const whyPrioritized: string[] = []; - if (opp.savings > 50000) whyPrioritized.push(`Alto ahorro potencial (€${(opp.savings / 1000).toFixed(0)}K/año)`); - if (lookupData?.volume && lookupData.volume > 1000) whyPrioritized.push(`Alto volumen (${lookupData.volume.toLocaleString()} interacciones)`); - if (tier === 'AUTOMATE') whyPrioritized.push('Proceso altamente predecible y repetitivo'); - if (cv < 60) whyPrioritized.push('Baja variabilidad en tiempos de gestión'); - if (transfer < 15) whyPrioritized.push('Baja tasa de transferencias'); - if (opp.feasibility >= 7) whyPrioritized.push('Alta factibilidad técnica'); + // Generate "why" explanation - store keys for translation + const whyPrioritized: { key: string; params?: any }[] = []; + if (opp.savings > 50000) whyPrioritized.push({ key: 'reasons.highSavingsPotential', params: { amount: (opp.savings / 1000).toFixed(0) } }); + if (lookupData?.volume && lookupData.volume > 1000) whyPrioritized.push({ key: 'reasons.highVolume', params: { volume: lookupData.volume.toLocaleString() } }); + if (tier === 'AUTOMATE') whyPrioritized.push({ key: 'reasons.highlyPredictable' }); + if (cv < 60) whyPrioritized.push({ key: 'reasons.lowVariability' }); + if (transfer < 15) whyPrioritized.push({ key: 'reasons.lowTransferRate' }); + if (opp.feasibility >= 7) whyPrioritized.push({ key: 'reasons.highFeasibility' }); - // Generate next steps + // Generate next steps - store keys for translation const nextSteps: string[] = []; if (tier === 'AUTOMATE') { - nextSteps.push('Definir flujos conversacionales principales'); - nextSteps.push('Identificar integraciones necesarias (CRM, APIs)'); - nextSteps.push('Crear piloto con 10% del volumen'); + nextSteps.push('steps.automate1', 'steps.automate2', 'steps.automate3'); } else if (tier === 'ASSIST') { - nextSteps.push('Mapear puntos de fricción del agente'); - nextSteps.push('Diseñar sugerencias contextuales'); - nextSteps.push('Piloto con equipo seleccionado'); + nextSteps.push('steps.assist1', 'steps.assist2', 'steps.assist3'); } else { - nextSteps.push('Analizar causa raíz de variabilidad'); - nextSteps.push('Estandarizar procesos y scripts'); - nextSteps.push('Capacitar equipo en mejores prácticas'); + nextSteps.push('steps.augment1', 'steps.augment2', 'steps.augment3'); } return { @@ -250,8 +244,8 @@ const OpportunityPrioritizer: React.FC = ({ return (
-

No hay oportunidades identificadas

-

Los datos actuales no muestran oportunidades de automatización viables.

+

{t('opportunityPrioritizer.noOpportunitiesTitle')}

+

{t('opportunityPrioritizer.noOpportunitiesDescription')}

); } @@ -292,7 +286,7 @@ const OpportunityPrioritizer: React.FC = ({ {summary.byTier.AUTOMATE.length}
- €{(summary.byTier.AUTOMATE.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { count: '3-6' })} + €{(summary.byTier.AUTOMATE.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { months: '3-6' })}
@@ -305,7 +299,7 @@ const OpportunityPrioritizer: React.FC = ({ {summary.byTier.ASSIST.length}
- €{(summary.byTier.ASSIST.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { count: '6-9' })} + €{(summary.byTier.ASSIST.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { months: '6-9' })}
@@ -318,7 +312,7 @@ const OpportunityPrioritizer: React.FC = ({ {summary.byTier.AUGMENT.length}
- €{(summary.byTier.AUGMENT.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { count: '9-12' })} + €{(summary.byTier.AUGMENT.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { months: '9-12' })}
@@ -345,7 +339,7 @@ const OpportunityPrioritizer: React.FC = ({ {topOpportunity.name.replace(/^[^\w\s]+\s*/, '')} - {t(`opportunityPrioritizer.tierLabels.${topOpportunity.tier.toLowerCase()}`)} • {TIER_CONFIG[topOpportunity.tier].description} + {t(TIER_CONFIG[topOpportunity.tier].labelKey)} • {t(TIER_CONFIG[topOpportunity.tier].descriptionKey)} @@ -371,7 +365,7 @@ const OpportunityPrioritizer: React.FC = ({
-
Agentic Score
+
{t('opportunityPrioritizer.agenticScore')}
{topOpportunity.agenticScore.toFixed(1)}/10
@@ -382,13 +376,13 @@ const OpportunityPrioritizer: React.FC = ({

- ¿Por qué es la prioridad #1? + {t('opportunityPrioritizer.whyPriority1')}

    {topOpportunity.whyPrioritized.slice(0, 4).map((reason, i) => (
  • - {reason} + {t(`opportunityPrioritizer.${reason.key}`, reason.params)}
  • ))}
@@ -399,7 +393,7 @@ const OpportunityPrioritizer: React.FC = ({

- t("opportunityPrioritizer.nextSteps") + {t('opportunityPrioritizer.nextSteps')}

    {topOpportunity.nextSteps.map((step, i) => ( @@ -407,12 +401,12 @@ const OpportunityPrioritizer: React.FC = ({ {i + 1} - {step} + {t(`opportunityPrioritizer.${step}`)} ))}
@@ -462,7 +456,7 @@ const OpportunityPrioritizer: React.FC = ({ {opp.name.replace(/^[^\w\s]+\s*/, '')} - {t(`opportunityPrioritizer.tierLabels.${opp.tier.toLowerCase()}`)} • {t(`opportunityPrioritizer.timelines.${opp.tier.toLowerCase()}`)} + {t(TIER_CONFIG[opp.tier].labelKey)} • {t(TIER_CONFIG[opp.tier].timelineKey)}
@@ -496,8 +490,8 @@ const OpportunityPrioritizer: React.FC = ({ />
- Valor - Esfuerzo + {t('opportunityPrioritizer.value')} + {t('opportunityPrioritizer.effort')}
@@ -525,12 +519,12 @@ const OpportunityPrioritizer: React.FC = ({
{/* Why prioritized */}
-
¿Por qué esta posición?
+
{t('opportunityPrioritizer.whyThisPosition')}
    {opp.whyPrioritized.map((reason, i) => (
  • - {reason} + {t(`opportunityPrioritizer.${reason.key}`, reason.params)}
  • ))}
@@ -538,7 +532,7 @@ const OpportunityPrioritizer: React.FC = ({ {/* Metrics */}
-
Métricas Clave
+
{t('opportunityPrioritizer.keyMetrics')}
CV AHT
@@ -553,12 +547,12 @@ const OpportunityPrioritizer: React.FC = ({
{opp.fcr_rate.toFixed(1)}%
-
Riesgo
+
{t('roadmap.risk')}
- {opp.riskLevel === 'low' ? 'Bajo' : opp.riskLevel === 'medium' ? 'Medio' : 'Alto'} + {t(`roadmap.risk${opp.riskLevel.charAt(0).toUpperCase() + opp.riskLevel.slice(1)}`)}
@@ -571,7 +565,7 @@ const OpportunityPrioritizer: React.FC = ({
{opp.nextSteps.map((step, i) => ( - {i + 1}. {step} + {i + 1}. {t(`opportunityPrioritizer.${step}`)} ))}
@@ -593,12 +587,12 @@ const OpportunityPrioritizer: React.FC = ({ {showAllOpportunities ? ( <> - Mostrar menos + {t('opportunityPrioritizer.showLess')} ) : ( <> - Ver {enrichedOpportunities.length - 5} oportunidades más + {t('opportunityPrioritizer.viewMore', { count: enrichedOpportunities.length - 5 })} )} @@ -611,9 +605,7 @@ const OpportunityPrioritizer: React.FC = ({
- {t('opportunityPrioritizer.methodology')} Las oportunidades se ordenan por potencial de ahorro TCO (volumen × tasa de contención × diferencial CPI). - La clasificación de tier (AUTOMATE/ASSIST/AUGMENT) se basa en el Agentic Readiness Score considerando predictibilidad (CV AHT), - resolutividad (FCR + Transfer), volumen, calidad de datos y simplicidad del proceso. + {t('opportunityPrioritizer.methodology')} {t('opportunityPrioritizer.methodologyDescription')}
diff --git a/frontend/locales/en.json b/frontend/locales/en.json index 0da6f71..2b8d58f 100644 --- a/frontend/locales/en.json +++ b/frontend/locales/en.json @@ -1849,12 +1849,46 @@ "tierLabels": { "automate": "Automate", "assist": "Assist", - "augment": "Augment" + "augment": "Augment", + "human": "Human" }, "timelines": { "automate": "3-6 months", "assist": "6-9 months", "augment": "9-12 months" + }, + "tierDescriptions": { + "automate": "Full automation with AI agents", + "assist": "AI Copilot for human agents", + "augment": "Process standardization and improvement", + "humanOnly": "Requires human intervention" + }, + "agenticScore": "Agentic Score", + "whyPriority1": "Why is this priority #1?", + "viewCompleteDetail": "View Complete Detail", + "showLess": "Show less", + "whyThisPosition": "Why this position?", + "keyMetrics": "Key Metrics", + "noOpportunitiesTitle": "No opportunities identified", + "noOpportunitiesDescription": "Current data doesn't show viable automation opportunities.", + "reasons": { + "highSavingsPotential": "High savings potential (€{{amount}}K/year)", + "highVolume": "High volume ({{volume}} interactions)", + "highlyPredictable": "Highly predictable and repetitive process", + "lowVariability": "Low variability in handling times", + "lowTransferRate": "Low transfer rate", + "highFeasibility": "High technical feasibility" + }, + "steps": { + "automate1": "Define main conversational flows", + "automate2": "Identify necessary integrations (CRM, APIs)", + "automate3": "Create pilot with 10% of volume", + "assist1": "Map agent friction points", + "assist2": "Design contextual suggestions", + "assist3": "Pilot with selected team", + "augment1": "Analyze root cause of variability", + "augment2": "Standardize processes and scripts", + "augment3": "Train team on best practices" } } } \ No newline at end of file diff --git a/frontend/locales/es.json b/frontend/locales/es.json index 986343e..9fcbc93 100644 --- a/frontend/locales/es.json +++ b/frontend/locales/es.json @@ -1833,12 +1833,46 @@ "tierLabels": { "automate": "Automatizar", "assist": "Asistir", - "augment": "Aumentar" + "augment": "Aumentar", + "human": "Humano" }, "timelines": { "automate": "3-6 meses", "assist": "6-9 meses", "augment": "9-12 meses" + }, + "tierDescriptions": { + "automate": "Automatización completa con agentes IA", + "assist": "Copilot IA para agentes humanos", + "augment": "Estandarización y mejora de procesos", + "humanOnly": "Requiere intervención humana" + }, + "agenticScore": "Puntuación Agéntica", + "whyPriority1": "¿Por qué es la prioridad #1?", + "viewCompleteDetail": "Ver Detalle Completo", + "showLess": "Mostrar menos", + "whyThisPosition": "¿Por qué esta posición?", + "keyMetrics": "Métricas Clave", + "noOpportunitiesTitle": "No hay oportunidades identificadas", + "noOpportunitiesDescription": "Los datos actuales no muestran oportunidades de automatización viables.", + "reasons": { + "highSavingsPotential": "Alto ahorro potencial (€{{amount}}K/año)", + "highVolume": "Alto volumen ({{volume}} interacciones)", + "highlyPredictable": "Proceso altamente predecible y repetitivo", + "lowVariability": "Baja variabilidad en tiempos de gestión", + "lowTransferRate": "Baja tasa de transferencias", + "highFeasibility": "Alta factibilidad técnica" + }, + "steps": { + "automate1": "Definir flujos conversacionales principales", + "automate2": "Identificar integraciones necesarias (CRM, APIs)", + "automate3": "Crear piloto con 10% del volumen", + "assist1": "Mapear puntos de fricción del agente", + "assist2": "Diseñar sugerencias contextuales", + "assist3": "Piloto con equipo seleccionado", + "augment1": "Analizar causa raíz de variabilidad", + "augment2": "Estandarizar procesos y scripts", + "augment3": "Capacitar equipo en mejores prácticas" } } } \ No newline at end of file