mirror of
https://github.com/wekan/wekan.git
synced 2025-09-22 01:50:48 +02:00
Merge pull request #5769 from Adamsss001/feature/email-i18n
Add email notifications language localization feature
This commit is contained in:
commit
d65c422e3f
6 changed files with 142 additions and 118 deletions
|
@ -275,22 +275,18 @@ if (Meteor.isServer) {
|
|||
url: FlowRouter.url('sign-up'),
|
||||
};
|
||||
const lang = author.getLanguage();
|
||||
/*
|
||||
if (process.env.MAIL_SERVICE !== '') {
|
||||
let transporter = nodemailer.createTransport({
|
||||
service: process.env.MAIL_SERVICE,
|
||||
auth: {
|
||||
user: process.env.MAIL_SERVICE_USER,
|
||||
pass: process.env.MAIL_SERVICE_PASSWORD
|
||||
},
|
||||
})
|
||||
let info = transporter.sendMail({
|
||||
// Use EmailLocalization utility to handle email in the proper language
|
||||
if (typeof EmailLocalization !== 'undefined') {
|
||||
EmailLocalization.sendEmail({
|
||||
to: icode.email,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject: TAPi18n.__('email-invite-register-subject', params, lang),
|
||||
text: TAPi18n.__('email-invite-register-text', params, lang),
|
||||
})
|
||||
subject: 'email-invite-register-subject',
|
||||
text: 'email-invite-register-text',
|
||||
params: params,
|
||||
language: lang
|
||||
});
|
||||
} else {
|
||||
// Fallback if EmailLocalization is not available
|
||||
Email.send({
|
||||
to: icode.email,
|
||||
from: Accounts.emailTemplates.from,
|
||||
|
@ -298,13 +294,6 @@ if (Meteor.isServer) {
|
|||
text: TAPi18n.__('email-invite-register-text', params, lang),
|
||||
});
|
||||
}
|
||||
*/
|
||||
Email.send({
|
||||
to: icode.email,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject: TAPi18n.__('email-invite-register-subject', params, lang),
|
||||
text: TAPi18n.__('email-invite-register-text', params, lang),
|
||||
});
|
||||
} catch (e) {
|
||||
InvitationCodes.remove(_id);
|
||||
throw new Meteor.Error('email-fail', e.message);
|
||||
|
|
|
@ -1618,62 +1618,51 @@ if (Meteor.isServer) {
|
|||
subBoard.addMember(user._id);
|
||||
user.addInvite(subBoard._id);
|
||||
}
|
||||
}
|
||||
} try {
|
||||
const fullName =
|
||||
inviter.profile !== undefined &&
|
||||
inviter.profile.fullname !== undefined
|
||||
? inviter.profile.fullname
|
||||
: '';
|
||||
const userFullName =
|
||||
user.profile !== undefined && user.profile.fullname !== undefined
|
||||
? user.profile.fullname
|
||||
: '';
|
||||
const params = {
|
||||
user:
|
||||
userFullName != ''
|
||||
? userFullName + ' (' + user.username + ' )'
|
||||
: user.username,
|
||||
inviter:
|
||||
fullName != ''
|
||||
? fullName + ' (' + inviter.username + ' )'
|
||||
: inviter.username,
|
||||
board: board.title,
|
||||
url: board.absoluteUrl(),
|
||||
};
|
||||
// Get the recipient user's language preference for the email
|
||||
const lang = user.getLanguage();
|
||||
|
||||
try {
|
||||
const fullName =
|
||||
inviter.profile !== undefined &&
|
||||
inviter.profile.fullname !== undefined
|
||||
? inviter.profile.fullname
|
||||
: '';
|
||||
const userFullName =
|
||||
user.profile !== undefined && user.profile.fullname !== undefined
|
||||
? user.profile.fullname
|
||||
: '';
|
||||
const params = {
|
||||
user:
|
||||
userFullName != ''
|
||||
? userFullName + ' (' + user.username + ' )'
|
||||
: user.username,
|
||||
inviter:
|
||||
fullName != ''
|
||||
? fullName + ' (' + inviter.username + ' )'
|
||||
: inviter.username,
|
||||
board: board.title,
|
||||
url: board.absoluteUrl(),
|
||||
};
|
||||
const lang = user.getLanguage();
|
||||
|
||||
/*
|
||||
if (process.env.MAIL_SERVICE !== '') {
|
||||
let transporter = nodemailer.createTransport({
|
||||
service: process.env.MAIL_SERVICE,
|
||||
auth: {
|
||||
user: process.env.MAIL_SERVICE_USER,
|
||||
pass: process.env.MAIL_SERVICE_PASSWORD
|
||||
},
|
||||
})
|
||||
let info = transporter.sendMail({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject: TAPi18n.__('email-invite-subject', params, lang),
|
||||
text: TAPi18n.__('email-invite-text', params, lang),
|
||||
})
|
||||
} else {
|
||||
Email.send({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject: TAPi18n.__('email-invite-subject', params, lang),
|
||||
text: TAPi18n.__('email-invite-text', params, lang),
|
||||
});
|
||||
}
|
||||
*/
|
||||
Email.send({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject: TAPi18n.__('email-invite-subject', params, lang),
|
||||
text: TAPi18n.__('email-invite-text', params, lang),
|
||||
});
|
||||
// Add code to send invitation with EmailLocalization
|
||||
if (typeof EmailLocalization !== 'undefined') {
|
||||
EmailLocalization.sendEmail({
|
||||
to: user.emails[0].address,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject: 'email-invite-subject',
|
||||
text: 'email-invite-text',
|
||||
params: params,
|
||||
language: lang,
|
||||
userId: user._id
|
||||
});
|
||||
} else {
|
||||
// Fallback if EmailLocalization is not available
|
||||
Email.send({
|
||||
to: user.emails[0].address,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject: TAPi18n.__('email-invite-subject', params, lang),
|
||||
text: TAPi18n.__('email-invite-text', params, lang),
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Meteor.Error('email-fail', e.message);
|
||||
}
|
||||
|
|
58
server/lib/emailLocalization.js
Normal file
58
server/lib/emailLocalization.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
// emailLocalization.js
|
||||
// Utility functions to handle email localization in Wekan
|
||||
|
||||
import { TAPi18n } from '/imports/i18n';
|
||||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
|
||||
// Main object for email localization utilities
|
||||
EmailLocalization = {
|
||||
/**
|
||||
* Send an email using the recipient's preferred language
|
||||
* @param {Object} options - Standard email sending options plus language options
|
||||
* @param {String} options.to - Recipient email address
|
||||
* @param {String} options.from - Sender email address
|
||||
* @param {String} options.subject - Email subject i18n key
|
||||
* @param {String} options.text - Email text i18n key
|
||||
* @param {Object} options.params - Parameters for i18n translation
|
||||
* @param {String} options.language - Language code to use (if not provided, will try to detect)
|
||||
* @param {String} options.userId - User ID to determine language (if not provided with language)
|
||||
*/
|
||||
sendEmail(options) {
|
||||
// Determine the language to use
|
||||
let lang = options.language;
|
||||
|
||||
// If no language is specified but we have a userId, try to get the user's language
|
||||
if (!lang && options.userId) {
|
||||
const user = ReactiveCache.getUser(options.userId);
|
||||
if (user) {
|
||||
lang = user.getLanguage();
|
||||
}
|
||||
}
|
||||
|
||||
// If no language could be determined, use the site default
|
||||
if (!lang) {
|
||||
lang = TAPi18n.getLanguage() || 'en';
|
||||
}
|
||||
|
||||
// Translate subject and text using the determined language
|
||||
const subject = TAPi18n.__(options.subject, options.params || {}, lang);
|
||||
let text = options.text;
|
||||
|
||||
// If text is an i18n key, translate it
|
||||
if (typeof text === 'string' && text.startsWith('email-')) {
|
||||
text = TAPi18n.__(text, options.params || {}, lang);
|
||||
}
|
||||
|
||||
// Send the email with translated content
|
||||
return Email.send({
|
||||
to: options.to,
|
||||
from: options.from || Accounts.emailTemplates.from,
|
||||
subject: subject,
|
||||
text: text,
|
||||
html: options.html
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Add module.exports to make it accessible from other files
|
||||
module.exports = EmailLocalization;
|
4
server/lib/importer.js
Normal file
4
server/lib/importer.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
// This file ensures the EmailLocalization utility is imported
|
||||
// and available throughout the application
|
||||
|
||||
import './emailLocalization';
|
|
@ -2,6 +2,8 @@ import { ReactiveCache } from '/imports/reactiveCache';
|
|||
import { TAPi18n } from '/imports/i18n';
|
||||
//var nodemailer = require('nodemailer');
|
||||
|
||||
import EmailLocalization from '../lib/emailLocalization';
|
||||
|
||||
// buffer each user's email text in a queue, then flush them in single email
|
||||
Meteor.startup(() => {
|
||||
Notifications.subscribe('email', (user, title, description, params) => {
|
||||
|
@ -14,6 +16,7 @@ Meteor.startup(() => {
|
|||
quoteParams[key] = quoteParams[key] ? `${params[key]}` : '';
|
||||
});
|
||||
|
||||
// Get user's preferred language
|
||||
const lan = user.getLanguage();
|
||||
const subject = TAPi18n.__(title, params, lan); // the original function has a fault, i believe the title should be used according to original author
|
||||
const existing = user.getEmailBuffer().length > 0;
|
||||
|
@ -42,35 +45,14 @@ Meteor.startup(() => {
|
|||
const html = texts.join('<br/>\n\n');
|
||||
user.clearEmailBuffer();
|
||||
try {
|
||||
/*
|
||||
if (process.env.MAIL_SERVICE !== '') {
|
||||
let transporter = nodemailer.createTransport({
|
||||
service: process.env.MAIL_SERVICE,
|
||||
auth: {
|
||||
user: process.env.MAIL_SERVICE_USER,
|
||||
pass: process.env.MAIL_SERVICE_PASSWORD
|
||||
},
|
||||
})
|
||||
let info = transporter.sendMail({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
html,
|
||||
})
|
||||
} else {
|
||||
Email.send({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
html,
|
||||
});
|
||||
}
|
||||
*/
|
||||
Email.send({
|
||||
// Use EmailLocalization utility to ensure the correct language is used
|
||||
EmailLocalization.sendEmail({
|
||||
to: user.emails[0].address.toLowerCase(),
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
html,
|
||||
language: user.getLanguage(),
|
||||
userId: user._id
|
||||
});
|
||||
} catch (e) {
|
||||
return;
|
||||
|
|
|
@ -125,22 +125,31 @@ RulesHelper = {
|
|||
const text = action.emailMsg || '';
|
||||
const subject = action.emailSubject || '';
|
||||
try {
|
||||
/*
|
||||
if (process.env.MAIL_SERVICE !== '') {
|
||||
let transporter = nodemailer.createTransport({
|
||||
service: process.env.MAIL_SERVICE,
|
||||
auth: {
|
||||
user: process.env.MAIL_SERVICE_USER,
|
||||
pass: process.env.MAIL_SERVICE_PASSWORD
|
||||
},
|
||||
})
|
||||
let info = transporter.sendMail({
|
||||
// Try to detect the recipient's language preference if it's a Wekan user
|
||||
// Otherwise, use the default language for the rule-triggered emails
|
||||
let recipientUser = null;
|
||||
let recipientLang = TAPi18n.getLanguage() || 'en';
|
||||
|
||||
// Check if recipient is a Wekan user to get their language
|
||||
if (to && to.includes('@')) {
|
||||
recipientUser = ReactiveCache.getUser({ 'emails.address': to.toLowerCase() });
|
||||
if (recipientUser && typeof recipientUser.getLanguage === 'function') {
|
||||
recipientLang = recipientUser.getLanguage();
|
||||
}
|
||||
}
|
||||
|
||||
// Use EmailLocalization if available
|
||||
if (typeof EmailLocalization !== 'undefined') {
|
||||
EmailLocalization.sendEmail({
|
||||
to,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
text,
|
||||
})
|
||||
language: recipientLang,
|
||||
userId: recipientUser ? recipientUser._id : null
|
||||
});
|
||||
} else {
|
||||
// Fallback to standard Email.send
|
||||
Email.send({
|
||||
to,
|
||||
from: Accounts.emailTemplates.from,
|
||||
|
@ -148,13 +157,6 @@ RulesHelper = {
|
|||
text,
|
||||
});
|
||||
}
|
||||
*/
|
||||
Email.send({
|
||||
to,
|
||||
from: Accounts.emailTemplates.from,
|
||||
subject,
|
||||
text,
|
||||
});
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue