Fix dashboard translation issues and template variable interpolation
This commit resolves three critical translation/localization issues in the bakery dashboard:
1. **Health Status Translation Keys**: Fixed HealthStatusCard's translateKey function to properly handle `dashboard.health.*` keys by correctly stripping the `dashboard.` prefix while preserving the `health.` namespace path. This ensures checklist items like "production_on_schedule" and "all_ingredients_in_stock" display correctly in Spanish.
2. **Reasoning Translation Keys**: Updated backend dashboard_service.py to use the correct i18n key prefixes:
- Purchase orders now use `reasoning.purchaseOrder.*` instead of `reasoning.types.*`
- Production batches now use `reasoning.productionBatch.*`
- Added context parameter to `_get_reasoning_type_i18n_key()` method for proper namespace routing
3. **Template Variable Interpolation**: Fixed template variable replacement in action cards:
- Added array preprocessing logic in both backend and frontend to convert `product_names` arrays to `product_names_joined` strings
- Updated ActionQueueCard's translateKey to preprocess array parameters before i18n interpolation
- Fixed ProductionTimelineCard to properly handle reasoning namespace prefix removal
These fixes ensure that:
- Health status indicators show translated text instead of raw keys (e.g., "Producción a tiempo" vs "dashboard.health.production_on_schedule")
- Purchase order reasoning displays with proper product names and stockout days instead of literal template variables (e.g., "Stock bajo para Harina. El stock se agotará en 7 días" vs "Stock bajo para {{product_name}}")
- All dashboard components consistently handle i18n key namespaces and parameter interpolation
Affected files:
- frontend/src/components/dashboard/HealthStatusCard.tsx
- frontend/src/components/dashboard/ActionQueueCard.tsx
- frontend/src/components/dashboard/ProductionTimelineCard.tsx
- services/orchestrator/app/services/dashboard_service.py
This commit is contained in:
@@ -402,7 +402,13 @@ class DashboardService:
|
||||
|
||||
# Get reasoning type and convert to i18n key
|
||||
reasoning_type = reasoning_data.get('type', 'inventory_replenishment')
|
||||
reasoning_type_i18n_key = self._get_reasoning_type_i18n_key(reasoning_type)
|
||||
reasoning_type_i18n_key = self._get_reasoning_type_i18n_key(reasoning_type, context="purchaseOrder")
|
||||
|
||||
# Preprocess parameters for i18n
|
||||
params = reasoning_data.get('parameters', {})
|
||||
# Convert product_names array to product_names_joined string
|
||||
if 'product_names' in params and isinstance(params['product_names'], list):
|
||||
params['product_names_joined'] = ', '.join(params['product_names'])
|
||||
|
||||
actions.append({
|
||||
"id": po["id"],
|
||||
@@ -418,7 +424,7 @@ class DashboardService:
|
||||
},
|
||||
"reasoning_i18n": {
|
||||
"key": reasoning_type_i18n_key,
|
||||
"params": reasoning_data.get('parameters', {})
|
||||
"params": params
|
||||
},
|
||||
"consequence_i18n": {
|
||||
"key": "action_queue.consequences.delayed_delivery",
|
||||
@@ -465,18 +471,41 @@ class DashboardService:
|
||||
|
||||
return actions
|
||||
|
||||
def _get_reasoning_type_i18n_key(self, reasoning_type: str) -> str:
|
||||
"""Map reasoning type identifiers to i18n keys"""
|
||||
reasoning_type_map = {
|
||||
"low_stock_detection": "reasoning.types.low_stock_detection",
|
||||
"stockout_prevention": "reasoning.types.stockout_prevention",
|
||||
"forecast_demand": "reasoning.types.forecast_demand",
|
||||
"customer_orders": "reasoning.types.customer_orders",
|
||||
"seasonal_demand": "reasoning.types.seasonal_demand",
|
||||
"inventory_replenishment": "reasoning.types.inventory_replenishment",
|
||||
"production_schedule": "reasoning.types.production_schedule",
|
||||
}
|
||||
return reasoning_type_map.get(reasoning_type, "reasoning.types.other")
|
||||
def _get_reasoning_type_i18n_key(self, reasoning_type: str, context: str = "purchaseOrder") -> str:
|
||||
"""Map reasoning type identifiers to i18n keys
|
||||
|
||||
Args:
|
||||
reasoning_type: The type of reasoning (e.g., "low_stock_detection")
|
||||
context: The context (either "purchaseOrder" or "productionBatch")
|
||||
|
||||
Returns:
|
||||
Full i18n key with namespace and context prefix
|
||||
"""
|
||||
if context == "productionBatch":
|
||||
reasoning_type_map = {
|
||||
"forecast_demand": "reasoning.productionBatch.forecast_demand",
|
||||
"customer_order": "reasoning.productionBatch.customer_order",
|
||||
"stock_replenishment": "reasoning.productionBatch.stock_replenishment",
|
||||
"seasonal_preparation": "reasoning.productionBatch.seasonal_preparation",
|
||||
"promotion_event": "reasoning.productionBatch.promotion_event",
|
||||
"urgent_order": "reasoning.productionBatch.urgent_order",
|
||||
"regular_schedule": "reasoning.productionBatch.regular_schedule",
|
||||
}
|
||||
else: # purchaseOrder context
|
||||
reasoning_type_map = {
|
||||
"low_stock_detection": "reasoning.purchaseOrder.low_stock_detection",
|
||||
"stockout_prevention": "reasoning.purchaseOrder.low_stock_detection",
|
||||
"forecast_demand": "reasoning.purchaseOrder.forecast_demand",
|
||||
"customer_orders": "reasoning.purchaseOrder.forecast_demand",
|
||||
"seasonal_demand": "reasoning.purchaseOrder.seasonal_demand",
|
||||
"inventory_replenishment": "reasoning.purchaseOrder.safety_stock_replenishment",
|
||||
"production_schedule": "reasoning.purchaseOrder.production_requirement",
|
||||
"supplier_contract": "reasoning.purchaseOrder.supplier_contract",
|
||||
"safety_stock_replenishment": "reasoning.purchaseOrder.safety_stock_replenishment",
|
||||
"production_requirement": "reasoning.purchaseOrder.production_requirement",
|
||||
"manual_request": "reasoning.purchaseOrder.manual_request",
|
||||
}
|
||||
return reasoning_type_map.get(reasoning_type, f"reasoning.{context}.forecast_demand")
|
||||
|
||||
def _calculate_po_urgency(self, po: Dict[str, Any]) -> str:
|
||||
"""Calculate urgency of PO approval based on delivery date"""
|
||||
@@ -579,7 +608,7 @@ class DashboardService:
|
||||
|
||||
# Get reasoning type and convert to i18n key
|
||||
reasoning_type = reasoning_data.get('type', 'forecast_demand')
|
||||
reasoning_type_i18n_key = self._get_reasoning_type_i18n_key(reasoning_type)
|
||||
reasoning_type_i18n_key = self._get_reasoning_type_i18n_key(reasoning_type, context="productionBatch")
|
||||
|
||||
timeline.append({
|
||||
"id": batch["id"],
|
||||
|
||||
Reference in New Issue
Block a user