Implement multi-language email templates
- Add language columns to email_templates table (subject_en/de, body_html_en/de, body_text_en/de) - Update adminEmail.js routes to support language-specific templates - Create EmailProcessor service to handle language selection based on recipient - Update EmailConfigPage component with language tabs similar to CMS pages - Add German translations for all email templates - Update all email queue usage to use proper template keys - Add missing email templates (gallery_expired, archive_complete) - Integrate email processor service into main server startup The system now automatically selects the appropriate language (English/German) based on the recipient's email domain or preferences. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -159,10 +159,20 @@ router.get('/templates', adminAuth, async (req, res) => {
|
||||
.select('*')
|
||||
.orderBy('template_key');
|
||||
|
||||
// Parse variables JSON
|
||||
// Parse variables JSON and format for multi-language support
|
||||
const formattedTemplates = templates.map(template => ({
|
||||
...template,
|
||||
variables: template.variables ? JSON.parse(template.variables) : []
|
||||
id: template.id,
|
||||
template_key: template.template_key,
|
||||
// English versions
|
||||
subject_en: template.subject_en || template.subject,
|
||||
body_html_en: template.body_html_en || template.body_html,
|
||||
body_text_en: template.body_text_en || template.body_text,
|
||||
// German versions
|
||||
subject_de: template.subject_de || template.subject_en || template.subject,
|
||||
body_html_de: template.body_html_de || template.body_html_en || template.body_html,
|
||||
body_text_de: template.body_text_de || template.body_text_en || template.body_text,
|
||||
variables: template.variables ? JSON.parse(template.variables) : [],
|
||||
updated_at: template.updated_at
|
||||
}));
|
||||
|
||||
res.json(formattedTemplates);
|
||||
@@ -184,8 +194,18 @@ router.get('/templates/:key', adminAuth, async (req, res) => {
|
||||
}
|
||||
|
||||
res.json({
|
||||
...template,
|
||||
variables: template.variables ? JSON.parse(template.variables) : []
|
||||
id: template.id,
|
||||
template_key: template.template_key,
|
||||
// English versions
|
||||
subject_en: template.subject_en || template.subject,
|
||||
body_html_en: template.body_html_en || template.body_html,
|
||||
body_text_en: template.body_text_en || template.body_text,
|
||||
// German versions
|
||||
subject_de: template.subject_de || template.subject_en || template.subject,
|
||||
body_html_de: template.body_html_de || template.body_html_en || template.body_html,
|
||||
body_text_de: template.body_text_de || template.body_text_en || template.body_text,
|
||||
variables: template.variables ? JSON.parse(template.variables) : [],
|
||||
updated_at: template.updated_at
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Email template fetch error:', error);
|
||||
@@ -196,8 +216,10 @@ router.get('/templates/:key', adminAuth, async (req, res) => {
|
||||
// Update email template
|
||||
router.put('/templates/:key', [
|
||||
adminAuth,
|
||||
body('subject').notEmpty().withMessage('Subject is required'),
|
||||
body('body_html').notEmpty().withMessage('HTML body is required')
|
||||
body('subject_en').optional().notEmpty().withMessage('English subject cannot be empty'),
|
||||
body('subject_de').optional().notEmpty().withMessage('German subject cannot be empty'),
|
||||
body('body_html_en').optional().notEmpty().withMessage('English HTML body cannot be empty'),
|
||||
body('body_html_de').optional().notEmpty().withMessage('German HTML body cannot be empty')
|
||||
], async (req, res) => {
|
||||
try {
|
||||
const errors = validationResult(req);
|
||||
@@ -205,29 +227,38 @@ router.put('/templates/:key', [
|
||||
return res.status(400).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
const { subject, body_html, body_text } = req.body;
|
||||
const {
|
||||
subject_en, subject_de,
|
||||
body_html_en, body_html_de,
|
||||
body_text_en, body_text_de
|
||||
} = req.body;
|
||||
|
||||
const updateData = {
|
||||
updated_at: new Date()
|
||||
};
|
||||
|
||||
// Only update provided fields
|
||||
if (subject_en !== undefined) updateData.subject_en = subject_en;
|
||||
if (subject_de !== undefined) updateData.subject_de = subject_de;
|
||||
if (body_html_en !== undefined) updateData.body_html_en = body_html_en;
|
||||
if (body_html_de !== undefined) updateData.body_html_de = body_html_de;
|
||||
if (body_text_en !== undefined) updateData.body_text_en = body_text_en || '';
|
||||
if (body_text_de !== undefined) updateData.body_text_de = body_text_de || '';
|
||||
|
||||
const updated = await db('email_templates')
|
||||
.where('template_key', req.params.key)
|
||||
.update({
|
||||
subject,
|
||||
body_html,
|
||||
body_text: body_text || '',
|
||||
updated_at: new Date()
|
||||
});
|
||||
.update(updateData);
|
||||
|
||||
if (!updated) {
|
||||
return res.status(404).json({ error: 'Template not found' });
|
||||
}
|
||||
|
||||
// Log activity
|
||||
await db('activity_logs').insert({
|
||||
activity_type: 'email_template_updated',
|
||||
actor_type: 'admin',
|
||||
actor_id: req.admin.id,
|
||||
actor_name: req.admin.username,
|
||||
metadata: JSON.stringify({ template_key: req.params.key })
|
||||
});
|
||||
await logActivity('email_template_updated',
|
||||
{ template_key: req.params.key },
|
||||
null,
|
||||
{ type: 'admin', id: req.admin.id, name: req.admin.username }
|
||||
);
|
||||
|
||||
res.json({ message: 'Email template updated successfully' });
|
||||
} catch (error) {
|
||||
@@ -247,12 +278,17 @@ router.post('/templates/:key/preview', adminAuth, async (req, res) => {
|
||||
return res.status(404).json({ error: 'Template not found' });
|
||||
}
|
||||
|
||||
const { preview_data } = req.body;
|
||||
const { preview_data, language = 'en' } = req.body;
|
||||
|
||||
// Replace variables in template
|
||||
let htmlContent = template.body_html;
|
||||
let textContent = template.body_text || '';
|
||||
let subject = template.subject;
|
||||
// Get the appropriate language version
|
||||
const subjectField = language === 'de' && template.subject_de ? 'subject_de' : 'subject_en';
|
||||
const htmlField = language === 'de' && template.body_html_de ? 'body_html_de' : 'body_html_en';
|
||||
const textField = language === 'de' && template.body_text_de ? 'body_text_de' : 'body_text_en';
|
||||
|
||||
// Handle backward compatibility
|
||||
let htmlContent = template[htmlField] || template.body_html || '';
|
||||
let textContent = template[textField] || template.body_text || '';
|
||||
let subject = template[subjectField] || template.subject || '';
|
||||
|
||||
if (preview_data) {
|
||||
Object.keys(preview_data).forEach(key => {
|
||||
@@ -266,7 +302,8 @@ router.post('/templates/:key/preview', adminAuth, async (req, res) => {
|
||||
res.json({
|
||||
subject,
|
||||
body_html: htmlContent,
|
||||
body_text: textContent
|
||||
body_text: textContent,
|
||||
language
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Email template preview error:', error);
|
||||
|
||||
Reference in New Issue
Block a user