From 5c228fc9333aa7e7d5f05fa8794623e05d5847bc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 10:13:23 +0000 Subject: [PATCH 1/3] Initial plan From 338a9b42010374f2a3e4827232c2dc5ec41e8438 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 10:19:34 +0000 Subject: [PATCH 2/3] feat: localize email notification content Agent-Logs-Url: https://github.com/ether/ep_email_notifications/sessions/f3033cd5-8920-4012-9ab7-06a01e394045 Co-authored-by: JohnMcLear <220864+JohnMcLear@users.noreply.github.com> --- emailTemplates.js | 78 +++++++++++++++++++ handleMessage.js | 52 +++++++++---- index.js | 1 + locales/de.json | 9 +++ locales/en.json | 9 +++ locales/es.json | 9 +++ locales/fr.json | 9 +++ locales/hu.json | 9 +++ static/js/ep_email.js | 3 +- .../backend/specs/emailTemplates.spec.js | 46 +++++++++++ update.js | 23 ++++-- 11 files changed, 225 insertions(+), 23 deletions(-) create mode 100644 emailTemplates.js create mode 100644 static/tests/backend/specs/emailTemplates.spec.js diff --git a/emailTemplates.js b/emailTemplates.js new file mode 100644 index 0000000..7410495 --- /dev/null +++ b/emailTemplates.js @@ -0,0 +1,78 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const defaultLocale = 'en'; +const localeDir = path.join(__dirname, 'locales'); +const availableLocales = new Set( + fs.readdirSync(localeDir) + .filter((name) => name.endsWith('.json')) + .map((name) => path.basename(name, '.json')), +); +const translations = new Map(); + +const normalizeLocale = (locale) => { + if (typeof locale !== 'string' || locale === '') return defaultLocale; + const normalized = locale.toLowerCase().replace(/_/g, '-'); + for (const candidate of [normalized, normalized.split('-')[0]]) { + if (availableLocales.has(candidate)) return candidate; + } + return defaultLocale; +}; + +const getTranslations = (locale) => { + const resolvedLocale = normalizeLocale(locale); + if (!translations.has(resolvedLocale)) { + translations.set(resolvedLocale, JSON.parse( + fs.readFileSync(path.join(localeDir, `${resolvedLocale}.json`), 'utf8'))); + } + return translations.get(resolvedLocale); +}; + +const translate = (locale, key, replacements = {}) => { + const template = getTranslations(locale)[key] ?? getTranslations(defaultLocale)[key] ?? key; + return template.replace(/\{(\w+)\}/g, (match, name) => { + if (!Object.prototype.hasOwnProperty.call(replacements, name)) return match; + return `${replacements[name]}`; + }); +}; + +const getUserLocale = (userInfo) => normalizeLocale(userInfo && userInfo.language); + +const getConfirmationEmail = ({action, locale, padId, padUrl, token}) => { + const actionUrl = `${padUrl}/${action}=${token}`; + const subjectKey = action === 'unsubscribe' + ? 'ep_email_notifications.emailUnsubscriptionConfirmationSubject' + : 'ep_email_notifications.emailSubscriptionConfirmationSubject'; + const bodyKey = action === 'unsubscribe' + ? 'ep_email_notifications.emailUnsubscriptionConfirmationBody' + : 'ep_email_notifications.emailSubscriptionConfirmationBody'; + return { + subject: translate(locale, subjectKey, {padId}), + text: translate(locale, bodyKey, {actionUrl, padId}), + }; +}; + +const getNotificationEmail = ({event, locale, padId, padUrl}) => { + const footer = translate(locale, 'ep_email_notifications.emailFooter'); + const subjectKey = event === 'end' + ? 'ep_email_notifications.emailNotificationEndSubject' + : 'ep_email_notifications.emailNotificationStartSubject'; + const bodyKey = event === 'end' + ? 'ep_email_notifications.emailNotificationEndBody' + : 'ep_email_notifications.emailNotificationStartBody'; + return { + subject: translate(locale, subjectKey, {padId}), + text: translate(locale, bodyKey, {footer, padUrl}), + }; +}; + +module.exports = { + defaultLocale, + getConfirmationEmail, + getNotificationEmail, + getUserLocale, + normalizeLocale, + translate, +}; diff --git a/handleMessage.js b/handleMessage.js index 7cc7bc4..a870ca1 100644 --- a/handleMessage.js +++ b/handleMessage.js @@ -4,6 +4,10 @@ const db = require('ep_etherpad-lite/node/db/DB'); const email = require('emailjs'); const randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; const settings = require('ep_etherpad-lite/node/utils/Settings'); +const { + getConfirmationEmail, + getUserLocale, +} = require('./emailTemplates'); const util = require('util'); const validator = require('validator'); @@ -42,7 +46,7 @@ exports.handleMessage = async (hookName, context) => { const userInfo = context.message.data.userInfo; if (!userInfo || !userInfo.email || !userInfo.email_option) return; if (!pluginSettings) { - context.socket.emit("message", { + context.socket.emit('message', { type: 'COLLABROOM', data: { type: 'emailNotificationMissingParams', @@ -147,7 +151,7 @@ const subscriptionEmail = async (context, email, emailFound, userInfo, padId) => await setAuthorEmailRegistered(userInfo, userInfo.userId, subscribeId, padId); console.debug('emailSubSucc'); - context.socket.emit("message", { + context.socket.emit('message', { type: 'COLLABROOM', data: { type: 'emailSubscriptionSuccess', @@ -161,12 +165,18 @@ const subscriptionEmail = async (context, email, emailFound, userInfo, padId) => // Send mail to user with the link for validation let message; try { + const localizedEmail = getConfirmationEmail({ + action: 'subscribe', + locale: getUserLocale(userInfo), + padId, + padUrl: padUrl(padId), + token: subscribeId, + }); message = await util.promisify(server.send.bind(server))({ - text: 'Please click on this link in order to validate your subscription to the pad ' + - `${padId}\n${padUrl(padId)}/subscribe=${subscribeId}`, + text: localizedEmail.text, from: `${fromName} <${fromEmail}>`, to: userInfo.email, - subject: `Email subscription confirmation for pad ${padId}`, + subject: localizedEmail.subject, }); } catch (err) { console.error(err); @@ -176,7 +186,7 @@ const subscriptionEmail = async (context, email, emailFound, userInfo, padId) => } else if (!validatesAsEmail) { // Subscription -> failed coz mail malformed.. y'know in general fuck em! console.debug('Dropped email subscription due to malformed email address'); - context.socket.emit("message", { + context.socket.emit('message', { type: 'COLLABROOM', data: { type: 'emailSubscriptionSuccess', @@ -192,7 +202,7 @@ const subscriptionEmail = async (context, email, emailFound, userInfo, padId) => console.debug('email ', context.message.data.userInfo.email, 'already subscribed to ', context.message.data.padId, ' so sending message to client'); - context.socket.emit("message", { + context.socket.emit('message', { type: 'COLLABROOM', data: { type: 'emailSubscriptionSuccess', @@ -219,7 +229,7 @@ const unsubscriptionEmail = async (context, emailFound, userInfo, padId) => { await unsetAuthorEmailRegistered(userInfo, userInfo.userId, unsubscribeId, padId); - context.socket.emit("message", { + context.socket.emit('message', { type: 'COLLABROOM', data: { type: 'emailUnsubscriptionSuccess', @@ -233,12 +243,18 @@ const unsubscriptionEmail = async (context, emailFound, userInfo, padId) => { // Send mail to user with the link for validation let message; try { + const localizedEmail = getConfirmationEmail({ + action: 'unsubscribe', + locale: getUserLocale(userInfo), + padId, + padUrl: padUrl(padId), + token: unsubscribeId, + }); message = await util.promisify(server.send.bind(server))({ - text: 'Please click on this link in order to validate your unsubscription to the pad ' + - `${padId}\n${padUrl(padId)}/unsubscribe=${unsubscribeId}`, + text: localizedEmail.text, from: `${fromName} <${fromEmail}>`, to: userInfo.email, - subject: `Email unsubscription confirmation for pad ${padId}`, + subject: localizedEmail.subject, }); } catch (err) { console.error(err); @@ -250,7 +266,7 @@ const unsubscriptionEmail = async (context, emailFound, userInfo, padId) => { console.debug( 'Unsubscription: Send client a negative response ', context.message.data.userInfo.email); - context.socket.emit("message", { + context.socket.emit('message', { type: 'COLLABROOM', data: { type: 'emailUnsubscriptionSuccess', @@ -270,7 +286,7 @@ const sendUserInfo = (context, emailFound, email, userInfo) => { const {onStart = true, onEnd = false} = userInfo; if (emailFound) { // We send back the options associated to this userId - context.socket.emit("message", { + context.socket.emit('message', { type: 'COLLABROOM', data: { type: 'emailNotificationGetUserInfo', @@ -285,7 +301,7 @@ const sendUserInfo = (context, emailFound, email, userInfo) => { }); } else { // No options set for this userId - context.socket.emit("message", { + context.socket.emit('message', { type: 'COLLABROOM', data: { type: 'emailNotificationGetUserInfo', @@ -309,6 +325,7 @@ const setAuthorEmailRegistered = async (userInfo, authorId, subscribeId, padId) authorId, onStart: userInfo.email_onStart, onEnd: userInfo.email_onEnd, + locale: getUserLocale(userInfo), subscribeId, timestamp, }; @@ -335,7 +352,12 @@ const unsetAuthorEmailRegistered = async (userInfo, authorId, unsubscribeId, pad if (!value.pending) value.pending = {}; // add the registered values to the pending section of the object - value.pending[userInfo.email] = {authorId, unsubscribeId, timestamp}; + value.pending[userInfo.email] = { + authorId, + locale: getUserLocale(userInfo), + timestamp, + unsubscribeId, + }; // Write the modified datas back in the Db await db.set(`emailSubscription:${padId}`, value); diff --git a/index.js b/index.js index 9b14675..5a714c2 100644 --- a/index.js +++ b/index.js @@ -83,6 +83,7 @@ const setAuthorEmailRegistered = async (userIds, userInfo, email, padId) => { const timestamp = new Date().getTime(); const registered = { authorId: userInfo.authorId, + locale: userInfo.locale, onStart: userInfo.onStart, onEnd: userInfo.onEnd, timestamp, diff --git a/locales/de.json b/locales/de.json index cd387f6..d1524a4 100644 --- a/locales/de.json +++ b/locales/de.json @@ -16,4 +16,13 @@ , "ep_email_notifications.formOptionOnEnd": "aufhört, das Pad zu bearbeiten" , "ep_email_notifications.formBtnSubscr": "Anmelden" , "ep_email_notifications.formBtnUnsubscr": "Abmelden" +, "ep_email_notifications.emailFooter": "Sie können diese E-Mails im Einstellungsfenster des Pads abbestellen." +, "ep_email_notifications.emailNotificationStartSubject": "Jemand hat mit der Bearbeitung von {padId} begonnen" +, "ep_email_notifications.emailNotificationStartBody": "Dieses Pad wird gerade bearbeitet:\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailNotificationEndSubject": "Jemand hat die Bearbeitung von {padId} beendet" +, "ep_email_notifications.emailNotificationEndBody": "Dieses Pad wird nicht mehr bearbeitet:\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailSubscriptionConfirmationSubject": "Bestätigung der E-Mail-Anmeldung für Pad {padId}" +, "ep_email_notifications.emailSubscriptionConfirmationBody": "Bitte klicken Sie auf diesen Link, um Ihre Anmeldung für das Pad {padId} zu bestätigen\n{actionUrl}" +, "ep_email_notifications.emailUnsubscriptionConfirmationSubject": "Bestätigung der E-Mail-Abmeldung für Pad {padId}" +, "ep_email_notifications.emailUnsubscriptionConfirmationBody": "Bitte klicken Sie auf diesen Link, um Ihre Abmeldung vom Pad {padId} zu bestätigen\n{actionUrl}" } diff --git a/locales/en.json b/locales/en.json index 21a0b0d..10d02a0 100644 --- a/locales/en.json +++ b/locales/en.json @@ -16,4 +16,13 @@ , "ep_email_notifications.formOptionOnEnd": "finishes editing this pad" , "ep_email_notifications.formBtnSubscr": "Subscribe" , "ep_email_notifications.formBtnUnsubscr": "Unsubscribe" +, "ep_email_notifications.emailFooter": "You can unsubscribe from these emails in the pad's Settings window." +, "ep_email_notifications.emailNotificationStartSubject": "Someone started editing {padId}" +, "ep_email_notifications.emailNotificationStartBody": "This pad is now being edited:\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailNotificationEndSubject": "Someone finished editing {padId}" +, "ep_email_notifications.emailNotificationEndBody": "This pad is done being edited:\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailSubscriptionConfirmationSubject": "Email subscription confirmation for pad {padId}" +, "ep_email_notifications.emailSubscriptionConfirmationBody": "Please click on this link in order to validate your subscription to the pad {padId}\n{actionUrl}" +, "ep_email_notifications.emailUnsubscriptionConfirmationSubject": "Email unsubscription confirmation for pad {padId}" +, "ep_email_notifications.emailUnsubscriptionConfirmationBody": "Please click on this link in order to validate your unsubscription to the pad {padId}\n{actionUrl}" } diff --git a/locales/es.json b/locales/es.json index ceeb5c2..4c11f6a 100644 --- a/locales/es.json +++ b/locales/es.json @@ -16,4 +16,13 @@ , "ep_email_notifications.formOptionOnEnd": "termine de editar este documento" , "ep_email_notifications.formBtnSubscr": "Suscribirse" , "ep_email_notifications.formBtnUnsubscr": "Desuscribirse" +, "ep_email_notifications.emailFooter": "Puedes darte de baja de estos correos desde la ventana de configuración del pad." +, "ep_email_notifications.emailNotificationStartSubject": "Alguien empezó a editar {padId}" +, "ep_email_notifications.emailNotificationStartBody": "Este pad se está editando ahora:\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailNotificationEndSubject": "Alguien terminó de editar {padId}" +, "ep_email_notifications.emailNotificationEndBody": "La edición de este pad ha finalizado:\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailSubscriptionConfirmationSubject": "Confirmación de suscripción por correo para el pad {padId}" +, "ep_email_notifications.emailSubscriptionConfirmationBody": "Haz clic en este enlace para validar tu suscripción al pad {padId}\n{actionUrl}" +, "ep_email_notifications.emailUnsubscriptionConfirmationSubject": "Confirmación de desuscripción por correo para el pad {padId}" +, "ep_email_notifications.emailUnsubscriptionConfirmationBody": "Haz clic en este enlace para validar tu desuscripción del pad {padId}\n{actionUrl}" } diff --git a/locales/fr.json b/locales/fr.json index a301ed5..8a7e4c8 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -16,4 +16,13 @@ , "ep_email_notifications.formOptionOnEnd": "a fini d\u2019\u00e9diter le pad" , "ep_email_notifications.formBtnSubscr": "inscription" , "ep_email_notifications.formBtnUnsubscr": "d\u00e9sinscription" +, "ep_email_notifications.emailFooter": "Vous pouvez vous d\u00e9sinscrire de ces e-mails dans la fen\u00eatre des param\u00e8tres du pad." +, "ep_email_notifications.emailNotificationStartSubject": "Quelqu\u2019un a commenc\u00e9 \u00e0 modifier {padId}" +, "ep_email_notifications.emailNotificationStartBody": "Ce pad est en cours de modification :\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailNotificationEndSubject": "Quelqu\u2019un a termin\u00e9 la modification de {padId}" +, "ep_email_notifications.emailNotificationEndBody": "La modification de ce pad est termin\u00e9e :\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailSubscriptionConfirmationSubject": "Confirmation d\u2019inscription par e-mail pour le pad {padId}" +, "ep_email_notifications.emailSubscriptionConfirmationBody": "Veuillez cliquer sur ce lien pour valider votre inscription au pad {padId}\n{actionUrl}" +, "ep_email_notifications.emailUnsubscriptionConfirmationSubject": "Confirmation de d\u00e9sinscription par e-mail pour le pad {padId}" +, "ep_email_notifications.emailUnsubscriptionConfirmationBody": "Veuillez cliquer sur ce lien pour valider votre d\u00e9sinscription du pad {padId}\n{actionUrl}" } diff --git a/locales/hu.json b/locales/hu.json index 724a01f..cda1769 100644 --- a/locales/hu.json +++ b/locales/hu.json @@ -16,4 +16,13 @@ , "ep_email_notifications.formOptionOnEnd": "befejezi a jegyzetfüzet szerkesztését" , "ep_email_notifications.formBtnSubscr": "feliratkozás" , "ep_email_notifications.formBtnUnsubscr": "leiratkozás" +, "ep_email_notifications.emailFooter": "Ezekről az e-mailekről a pad Beállítások ablakában tud leiratkozni." +, "ep_email_notifications.emailNotificationStartSubject": "Valaki elkezdte szerkeszteni ezt: {padId}" +, "ep_email_notifications.emailNotificationStartBody": "Ezt a padet most szerkesztik:\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailNotificationEndSubject": "Valaki befejezte ennek a szerkesztését: {padId}" +, "ep_email_notifications.emailNotificationEndBody": "Ennek a padnek a szerkesztése befejeződött:\n <{padUrl}>\n{footer}" +, "ep_email_notifications.emailSubscriptionConfirmationSubject": "{padId} pad e-mailes feliratkozásának megerősítése" +, "ep_email_notifications.emailSubscriptionConfirmationBody": "Kattintson erre a hivatkozásra, hogy megerősítse a {padId} padre való feliratkozását\n{actionUrl}" +, "ep_email_notifications.emailUnsubscriptionConfirmationSubject": "{padId} pad e-mailes leiratkozásának megerősítése" +, "ep_email_notifications.emailUnsubscriptionConfirmationBody": "Kattintson erre a hivatkozásra, hogy megerősítse a {padId} padról való leiratkozását\n{actionUrl}" } diff --git a/static/js/ep_email.js b/static/js/ep_email.js index a740df2..5987e1d 100644 --- a/static/js/ep_email.js +++ b/static/js/ep_email.js @@ -85,7 +85,6 @@ exports.handleClientMessage_emailSubscriptionSuccess = (hook, context) => { $('.ep_email_settings').slideToggle(); $('#options-emailNotifications').prop('checked', false); } - } }; @@ -105,7 +104,6 @@ exports.handleClientMessage_emailUnsubscriptionSuccess = (hook, context) => { $('.ep_email_settings').slideToggle(); $('#options-emailNotifications').prop('checked', false); } - } }; @@ -219,6 +217,7 @@ const sendEmailToServer = (formName) => { message.userInfo.email_onStart = $(`#${formName} [name=ep_email_onStart]`).is(':checked'); message.userInfo.email_onEnd = $(`#${formName} [name=ep_email_onEnd]`).is(':checked'); message.userInfo.formName = formName; + message.userInfo.language = document.documentElement.lang || navigator.language || 'en'; message.userInfo.userId = userId; if (email) { pad.collabClient.sendMessage(message); diff --git a/static/tests/backend/specs/emailTemplates.spec.js b/static/tests/backend/specs/emailTemplates.spec.js new file mode 100644 index 0000000..699f84f --- /dev/null +++ b/static/tests/backend/specs/emailTemplates.spec.js @@ -0,0 +1,46 @@ +'use strict'; + +const assert = require('node:assert/strict'); + +const { + getConfirmationEmail, + getNotificationEmail, + getUserLocale, + normalizeLocale, +} = require('../../../../emailTemplates'); + +{ + const email = getConfirmationEmail({ + action: 'subscribe', + locale: 'fr-CA', + padId: 'test-pad', + padUrl: 'https://example.test/p/test-pad', + token: 'abc123', + }); + + assert.equal(email.subject, 'Confirmation d’inscription par e-mail pour le pad test-pad'); + assert.match( + email.text, + /Veuillez cliquer sur ce lien pour valider votre inscription au pad test-pad/, + ); + assert.match(email.text, /https:\/\/example\.test\/p\/test-pad\/subscribe=abc123/); +} + +{ + const email = getNotificationEmail({ + event: 'end', + locale: 'pt-BR', + padId: 'test-pad', + padUrl: 'https://example.test/p/test-pad', + }); + + assert.equal(email.subject, 'Someone finished editing test-pad'); + assert.match(email.text, /This pad is done being edited:/); + assert.match(email.text, /You can unsubscribe from these emails in the pad's Settings window\./); +} + +{ + assert.equal(getUserLocale({language: 'de-DE'}), 'de'); + assert.equal(normalizeLocale('hu_HU'), 'hu'); + assert.equal(normalizeLocale(), 'en'); +} diff --git a/update.js b/update.js index 3e58eff..bd053fa 100644 --- a/update.js +++ b/update.js @@ -6,6 +6,7 @@ const db = require('ep_etherpad-lite/node/db/DB'); const API = require('ep_etherpad-lite/node/db/API'); const email = require('emailjs'); const settings = require('ep_etherpad-lite/node/utils/Settings'); +const {getNotificationEmail} = require('./emailTemplates'); const util = require('util'); const SMTPClient = email.SMTPClient; @@ -33,8 +34,6 @@ const timers = {}; const server = new SMTPClient(emailServer); -const emailFooter = "\nYou can unsubscribe from these emails in the pad's Settings window.\n"; - exports.padUpdate = (hookName, _pad) => { if (!pluginSettings) return false; @@ -72,11 +71,17 @@ const notifyBegin = async (padId) => { console.debug(`Emailing ${recipient} about a new begin update`); let message; try { + const localizedEmail = getNotificationEmail({ + event: 'start', + locale: recipients[recipient].locale, + padId, + padUrl: padUrl(padId), + }); message = await util.promisify(server.send.bind(server))({ - text: `This pad is now being edited:\n <${padUrl(padId)}>\n${emailFooter}`, + text: localizedEmail.text, from: `${fromName} <${fromEmail}>`, to: recipient, - subject: `Someone started editing ${padId}`, + subject: localizedEmail.subject, }); } catch (err) { console.error(err); @@ -106,11 +111,17 @@ const notifyEnd = async (padId) => { console.debug(`Emailing ${recipient} about a pad finished being updated`); let message; try { + const localizedEmail = getNotificationEmail({ + event: 'end', + locale: recipients[recipient].locale, + padId, + padUrl: padUrl(padId), + }); message = await util.promisify(server.send.bind(server))({ - text: `This pad is done being edited:\n <${padUrl(padId)}>\n${emailFooter}`, + text: localizedEmail.text, from: `${fromName} <${fromEmail}>`, to: recipient, - subject: `Someone finished editing ${padId}`, + subject: localizedEmail.subject, }); } catch (err) { console.error(err); From 5582af3c1a6f4e1bd670b94dc65a676b17530a4e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 10:20:45 +0000 Subject: [PATCH 3/3] fix: correct hungarian email locale string Agent-Logs-Url: https://github.com/ether/ep_email_notifications/sessions/f3033cd5-8920-4012-9ab7-06a01e394045 Co-authored-by: JohnMcLear <220864+JohnMcLear@users.noreply.github.com> --- locales/hu.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/hu.json b/locales/hu.json index cda1769..fa930c1 100644 --- a/locales/hu.json +++ b/locales/hu.json @@ -22,7 +22,7 @@ , "ep_email_notifications.emailNotificationEndSubject": "Valaki befejezte ennek a szerkesztését: {padId}" , "ep_email_notifications.emailNotificationEndBody": "Ennek a padnek a szerkesztése befejeződött:\n <{padUrl}>\n{footer}" , "ep_email_notifications.emailSubscriptionConfirmationSubject": "{padId} pad e-mailes feliratkozásának megerősítése" -, "ep_email_notifications.emailSubscriptionConfirmationBody": "Kattintson erre a hivatkozásra, hogy megerősítse a {padId} padre való feliratkozását\n{actionUrl}" +, "ep_email_notifications.emailSubscriptionConfirmationBody": "Kattintson erre a hivatkozásra, hogy megerősítse a {padId} padra való feliratkozását\n{actionUrl}" , "ep_email_notifications.emailUnsubscriptionConfirmationSubject": "{padId} pad e-mailes leiratkozásának megerősítése" , "ep_email_notifications.emailUnsubscriptionConfirmationBody": "Kattintson erre a hivatkozásra, hogy megerősítse a {padId} padról való leiratkozását\n{actionUrl}" }