From 2d9fc0151517d3824d0b1c5438b94bca63b420fe Mon Sep 17 00:00:00 2001 From: Urtzi Alfaro Date: Thu, 27 Nov 2025 16:28:44 +0100 Subject: [PATCH] New alert system and panel de control page 2 --- frontend/src/locales/en/alerts.json | 102 ++++++++-------- frontend/src/locales/eu/alerts.json | 108 ++++++++-------- frontend/src/locales/eu/common.json | 2 +- test_i18n_parameters.py | 183 ---------------------------- 4 files changed, 106 insertions(+), 289 deletions(-) delete mode 100644 test_i18n_parameters.py diff --git a/frontend/src/locales/en/alerts.json b/frontend/src/locales/en/alerts.json index e586dc56..69c29620 100644 --- a/frontend/src/locales/en/alerts.json +++ b/frontend/src/locales/en/alerts.json @@ -164,137 +164,137 @@ }, "alerts": { "critical_stock_shortage": { - "title": "🚨 Critical Stock: {{ingredient_name}}", - "message_with_po_pending": "Only {{current_stock}}kg of {{ingredient_name}} (need {{required_stock}}kg). Already created {{po_id}} for delivery on {{delivery_day_name}}. Please approve €{{po_amount}}.", - "message_with_po_created": "Only {{current_stock}}kg of {{ingredient_name}} (need {{required_stock}}kg). Already created {{po_id}}. Review and approve €{{po_amount}}.", - "message_with_hours": "Only {{current_stock}}kg of {{ingredient_name}} available (need {{required_stock}}kg in {{hours_until}} hours).", - "message_with_date": "Only {{current_stock}}kg of {{ingredient_name}} available (need {{required_stock}}kg for production on {{production_day_name}}).", - "message_generic": "Only {{current_stock}}kg of {{ingredient_name}} available (need {{required_stock}}kg)." + "title": "🚨 Critical Stock: {ingredient_name}", + "message_with_po_pending": "Only {current_stock}kg of {ingredient_name} (need {required_stock}kg). Already created {po_id} for delivery on {delivery_day_name}. Please approve €{po_amount}.", + "message_with_po_created": "Only {current_stock}kg of {ingredient_name} (need {required_stock}kg). Already created {po_id}. Review and approve €{po_amount}.", + "message_with_hours": "Only {current_stock}kg of {ingredient_name} available (need {required_stock}kg in {hours_until} hours).", + "message_with_date": "Only {current_stock}kg of {ingredient_name} available (need {required_stock}kg for production on {production_day_name}).", + "message_generic": "Only {current_stock}kg of {ingredient_name} available (need {required_stock}kg)." }, "low_stock": { - "title": "⚠️ Low Stock: {{ingredient_name}}", - "message_with_po": "{{ingredient_name}} stock: {{current_stock}}kg (minimum: {{minimum_stock}}kg). Already scheduled PO for replenishment.", - "message_generic": "{{ingredient_name}} stock: {{current_stock}}kg (minimum: {{minimum_stock}}kg). Consider placing an order." + "title": "⚠️ Low Stock: {ingredient_name}", + "message_with_po": "{ingredient_name} stock: {current_stock}kg (minimum: {minimum_stock}kg). Already scheduled PO for replenishment.", + "message_generic": "{ingredient_name} stock: {current_stock}kg (minimum: {minimum_stock}kg). Consider placing an order." }, "stock_depleted": { "title": "📦 Stock Depleted by Order", - "message_with_supplier": "Order #{{order_id}} requires {{ingredient_name}} but it's depleted. Contact {{supplier_name}} ({{supplier_phone}}).", - "message_generic": "Order #{{order_id}} requires {{ingredient_name}} but it's depleted. Immediate action required." + "message_with_supplier": "Order #{order_id} requires {ingredient_name} but it's depleted. Contact {supplier_name} ({supplier_phone}).", + "message_generic": "Order #{order_id} requires {ingredient_name} but it's depleted. Immediate action required." }, "ingredient_shortage": { "title": "⚠️ Ingredient Shortage in Production", - "message_with_customers": "{{ingredient_name}} insufficient for batches in progress. {{affected_orders}} orders affected ({{customer_names}}). Current stock: {{current_stock}}kg, required: {{required_stock}}kg.", - "message_generic": "{{ingredient_name}} insufficient for batches in progress. Current stock: {{current_stock}}kg, required: {{required_stock}}kg." + "message_with_customers": "{ingredient_name} insufficient for batches in progress. {affected_orders} orders affected ({customer_names}). Current stock: {current_stock}kg, required: {required_stock}kg.", + "message_generic": "{ingredient_name} insufficient for batches in progress. Current stock: {current_stock}kg, required: {required_stock}kg." }, "expired_products": { "title": "🚫 Expired or Expiring Products", - "message_with_names": "{{count}} products expiring: {{product_names}}. Total value: €{{total_value}}.", - "message_generic": "{{count}} products expiring. Total value: €{{total_value}}." + "message_with_names": "{count} products expiring: {product_names}. Total value: €{total_value}.", + "message_generic": "{count} products expiring. Total value: €{total_value}." }, "production_delay": { - "title": "⏰ Production Delay: {{batch_name}}", - "message_with_customers": "Batch {{batch_name}} delayed {{delay_minutes}} minutes. Affected customers: {{customer_names}}. Original delivery time: {{scheduled_time}}.", - "message_with_orders": "Batch {{batch_name}} delayed {{delay_minutes}} minutes. {{affected_orders}} orders affected. Original delivery time: {{scheduled_time}}.", - "message_generic": "Batch {{batch_name}} delayed {{delay_minutes}} minutes. Original delivery time: {{scheduled_time}}." + "title": "⏰ Production Delay: {batch_name}", + "message_with_customers": "Batch {batch_name} delayed {delay_minutes} minutes. Affected customers: {customer_names}. Original delivery time: {scheduled_time}.", + "message_with_orders": "Batch {batch_name} delayed {delay_minutes} minutes. {affected_orders} orders affected. Original delivery time: {scheduled_time}.", + "message_generic": "Batch {batch_name} delayed {delay_minutes} minutes. Original delivery time: {scheduled_time}." }, "equipment_failure": { - "title": "🔧 Equipment Failure: {{equipment_name}}", - "message_with_batches": "{{equipment_name}} failed. {{affected_batches}} batches in production affected ({{batch_names}}).", - "message_generic": "{{equipment_name}} failed. Requires immediate repair." + "title": "🔧 Equipment Failure: {equipment_name}", + "message_with_batches": "{equipment_name} failed. {affected_batches} batches in production affected ({batch_names}).", + "message_generic": "{equipment_name} failed. Requires immediate repair." }, "maintenance_required": { - "title": "🔧 Maintenance Required: {{equipment_name}}", - "message_with_hours": "{{equipment_name}} requires maintenance in {{hours_until}} hours. Schedule now to prevent disruptions.", - "message_with_days": "{{equipment_name}} requires maintenance in {{days_until}} days. Schedule before {{maintenance_date}}." + "title": "🔧 Maintenance Required: {equipment_name}", + "message_with_hours": "{equipment_name} requires maintenance in {hours_until} hours. Schedule now to prevent disruptions.", + "message_with_days": "{equipment_name} requires maintenance in {days_until} days. Schedule before {maintenance_date}." }, "low_equipment_efficiency": { - "title": "📉 Low Efficiency: {{equipment_name}}", - "message": "{{equipment_name}} operating at {{efficiency_percent}}% efficiency (expected: >{{threshold_percent}}%). Consider maintenance." + "title": "📉 Low Efficiency: {equipment_name}", + "message": "{equipment_name} operating at {efficiency_percent}% efficiency (expected: >{threshold_percent}%). Consider maintenance." }, "order_overload": { "title": "📊 Order Overload", - "message_with_orders": "Capacity overloaded by {{overload_percent}}%. {{total_orders}} orders scheduled, capacity: {{capacity_orders}}. Consider adjusting schedule.", - "message_generic": "Capacity overloaded by {{overload_percent}}%. Consider adjusting production schedule." + "message_with_orders": "Capacity overloaded by {overload_percent}%. {total_orders} orders scheduled, capacity: {capacity_orders}. Consider adjusting schedule.", + "message_generic": "Capacity overloaded by {overload_percent}%. Consider adjusting production schedule." }, "supplier_delay": { - "title": "🚚 Supplier Delay: {{supplier_name}}", - "message": "{{supplier_name}} delayed delivery of {{ingredient_name}} (PO: {{po_id}}). New date: {{new_delivery_date}}. Original: {{original_delivery_date}}." + "title": "🚚 Supplier Delay: {supplier_name}", + "message": "{supplier_name} delayed delivery of {ingredient_name} (PO: {po_id}). New date: {new_delivery_date}. Original: {original_delivery_date}." }, "temperature_breach": { "title": "🌡️ Temperature Breach", - "message": "Temperature {{location}}: {{current_temp}}°C (range: {{min_temp}}°C-{{max_temp}}°C). Duration: {{duration_minutes}} minutes." + "message": "Temperature {location}: {current_temp}°C (range: {min_temp}°C-{max_temp}°C). Duration: {duration_minutes} minutes." }, "demand_surge_weekend": { "title": "📈 Demand Surge: Weekend", - "message": "Expected demand {{surge_percent}}% higher for {{weekend_date}}. Affected products: {{products}}. Consider increasing production." + "message": "Expected demand {surge_percent}% higher for {weekend_date}. Affected products: {products}. Consider increasing production." }, "weather_impact_alert": { "title": "🌦️ Expected Weather Impact", - "message": "{{weather_condition}} expected {{date}}. Demand impact: {{impact_percent}}%. Affected products: {{products}}." + "message": "{weather_condition} expected {date}. Demand impact: {impact_percent}%. Affected products: {products}." }, "holiday_preparation": { - "title": "🎉 Holiday Preparation: {{holiday_name}}", - "message": "{{holiday_name}} in {{days_until}} days ({{holiday_date}}). Expected demand {{expected_increase}}% higher. Key products: {{products}}." + "title": "🎉 Holiday Preparation: {holiday_name}", + "message": "{holiday_name} in {days_until} days ({holiday_date}). Expected demand {expected_increase}% higher. Key products: {products}." }, "severe_weather_impact": { "title": "⛈️ Severe Weather Impact", - "message": "Severe {{weather_condition}} expected {{date}}. Demand impact: {{impact_percent}}%. Consider adjusting delivery schedules." + "message": "Severe {weather_condition} expected {date}. Demand impact: {impact_percent}%. Consider adjusting delivery schedules." }, "unexpected_demand_spike": { "title": "📊 Unexpected Demand Spike", - "message": "Demand increased {{spike_percent}}% for {{products}}. Current stock may run out in {{hours_until_stockout}} hours." + "message": "Demand increased {spike_percent}% for {products}. Current stock may run out in {hours_until_stockout} hours." }, "demand_pattern_optimization": { "title": "💡 Demand Pattern Optimization", - "message": "Pattern detected: {{pattern_description}}. Recommend adjusting production of {{products}} to optimize efficiency." + "message": "Pattern detected: {pattern_description}. Recommend adjusting production of {products} to optimize efficiency." }, "inventory_optimization": { "title": "📦 Inventory Optimization", - "message": "{{ingredient_name}} consistently over-stocked by {{excess_percent}}%. Recommend reducing order to {{recommended_amount}}kg." + "message": "{ingredient_name} consistently over-stocked by {excess_percent}%. Recommend reducing order to {recommended_amount}kg." }, "production_efficiency": { "title": "⚡ Production Efficiency Opportunity", - "message": "{{product_name}} more efficient at {{suggested_time}}. Production time {{time_saved}} minutes shorter ({{savings_percent}}% savings)." + "message": "{product_name} more efficient at {suggested_time}. Production time {time_saved} minutes shorter ({savings_percent}% savings)." }, "sales_opportunity": { "title": "💰 Sales Opportunity", - "message": "High demand for {{products}} detected. Consider additional production. Potential revenue: €{{potential_revenue}}." + "message": "High demand for {products} detected. Consider additional production. Potential revenue: €{potential_revenue}." }, "seasonal_adjustment": { "title": "🍂 Seasonal Adjustment Recommended", - "message": "{{season}} season approaching. Adjust production of {{products}} based on historical trends ({{adjustment_percent}}% {{adjustment_direction}})." + "message": "{season} season approaching. Adjust production of {products} based on historical trends ({adjustment_percent}% {adjustment_direction})." }, "cost_reduction": { "title": "💵 Cost Reduction Opportunity", - "message": "Switching to {{alternative_ingredient}} can save €{{savings_amount}}/month. Similar quality, lower cost." + "message": "Switching to {alternative_ingredient} can save €{savings_amount}/month. Similar quality, lower cost." }, "waste_reduction": { "title": "♻️ Waste Reduction Opportunity", - "message": "{{product_name}} waste high ({{waste_percent}}%). Recommend reducing batch to {{recommended_quantity}} units." + "message": "{product_name} waste high ({waste_percent}%). Recommend reducing batch to {recommended_quantity} units." }, "quality_improvement": { "title": "⭐ Quality Improvement Recommended", - "message": "{{issue_description}} detected in {{product_name}}. Recommended action: {{recommended_action}}." + "message": "{issue_description} detected in {product_name}. Recommended action: {recommended_action}." }, "customer_satisfaction": { "title": "😊 Customer Satisfaction Opportunity", - "message": "Customer {{customer_name}} consistently orders {{product_name}}. Consider special offer or loyalty program." + "message": "Customer {customer_name} consistently orders {product_name}. Consider special offer or loyalty program." }, "energy_optimization": { "title": "⚡ Energy Optimization", - "message": "Energy usage for {{equipment_name}} peaks at {{peak_time}}. Shifting to {{off_peak_start}}-{{off_peak_end}} can save €{{savings_amount}}/month." + "message": "Energy usage for {equipment_name} peaks at {peak_time}. Shifting to {off_peak_start}-{off_peak_end} can save €{savings_amount}/month." }, "staff_optimization": { "title": "👥 Staff Optimization", - "message": "{{shift_name}} over-staffed by {{excess_percent}}%. Consider adjusting staff levels to reduce labor costs." + "message": "{shift_name} over-staffed by {excess_percent}%. Consider adjusting staff levels to reduce labor costs." }, "po_approval_needed": { "title": "Purchase Order #{po_number} requires approval", "message": "Purchase order for {supplier_name} totaling {currency} {total_amount} is pending approval. Delivery required by {required_delivery_date}." }, "production_batch_start": { - "title": "Production Batch Ready: {{product_name}}", - "message": "Batch #{{batch_number}} ({{quantity_planned}} {{unit}} of {{product_name}}) is ready to start. Priority: {{priority}}." + "title": "Production Batch Ready: {product_name}", + "message": "Batch #{batch_number} ({quantity_planned} {unit} of {product_name}) is ready to start. Priority: {priority}." } } } diff --git a/frontend/src/locales/eu/alerts.json b/frontend/src/locales/eu/alerts.json index bc8a03bb..38f9f9c5 100644 --- a/frontend/src/locales/eu/alerts.json +++ b/frontend/src/locales/eu/alerts.json @@ -133,14 +133,14 @@ "trend": { "near_threshold": "Atalasearen ondoan" }, - "action_preview": { + "action_preview": { "title": "Ekintzaren Aurrebista", "outcome": "Zer gertatuko da", "financial_impact": "Finantza Eragina", "affected_systems": "Sistema Eragindak", "reversible": "Ekintza hau desegin daiteke", "not_reversible": "Ekintza hau ezin da desegin", - "confidence": "AIaren Konfiantza: {{confidence}}%", + "confidence": "AIaren Konfiantza: {confidence}%", "cancel": "Ezeztatu", "confirm": "Berretsi Ekintza" }, @@ -161,137 +161,137 @@ }, "alerts": { "critical_stock_shortage": { - "title": "🚨 Stock Kritikoa: {{ingredient_name}}", - "message_with_po_pending": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik ({{required_stock}}kg behar dituzu). Dagoeneko {{po_id}} sortu dut {{delivery_day_name}}rako entregarako. Mesedez onartu €{{po_amount}}.", - "message_with_po_created": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik ({{required_stock}}kg behar dituzu). Dagoeneko {{po_id}} sortu dut. Berrikusi eta onartu €{{po_amount}}.", - "message_with_hours": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik eskuragarri ({{required_stock}}kg behar dituzu {{hours_until}} ordutan).", - "message_with_date": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik eskuragarri ({{required_stock}}kg behar dituzu {{production_day_name}}ko ekoizpenerako).", - "message_generic": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik eskuragarri ({{required_stock}}kg behar dituzu)." + "title": "🚨 Stock Kritikoa: {ingredient_name}", + "message_with_po_pending": "{ingredient_name}-ren {current_stock}kg bakarrik ({required_stock}kg behar dituzu). Dagoeneko {po_id} sortu dut {delivery_day_name}rako entregarako. Mesedez onartu €{po_amount}.", + "message_with_po_created": "{ingredient_name}-ren {current_stock}kg bakarrik ({required_stock}kg behar dituzu). Dagoeneko {po_id} sortu dut. Berrikusi eta onartu €{po_amount}.", + "message_with_hours": "{ingredient_name}-ren {current_stock}kg bakarrik eskuragarri ({required_stock}kg behar dituzu {hours_until} ordutan).", + "message_with_date": "{ingredient_name}-ren {current_stock}kg bakarrik eskuragarri ({required_stock}kg behar dituzu {production_day_name}ko ekoizpenerako).", + "message_generic": "{ingredient_name}-ren {current_stock}kg bakarrik eskuragarri ({required_stock}kg behar dituzu)." }, "low_stock": { - "title": "⚠️ Stock Baxua: {{ingredient_name}}", - "message_with_po": "{{ingredient_name}} stocka: {{current_stock}}kg (gutxienekoa: {{minimum_stock}}kg). Dagoeneko PO programatu dut osatzeko.", - "message_generic": "{{ingredient_name}} stocka: {{current_stock}}kg (gutxienekoa: {{minimum_stock}}kg). Eskaera egitea kontuan hartu." + "title": "⚠️ Stock Baxua: {ingredient_name}", + "message_with_po": "{ingredient_name} stocka: {current_stock}kg (gutxienekoa: {minimum_stock}kg). Dagoeneko PO programatu dut osatzeko.", + "message_generic": "{ingredient_name} stocka: {current_stock}kg (gutxienekoa: {minimum_stock}kg). Eskaera egitea kontuan hartu." }, "stock_depleted": { "title": "📦 Eskaeragatik Stocka Agortu Da", - "message_with_supplier": "#{{order_id}} eskaerak {{ingredient_name}} behar du baina agortu da. Jarri harremanetan {{supplier_name}}rekin ({{supplier_phone}}).", - "message_generic": "#{{order_id}} eskaerak {{ingredient_name}} behar du baina agortu da. Berehala ekintza behar da." + "message_with_supplier": "#{order_id} eskaerak {ingredient_name} behar du baina agortu da. Jarri harremanetan {supplier_name}rekin ({supplier_phone}).", + "message_generic": "#{order_id} eskaerak {ingredient_name} behar du baina agortu da. Berehala ekintza behar da." }, "ingredient_shortage": { "title": "⚠️ Osagaien Falta Ekoizpenean", - "message_with_customers": "{{ingredient_name}} nahikoa ez abian dauden loteentzat. {{affected_orders}} eskabide eraginda ({{customer_names}}). Oraingo stocka: {{current_stock}}kg, beharrezkoa: {{required_stock}}kg.", - "message_generic": "{{ingredient_name}} nahikoa ez abian dauden loteentzat. Oraingo stocka: {{current_stock}}kg, beharrezkoa: {{required_stock}}kg." + "message_with_customers": "{ingredient_name} nahikoa ez abian dauden loteentzat. {affected_orders} eskabide eraginda ({customer_names}). Stock orain: {current_stock}kg, beharrezkoa: {required_stock}kg.", + "message_generic": "{ingredient_name} nahikoa ez abian dauden loteentzat. Stock orain: {current_stock}kg, beharrezkoa: {required_stock}kg." }, "expired_products": { "title": "🚫 Iraungitako edo Iraungitzear Dauden Produktuak", - "message_with_names": "{{count}} produktu iraungitzen: {{product_names}}. Balio osoa: €{{total_value}}.", - "message_generic": "{{count}} produktu iraungitzen. Balio osoa: €{{total_value}}." + "message_with_names": "{count} produktu iraungitzen: {product_names}. Balio osoa: €{total_value}.", + "message_generic": "{count} produktu iraungitzen. Balio osoa: €{total_value}." }, "production_delay": { - "title": "⏰ Ekoizpen Atzerapena: {{batch_name}}", - "message_with_customers": "{{batch_name}} lotea {{delay_minutes}} minutu atzeratu da. Bezeroak eraginda: {{customer_names}}. Jatorrizko entrega ordua: {{scheduled_time}}.", - "message_with_orders": "{{batch_name}} lotea {{delay_minutes}} minutu atzeratu da. {{affected_orders}} eskabide eraginda. Jatorrizko entrega ordua: {{scheduled_time}}.", - "message_generic": "{{batch_name}} lotea {{delay_minutes}} minutu atzeratu da. Jatorrizko entrega ordua: {{scheduled_time}}." + "title": "⏰ Ekoizpen Atzerapena: {batch_name}", + "message_with_customers": "{batch_name} lotea {delay_minutes} minutu atzeratu da. Bezeroak eraginda: {customer_names}. Jatorrizko entrega ordua: {scheduled_time}.", + "message_with_orders": "{batch_name} lotea {delay_minutes} minutu atzeratu da. {affected_orders} eskabide eraginda. Jatorrizko entrega ordua: {scheduled_time}.", + "message_generic": "{batch_name} lotea {delay_minutes} minutu atzeratu da. Jatorrizko entrega ordua: {scheduled_time}." }, "equipment_failure": { - "title": "🔧 Ekipamendu Matxura: {{equipment_name}}", - "message_with_batches": "{{equipment_name}} huts egin du. {{affected_batches}} ekoizpeneko lote eraginda ({{batch_names}}).", - "message_generic": "{{equipment_name}} huts egin du. Berehala konponketa behar du." + "title": "🔧 Ekipamendu Matxura: {equipment_name}", + "message_with_batches": "{equipment_name} huts egin du. {affected_batches} ekoizpeneko lote eraginda ({batch_names}).", + "message_generic": "{equipment_name} huts egin du. Berehala konponketa behar du." }, "maintenance_required": { - "title": "🔧 Mantentze-lanak Behar Dira: {{equipment_name}}", - "message_with_hours": "{{equipment_name}}(e)k mantentze-lanak behar ditu {{hours_until}} ordutan. Programatu orain etetenak saihesteko.", - "message_with_days": "{{equipment_name}}(e)k mantentze-lanak behar ditu {{days_until}} egunetan. Programatu {{maintenance_date}} baino lehen." + "title": "🔧 Mantentze-lanak Behar Dira: {equipment_name}", + "message_with_hours": "{equipment_name}(e)k mantentze-lanak behar ditu {hours_until} ordutan. Programatu orain etetenak saihesteko.", + "message_with_days": "{equipment_name}(e)k mantentze-lanak behar ditu {days_until} egunetan. Programatu {maintenance_date} baino lehen." }, "low_equipment_efficiency": { - "title": "📉 Eraginkortasun Baxua: {{equipment_name}}", - "message": "{{equipment_name}} %{{efficiency_percent}} eraginkortasunarekin funtzionatzen (esperoa: >{{threshold_percent}}%). Mantentze-lanak kontuan hartu." + "title": "📉 Eraginkortasun Baxua: {equipment_name}", + "message": "{equipment_name} %{efficiency_percent} eraginkortasunarekin funtzionatzen (esperoa: >{threshold_percent}%). Mantentze-lanak kontuan hartu." }, "order_overload": { "title": "📊 Eskabideen Gainzama", - "message_with_orders": "Gaitasuna %{{overload_percent}}z gainzamatuta. {{total_orders}} eskabide programatuta, gaitasuna: {{capacity_orders}}. Egutegia doitzea kontuan hartu.", - "message_generic": "Gaitasuna %{{overload_percent}}z gainzamatuta. Ekoizpen egutegia doitzea kontuan hartu." + "message_with_orders": "Gaitasuna %{overload_percent}z gainzamatuta. {total_orders} eskabide programatuta, gaitasuna: {capacity_orders}. Egutegia doitzea kontuan hartu.", + "message_generic": "Gaitasuna %{overload_percent}z gainzamatuta. Ekoizpen egutegia doitzea kontuan hartu." }, "supplier_delay": { - "title": "🚚 Hornitzaile Atzerapena: {{supplier_name}}", - "message": "{{supplier_name}}(e)k {{ingredient_name}} entrega atzeratu du (PO: {{po_id}}). Data berria: {{new_delivery_date}}. Jatorrizkoa: {{original_delivery_date}}." + "title": "🚚 Hornitzaile Atzerapena: {supplier_name}", + "message": "{supplier_name}(e)k {ingredient_name} entrega atzeratu du (PO: {po_id}). Data berria: {new_delivery_date}. Jatorrizkoa: {original_delivery_date}." }, "temperature_breach": { "title": "🌡️ Tenperatura Haustea", - "message": "Tenperatura {{location}}: {{current_temp}}°C (tartea: {{min_temp}}°C-{{max_temp}}°C). Iraupena: {{duration_minutes}} minutu." + "message": "Tenperatura {location}: {current_temp}°C (tartea: {min_temp}°C-{max_temp}°C). Iraupena: {duration_minutes} minutu." }, "demand_surge_weekend": { "title": "📈 Eskariaren Igoera: Asteburua", - "message": "Eskatutako eskaria %{{surge_percent}} handiagoa {{weekend_date}}rako. Produktu eragindak: {{products}}. Ekoizpena handitzea kontuan hartu." + "message": "Eskatutako eskaria %{surge_percent} handiagoa {weekend_date}rako. Produktu eragindak: {products}. Ekoizpena handitzea kontuan hartu." }, "weather_impact_alert": { "title": "🌦️ Espero den Eguraldiaren Eragina", - "message": "{{weather_condition}} esperotzen da {{date}}. Eskarian eragina: %{{impact_percent}}. Produktu eragindak: {{products}}." + "message": "{weather_condition} esperotzen da {date}. Eskarian eragina: %{impact_percent}. Produktu eragindak: {products}." }, "holiday_preparation": { - "title": "🎉 Jai Prestaketa: {{holiday_name}}", - "message": "{{holiday_name}} {{days_until}} egunetan ({{holiday_date}}). Eskatutako eskaria %{{expected_increase}} handiagoa. Funtsezko produktuak: {{products}}." + "title": "🎉 Jai Prestaketa: {holiday_name}", + "message": "{holiday_name} {days_until} egunetan ({holiday_date}). Eskatutako eskaria %{expected_increase} handiagoa. Produktu gakoak: {products}." }, "severe_weather_impact": { "title": "⛈️ Eguraldi Larriaren Eragina", - "message": "{{weather_condition}} larria esperotzen da {{date}}. Eskarian eragina: %{{impact_percent}}. Entrega ordutegiak doitzea kontuan hartu." + "message": "{weather_condition} larria esperotzen da {date}. Eskarian eragina: %{impact_percent}. Entrega ordutegiak doitzea kontuan hartu." }, "unexpected_demand_spike": { "title": "📊 Ustekabeko Eskariaren Igoera", - "message": "Eskaria %{{spike_percent}} igo da {{products}}entzat. Oraingo stocka agor daiteke {{hours_until_stockout}} ordutan." + "message": "Eskaria %{spike_percent} igo da {products}entzat. Oraingo stocka agor daiteke {hours_until_stockout} ordutan." }, "demand_pattern_optimization": { "title": "💡 Eskari Ereduaren Optimizazioa", - "message": "Eredua detektatua: {{pattern_description}}. Gomendatzen da {{products}} ekoizpena doitzea eraginkortasuna optimizatzeko." + "message": "Eredua detektatua: {pattern_description}. Gomendatzen da {products} ekoizpena doitzea eraginkortasuna optimizatzeko." }, "inventory_optimization": { "title": "📦 Inbentarioaren Optimizazioa", - "message": "{{ingredient_name}} etengabe gehiegizko stockarekin %{{excess_percent}}z. Gomendatzen da eskaera {{recommended_amount}}kg-ra murriztea." + "message": "{ingredient_name} etengabe gehiegizko stockarekin %{excess_percent}z. Gomendatzen da eskaera {recommended_amount}kg-ra murriztea." }, "production_efficiency": { "title": "⚡ Ekoizpen Eraginkortasunaren Aukera", - "message": "{{product_name}} eraginkorragoa da {{suggested_time}}etan. Ekoizpen denbora {{time_saved}} minutu laburragoa (%{{savings_percent}} aurrezkia)." + "message": "{product_name} eraginkorragoa da {suggested_time}etan. Ekoizpen denbora {time_saved} minutu laburragoa (%{savings_percent} aurrezkia)." }, "sales_opportunity": { "title": "💰 Salmenten Aukera", - "message": "{{products}}entzako eskari handia detektatuta. Ekoizpen gehigarria kontuan hartu. Sarrera potentziala: €{{potential_revenue}}." + "message": "{products}entzako eskari handia detektatuta. Ekoizpen gehigarria kontuan hartu. Sarrera potentziala: €{potential_revenue}." }, "seasonal_adjustment": { "title": "🍂 Sasoiko Doikuntza Gomendatua", - "message": "{{season}} sasoia hurbiltzen. Doitu {{products}} ekoizpena historia joerei oinarrituta (%{{adjustment_percent}} {{adjustment_direction}})." + "message": "{season} sasoia hurbiltzen. Doitu {products} ekoizpena historia joerei oinarrituta (%{adjustment_percent} {adjustment_direction})." }, "cost_reduction": { "title": "💵 Kostu Murrizketa Aukera", - "message": "{{alternative_ingredient}}ra aldatzeak €{{savings_amount}}/hilabetean aurreztu dezake. Antzeko kalitatea, kostu txikiagoa." + "message": "{alternative_ingredient}ra aldatzeak €{savings_amount}/hilabetean aurreztu dezake. Antzeko kalitatea, kostu txikiagoa." }, "waste_reduction": { "title": "♻️ Hondakin Murrizketa Aukera", - "message": "{{product_name}} hondakin handia (%{{waste_percent}}). Gomendatzen da lotea {{recommended_quantity}} unitatetara murriztea." + "message": "{product_name} hondakin handia (%{waste_percent}). Gomendatzen da lotea {recommended_quantity} unitatetara murriztea." }, "quality_improvement": { "title": "⭐ Kalitate Hobekuntza Gomendatua", - "message": "{{issue_description}} detektatuta {{product_name}}n. Gomendatutako ekintza: {{recommended_action}}." + "message": "{issue_description} detektatuta {product_name}n. Gomendatutako ekintza: {recommended_action}." }, "customer_satisfaction": { "title": "😊 Bezeroaren Gogobetetasun Aukera", - "message": "{{customer_name}} bezeroak etengabe eskatzen du {{product_name}}. Eskaintza berezia edo leialtasun programa kontuan hartu." + "message": "{customer_name} bezeroak etengabe eskatzen du {product_name}. Eskaintza berezia edo leialtasun programa kontuan hartu." }, "energy_optimization": { "title": "⚡ Energia Optimizazioa", - "message": "{{equipment_name}}rako energia erabilera gailurra {{peak_time}}etan. {{off_peak_start}}-{{off_peak_end}}ra aldatzeak €{{savings_amount}}/hilabetean aurreztu dezake." + "message": "{equipment_name}rako energia erabilera gailurra {peak_time}etan. {off_peak_start}-{off_peak_end}ra aldatzeak €{savings_amount}/hilabetean aurreztu dezake." }, "staff_optimization": { "title": "👥 Langile Optimizazioa", - "message": "{{shift_name}} langileak gehiegi %{{excess_percent}}z. Langile mailak doitzea kontuan hartu lan kostuak murrizteko." + "message": "{shift_name} langileak gehiegi %{excess_percent}z. Langile mailak doitzea kontuan hartu lan kostuak murrizteko." }, "po_approval_needed": { "title": "Erosketa Agindua #{po_number} onarpenaren beharra", - "message": "{supplier_name}-(r)entzako erosketa agindua {currency} {total_amount} onarpenaren zain. Entreaga {required_delivery_date}-(e)rako behar da." + "message": "Erosketa agindua {supplier_name}-(r)entzako {currency} {total_amount} onarpenaren zain. Entreaga {required_delivery_date}-(e)rako behar da." }, "production_batch_start": { - "title": "Ekoizpen Lote Prest: {{product_name}}", - "message": "#{{batch_number}} lotea ({{quantity_planned}} {{unit}} {{product_name}}) hasteko prest. Lehentasuna: {{priority}}." + "title": "Ekoizpen Lote Prest: {product_name}", + "message": "Lote #{batch_number} ({quantity_planned} {unit} {product_name}) hasierarako prest dago. Lehentasuna: {priority}." } } } diff --git a/frontend/src/locales/eu/common.json b/frontend/src/locales/eu/common.json index 1585defe..6e09ecb1 100644 --- a/frontend/src/locales/eu/common.json +++ b/frontend/src/locales/eu/common.json @@ -417,7 +417,7 @@ "header": { "main_navigation": "Nabigazio nagusia", "notifications": "Jakinarazpenak", - "unread_count": "{{count}} jakinarazpen irakurri gabeak", + "unread_count": "{count} jakinarazpen irakurri gabeak", "login": "Hasi Saioa", "start_free": "Hasi Doan", "register": "Erregistratu", diff --git a/test_i18n_parameters.py b/test_i18n_parameters.py deleted file mode 100644 index a9a98a32..00000000 --- a/test_i18n_parameters.py +++ /dev/null @@ -1,183 +0,0 @@ -""" -Test script to verify i18n ICU format parameters are properly structured -for PO approval alerts in the bakery-ia system. -""" - -import uuid -from datetime import datetime - - -def test_raw_alert_structure(): - """Test that raw alerts contain proper message_params for ICU format""" - print("Testing Raw Alert Structure...") - - # Simulate the structure that should be created by _emit_po_approval_alert - raw_alert_data = { - 'id': str(uuid.uuid4()), - 'tenant_id': str(uuid.uuid4()), - 'service': 'procurement', - 'type': 'po_approval_needed', - 'alert_type': 'po_approval_needed', - 'type_class': 'action_needed', - 'severity': 'high', - 'title': '', # Empty - will be generated by frontend with i18n - 'message': '', # Empty - will be generated by frontend with i18n - 'timestamp': datetime.utcnow().isoformat(), - 'metadata': { - 'po_id': str(uuid.uuid4()), - 'po_number': 'PO-12345', - 'supplier_id': str(uuid.uuid4()), - 'supplier_name': 'ABC Supplier', - 'total_amount': 1500.00, - 'currency': 'EUR', - 'priority': 'high', - 'required_delivery_date': '2024-01-15', - 'created_at': datetime.utcnow().isoformat(), - 'financial_impact': 1500.00, - 'urgency_score': 85, - 'reasoning_data': { - 'type': 'po_creation_approval', - 'parameters': { - 'po_number': 'PO-12345', - 'supplier_name': 'ABC Supplier', - 'total_amount': 1500.00, - 'currency': 'EUR', - 'required_delivery_date': '2024-01-15', - 'items_count': 5, - 'priority': 'high', - 'reason': 'automated_replenishment', - 'triggering_event': 'low_stock_detected', - 'financial_impact_if_delayed': 2000.00, - 'production_batches_affected': ['BATCH-001', 'BATCH-002'] - }, - 'consequence': { - 'severity': 'high', - 'affects': ['production_delay', 'stockout_risk'] - } - } - }, - 'message_params': { - 'po_number': 'PO-12345', - 'supplier_name': 'ABC Supplier', - 'total_amount': 1500.00, - 'currency': 'EUR', - 'priority': 'high', - 'required_delivery_date': '2024-01-15', - 'items_count': 5, - 'created_at': datetime.utcnow().isoformat() - }, - 'actions': ['approve_po', 'reject_po', 'modify_po'], - 'item_type': 'alert' - } - - print(f"✓ Raw alert contains message_params: {raw_alert_data['message_params']}") - print(f"✓ Message params structure: {list(raw_alert_data['message_params'].keys())}") - - # Verify ICU format compatibility - icu_compatible = all(isinstance(v, (str, int, float, bool)) for k, v in raw_alert_data['message_params'].items() - if k != 'created_at') # created_at is datetime string - print(f"✓ ICU format compatible: {icu_compatible}") - - return raw_alert_data - - -def test_enriched_alert_structure(raw_alert_data): - """Test that enriched alerts preserve and enhance message_params""" - print("\nTesting Enriched Alert Structure...") - - # Simulate the enriched alert structure (simplified version) - enriched_alert_data = { - 'id': raw_alert_data['id'], - 'tenant_id': raw_alert_data['tenant_id'], - 'service': raw_alert_data['service'], - 'alert_type': raw_alert_data['alert_type'], - 'type_class': raw_alert_data['type_class'], - 'priority_score': 85, - 'priority_level': 'important', - 'message_params': raw_alert_data['message_params'], # Preserved from raw alert - 'reasoning_data': raw_alert_data['metadata']['reasoning_data'], - 'actions': raw_alert_data['actions'], - 'business_impact': {'financial_impact_eur': 1500.00}, - 'urgency_context': {'time_until_consequence_hours': 24}, - 'user_agency': {'can_user_fix': True}, - 'created_at': datetime.utcnow(), - 'alert_metadata': { - **raw_alert_data['metadata'], - 'message_params': raw_alert_data['message_params'], # Preserved in metadata - 'i18n': { - 'title_key': f'alerts.{raw_alert_data["alert_type"]}.title', - 'message_key': f'alerts.{raw_alert_data["alert_type"]}.message', - 'message_params': raw_alert_data['message_params'] # ICU format params - } - }, - 'status': 'active' - } - - print(f"✓ Enriched alert preserves message_params: {enriched_alert_data['message_params']}") - print(f"✓ ICU params in metadata: {enriched_alert_data['alert_metadata']['i18n']['message_params']}") - print(f"✓ All ICU params preserved: {set(enriched_alert_data['message_params'].keys()) == set(raw_alert_data['message_params'].keys())}") - - return enriched_alert_data - - -def test_i18n_icu_usage(): - """Test how frontend would use ICU format parameters""" - print("\nTesting ICU Format Usage...") - - # Simulate frontend i18n usage - message_params = { - 'po_number': 'PO-12345', - 'supplier_name': 'ABC Supplier', - 'total_amount': 1500.00, - 'currency': 'EUR', - 'priority': 'high', - 'required_delivery_date': '2024-01-15', - 'items_count': 5 - } - - # Simulate ICU format translation strings - title_template = "{po_number} needs approval" - message_template = "Purchase order for {supplier_name} ({currency}{total_amount}) requires your approval. {items_count} items included. Required by {required_delivery_date}." - - # Simulate i18n.t() function replacement - title = title_template.format(**message_params) - message = message_template.format(**message_params) - - print(f"✓ ICU title: {title}") - print(f"✓ ICU message: {message}") - - # Verify ICU format compatibility - expected_title = "PO-12345 needs approval" - expected_message = "Purchase order for ABC Supplier (EUR150.0) requires your approval. 5 items included. Required by 2024-01-15." - - print(f"✓ Title matches expected: {title == expected_title}") - print(f"✓ Message matches expected: {message == expected_message}") - - return True - - -def main(): - """Main test function""" - print("Testing i18n ICU Format Implementation for PO Approval Alerts") - print("=" * 60) - - # Test 1: Raw alert structure - raw_alert = test_raw_alert_structure() - - # Test 2: Enriched alert structure - enriched_alert = test_enriched_alert_structure(raw_alert) - - # Test 3: ICU format usage - icu_test = test_i18n_icu_usage() - - print("\n" + "=" * 60) - print("All tests passed! ✓") - print("\nSummary:") - print("- Raw alerts now contain structured message_params for ICU format") - print("- Enriched alerts preserve and enhance message_params") - print("- ICU format supports {param} syntax for i18n translation") - print("- Parameters are compatible with frontend i18n libraries") - - -if __name__ == "__main__": - main()