/** * Clean i18n Parameter System for Event Content in Frontend * * Handles rendering of parameterized content for: * - Alert titles and messages * - Notification titles and messages * - Recommendation titles and messages * - AI reasoning summaries * - Action labels and consequences */ import { I18nContent, Event, Alert, Notification, Recommendation, SmartAction } from '../api/types/events'; import { useTranslation } from 'react-i18next'; interface I18nRenderer { renderTitle: (titleKey: string, titleParams?: Record) => string; renderMessage: (messageKey: string, messageParams?: Record) => string; renderReasoningSummary: (summaryKey: string, summaryParams?: Record) => string; renderActionLabel: (labelKey: string, labelParams?: Record) => string; renderUrgencyReason: (reasonKey: string, reasonParams?: Record) => string; } /** * Render a parameterized template with given parameters */ export const renderTemplate = (template: string, params: Record = {}): string => { if (!template) return ''; let result = template; for (const [key, value] of Object.entries(params)) { // Replace {{key}} with the value, handling nested properties const regex = new RegExp(`{{\\s*${key}\\s*}}`, 'g'); result = result.replace(regex, String(value ?? '')); } return result; }; /** * Hook for accessing the i18n renderer within React components */ export const useEventI18n = (): I18nRenderer => { const { t } = useTranslation(['events', 'common']); const renderTitle = (titleKey: string, titleParams: Record = {}): string => { return t(titleKey, { defaultValue: titleKey, ...titleParams }); }; const renderMessage = (messageKey: string, messageParams: Record = {}): string => { return t(messageKey, { defaultValue: messageKey, ...messageParams }); }; const renderReasoningSummary = (summaryKey: string, summaryParams: Record = {}): string => { return t(summaryKey, { defaultValue: summaryKey, ...summaryParams }); }; const renderActionLabel = (labelKey: string, labelParams: Record = {}): string => { return t(labelKey, { defaultValue: labelKey, ...labelParams }); }; const renderUrgencyReason = (reasonKey: string, reasonParams: Record = {}): string => { return t(reasonKey, { defaultValue: reasonKey, ...reasonParams }); }; return { renderTitle, renderMessage, renderReasoningSummary, renderActionLabel, renderUrgencyReason }; }; /** * Render i18n content for an event */ export const renderEventContent = (i18n: I18nContent, language?: string): { title: string; message: string } => { const title = renderTemplate(i18n.title_key, i18n.title_params); const message = renderTemplate(i18n.message_key, i18n.message_params); return { title, message }; }; /** * Render all content for an alert */ export const renderAlertContent = (alert: Alert, language?: string) => { const { title, message } = renderEventContent(alert.i18n, language); let reasoningSummary = ''; if (alert.ai_reasoning?.summary_key) { reasoningSummary = renderTemplate( alert.ai_reasoning.summary_key, alert.ai_reasoning.summary_params ); } // Render smart actions with parameterized labels const renderedActions = alert.smart_actions.map(action => ({ ...action, label: renderTemplate(action.label_key, action.label_params), consequence: action.consequence_key ? renderTemplate(action.consequence_key, action.consequence_params) : undefined, disabled_reason: action.disabled_reason_key ? renderTemplate(action.disabled_reason_key, action.disabled_reason_params) : action.disabled_reason })); return { title, message, reasoningSummary, renderedActions }; }; /** * Render all content for a notification */ export const renderNotificationContent = (notification: Notification, language?: string) => { const { title, message } = renderEventContent(notification.i18n, language); return { title, message }; }; /** * Render all content for a recommendation */ export const renderRecommendationContent = (recommendation: Recommendation, language?: string) => { const { title, message } = renderEventContent(recommendation.i18n, language); let reasoningSummary = ''; if (recommendation.ai_reasoning?.summary_key) { reasoningSummary = renderTemplate( recommendation.ai_reasoning.summary_key, recommendation.ai_reasoning.summary_params ); } // Render suggested actions with parameterized labels const renderedSuggestedActions = recommendation.suggested_actions.map(action => ({ ...action, label: renderTemplate(action.label_key, action.label_params), consequence: action.consequence_key ? renderTemplate(action.consequence_key, action.consequence_params) : undefined, disabled_reason: action.disabled_reason_key ? renderTemplate(action.disabled_reason_key, action.disabled_reason_params) : action.disabled_reason })); return { title, message, reasoningSummary, renderedSuggestedActions }; }; /** * Render content for any event type */ export const renderEvent = (event: Event, language?: string) => { switch (event.event_class) { case 'alert': return renderAlertContent(event as Alert, language); case 'notification': return renderNotificationContent(event as Notification, language); case 'recommendation': return renderRecommendationContent(event as Recommendation, language); default: throw new Error(`Unknown event class: ${(event as any).event_class}`); } };