feat: multilingual email templates with translations table
Replace column-based email template languages (subject_en/subject_de) with a normalized email_template_translations table where each language is a row. This allows adding new languages without schema changes. - Add migration 075 to create email_template_translations table, migrate existing EN/DE data, and seed NL/PT/RU for customer-facing templates - Update processTemplate() to query translations table with fallback chain (requested lang -> en -> first available), with legacy column fallback - Restructure admin email API to return/accept translations object format - Update frontend EmailConfigPage with dynamic 5-language tabs, translation count badges, and copy-from-language feature for empty translations - Add Dutch to default language dropdown in general settings - Add Dutch to clientAccessI18n and password security messages in emails - Expand email domain detection for NL/BE/BR/PT/RU domains - Add email i18n keys (copyFrom, noTranslation, etc.) across all 5 locales
This commit is contained in:
@@ -11,19 +11,17 @@ export interface EmailConfig {
|
||||
tls_reject_unauthorized: boolean;
|
||||
}
|
||||
|
||||
export interface EmailTemplateTranslation {
|
||||
subject: string;
|
||||
body_html: string;
|
||||
body_text?: string;
|
||||
}
|
||||
|
||||
export interface EmailTemplate {
|
||||
id: number;
|
||||
template_key: string;
|
||||
subject: string; // For backward compatibility
|
||||
body_html: string; // For backward compatibility
|
||||
body_text?: string; // For backward compatibility
|
||||
subject_en: string;
|
||||
subject_de: string;
|
||||
body_html_en: string;
|
||||
body_html_de: string;
|
||||
body_text_en?: string;
|
||||
body_text_de?: string;
|
||||
variables: string[];
|
||||
translations: Record<string, EmailTemplateTranslation>;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
@@ -63,16 +61,16 @@ export const emailService = {
|
||||
},
|
||||
|
||||
// Update email template
|
||||
async updateTemplate(key: string, template: Partial<EmailTemplate>): Promise<void> {
|
||||
await api.put(`/admin/email/templates/${key}`, template);
|
||||
async updateTemplate(key: string, data: { translations: Record<string, EmailTemplateTranslation> }): Promise<void> {
|
||||
await api.put(`/admin/email/templates/${key}`, data);
|
||||
},
|
||||
|
||||
// Preview email template
|
||||
async previewTemplate(key: string, previewData: Record<string, string>, language: 'en' | 'de' = 'en'): Promise<EmailPreview> {
|
||||
async previewTemplate(key: string, previewData: Record<string, string>, language: string = 'en'): Promise<EmailPreview> {
|
||||
const response = await api.post<EmailPreview>(
|
||||
`/admin/email/templates/${key}/preview`,
|
||||
{ preview_data: previewData, language }
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user