178 lines
5.6 KiB
TypeScript
178 lines
5.6 KiB
TypeScript
/**
|
|
* 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, any>) => string;
|
|
renderMessage: (messageKey: string, messageParams?: Record<string, any>) => string;
|
|
renderReasoningSummary: (summaryKey: string, summaryParams?: Record<string, any>) => string;
|
|
renderActionLabel: (labelKey: string, labelParams?: Record<string, any>) => string;
|
|
renderUrgencyReason: (reasonKey: string, reasonParams?: Record<string, any>) => string;
|
|
}
|
|
|
|
/**
|
|
* Render a parameterized template with given parameters
|
|
*/
|
|
export const renderTemplate = (template: string, params: Record<string, any> = {}): 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, any> = {}): string => {
|
|
return t(titleKey, { defaultValue: titleKey, ...titleParams });
|
|
};
|
|
|
|
const renderMessage = (messageKey: string, messageParams: Record<string, any> = {}): string => {
|
|
return t(messageKey, { defaultValue: messageKey, ...messageParams });
|
|
};
|
|
|
|
const renderReasoningSummary = (summaryKey: string, summaryParams: Record<string, any> = {}): string => {
|
|
return t(summaryKey, { defaultValue: summaryKey, ...summaryParams });
|
|
};
|
|
|
|
const renderActionLabel = (labelKey: string, labelParams: Record<string, any> = {}): string => {
|
|
return t(labelKey, { defaultValue: labelKey, ...labelParams });
|
|
};
|
|
|
|
const renderUrgencyReason = (reasonKey: string, reasonParams: Record<string, any> = {}): 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}`);
|
|
}
|
|
}; |