Further work on localization
This commit is contained in:
parent
fa451fc8da
commit
cb1fc5b28d
35 changed files with 430 additions and 2796 deletions
|
@ -67,7 +67,7 @@ async function _sendTransactionalMail(transport, mail, template) {
|
|||
}
|
||||
mail.headers['X-Sending-Zone'] = 'transactional';
|
||||
|
||||
const htmlRenderer = await tools.getTemplate(template.html);
|
||||
const htmlRenderer = await tools.getTemplate(template.html, template.locale);
|
||||
|
||||
if (htmlRenderer) {
|
||||
mail.html = htmlRenderer(template.data || {});
|
||||
|
@ -79,7 +79,7 @@ async function _sendTransactionalMail(transport, mail, template) {
|
|||
mail.html = preparedHtml;
|
||||
}
|
||||
|
||||
const textRenderer = await tools.getTemplate(template.text);
|
||||
const textRenderer = await tools.getTemplate(template.text, template.locale);
|
||||
|
||||
if (textRenderer) {
|
||||
mail.text = textRenderer(template.data || {});
|
||||
|
|
|
@ -20,49 +20,49 @@ module.exports = {
|
|||
sendUnsubscriptionConfirmed
|
||||
};
|
||||
|
||||
async function sendSubscriptionConfirmed(lang, list, email, subscription) {
|
||||
async function sendSubscriptionConfirmed(locale, list, email, subscription) {
|
||||
const relativeUrls = {
|
||||
preferencesUrl: '/subscription/' + list.cid + '/manage/' + subscription.cid,
|
||||
unsubscribeUrl: '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid
|
||||
};
|
||||
|
||||
await _sendMail(list, email, 'subscription_confirmed', lang, tMark('subscriptionconfirmed'), relativeUrls, subscription);
|
||||
await _sendMail(list, email, 'subscription_confirmed', locale, tMark('subscriptionconfirmed'), relativeUrls, subscription);
|
||||
}
|
||||
|
||||
async function sendAlreadySubscribed(lang, list, email, subscription) {
|
||||
async function sendAlreadySubscribed(locale, list, email, subscription) {
|
||||
const relativeUrls = {
|
||||
preferencesUrl: '/subscription/' + list.cid + '/manage/' + subscription.cid,
|
||||
unsubscribeUrl: '/subscription/' + list.cid + '/unsubscribe/' + subscription.cid
|
||||
};
|
||||
await _sendMail(list, email, 'already_subscribed', lang, tMark('listEmailAddressAlreadyRegistered'), relativeUrls, subscription);
|
||||
await _sendMail(list, email, 'already_subscribed', locale, tMark('listEmailAddressAlreadyRegistered'), relativeUrls, subscription);
|
||||
}
|
||||
|
||||
async function sendConfirmAddressChange(lang, list, email, cid, subscription) {
|
||||
async function sendConfirmAddressChange(locale, list, email, cid, subscription) {
|
||||
const relativeUrls = {
|
||||
confirmUrl: '/subscription/confirm/change-address/' + cid
|
||||
};
|
||||
await _sendMail(list, email, 'confirm_address_change', lang, tMark('listPleaseConfirmEmailChangeIn'), relativeUrls, subscription);
|
||||
await _sendMail(list, email, 'confirm_address_change', locale, tMark('listPleaseConfirmEmailChangeIn'), relativeUrls, subscription);
|
||||
}
|
||||
|
||||
async function sendConfirmSubscription(lang, list, email, cid, subscription) {
|
||||
async function sendConfirmSubscription(locale, list, email, cid, subscription) {
|
||||
const relativeUrls = {
|
||||
confirmUrl: '/subscription/confirm/subscribe/' + cid
|
||||
};
|
||||
await _sendMail(list, email, 'confirm_subscription', lang, tMark('pleaseConfirmSubscription'), relativeUrls, subscription);
|
||||
await _sendMail(list, email, 'confirm_subscription', locale, tMark('pleaseConfirmSubscription'), relativeUrls, subscription);
|
||||
}
|
||||
|
||||
async function sendConfirmUnsubscription(lang, list, email, cid, subscription) {
|
||||
async function sendConfirmUnsubscription(locale, list, email, cid, subscription) {
|
||||
const relativeUrls = {
|
||||
confirmUrl: '/subscription/confirm/unsubscribe/' + cid
|
||||
};
|
||||
await _sendMail(list, email, 'confirm_unsubscription', lang, tMark('listPleaseConfirmUnsubscription'), relativeUrls, subscription);
|
||||
await _sendMail(list, email, 'confirm_unsubscription', locale, tMark('listPleaseConfirmUnsubscription'), relativeUrls, subscription);
|
||||
}
|
||||
|
||||
async function sendUnsubscriptionConfirmed(lang, list, email, subscription) {
|
||||
async function sendUnsubscriptionConfirmed(locale, list, email, subscription) {
|
||||
const relativeUrls = {
|
||||
subscribeUrl: '/subscription/' + list.cid + '?cid=' + subscription.cid
|
||||
};
|
||||
await _sendMail(list, email, 'unsubscription_confirmed', lang, tMark('listUnsubscriptionConfirmed'), relativeUrls, subscription);
|
||||
await _sendMail(list, email, 'unsubscription_confirmed', locale, tMark('listUnsubscriptionConfirmed'), relativeUrls, subscription);
|
||||
}
|
||||
|
||||
function getDisplayName(flds, subscription) {
|
||||
|
@ -95,7 +95,7 @@ function getDisplayName(flds, subscription) {
|
|||
}
|
||||
}
|
||||
|
||||
async function _sendMail(list, email, template, language, subjectKey, relativeUrls, subscription) {
|
||||
async function _sendMail(list, email, template, locale, subjectKey, relativeUrls, subscription) {
|
||||
const flds = await fields.list(contextHelpers.getAdminContext(), list.id);
|
||||
|
||||
const encryptionKeys = [];
|
||||
|
@ -114,7 +114,7 @@ async function _sendMail(list, email, template, language, subjectKey, relativeUr
|
|||
};
|
||||
|
||||
for (let relativeUrlKey in relativeUrls) {
|
||||
data[relativeUrlKey] = getPublicUrl(relativeUrls[relativeUrlKey], {language});
|
||||
data[relativeUrlKey] = getPublicUrl(relativeUrls[relativeUrlKey], {locale});
|
||||
}
|
||||
|
||||
const fsTemplate = template.replace(/_/g, '-');
|
||||
|
@ -148,11 +148,12 @@ async function _sendMail(list, email, template, language, subjectKey, relativeUr
|
|||
name: getDisplayName(flds, subscription),
|
||||
address: email
|
||||
},
|
||||
subject: tUI(subjectKey, language, { list: list.name }),
|
||||
subject: tUI(subjectKey, locale, { list: list.name }),
|
||||
encryptionKeys
|
||||
}, {
|
||||
html,
|
||||
text,
|
||||
locale,
|
||||
data
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -19,17 +19,34 @@ const he = require('he');
|
|||
const fs = require('fs-extra');
|
||||
|
||||
const { JSDOM } = require('jsdom');
|
||||
const { tUI, tLog } = require('./translate');
|
||||
const { tUI, tLog, getLangCodeFromExpressLocale } = require('./translate');
|
||||
|
||||
|
||||
const templates = new Map();
|
||||
|
||||
async function getTemplate(template) {
|
||||
async function getLocalizedFile(basePath, fileName, language) {
|
||||
try {
|
||||
const locFn = path.join(basePath, language, fileName);
|
||||
const stats = await fs.stat(locFn);
|
||||
|
||||
if (stats.isFile()) {
|
||||
return locFn;
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return path.join(basePath, fileName)
|
||||
}
|
||||
|
||||
async function getTemplate(template, locale) {
|
||||
if (!template) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const key = (typeof template === 'object') ? hasher.hash(template) : template;
|
||||
const key = getLangCodeFromExpressLocale(locale) + ':' + ((typeof template === 'object') ? hasher.hash(template) : template);
|
||||
|
||||
if (templates.has(key)) {
|
||||
return templates.get(key);
|
||||
|
@ -37,9 +54,9 @@ async function getTemplate(template) {
|
|||
|
||||
let source;
|
||||
if (typeof template === 'object') {
|
||||
source = await mergeTemplateIntoLayout(template.template, template.layout);
|
||||
source = await mergeTemplateIntoLayout(template.template, template.layout, locale);
|
||||
} else {
|
||||
source = await fs.readFile(path.join(__dirname, '..', 'views', template), 'utf-8');
|
||||
source = await fs.readFile(await getLocalizedFile(path.join(__dirname, '..', 'views'), template, getLangCodeFromExpressLocale(locale)), 'utf-8');
|
||||
}
|
||||
|
||||
if (template.type === 'mjml') {
|
||||
|
@ -53,17 +70,35 @@ async function getTemplate(template) {
|
|||
}
|
||||
|
||||
const renderer = hbs.handlebars.compile(source);
|
||||
templates.set(key, renderer);
|
||||
|
||||
return renderer;
|
||||
const localizedRenderer = (data, options) => {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (!options.helpers) {
|
||||
options.helpers = {};
|
||||
}
|
||||
|
||||
options.helpers.translate = function (opts) { // eslint-disable-line prefer-arrow-callback
|
||||
const result = tUI(opts.fn(this), locale, opts.hash); // eslint-disable-line no-invalid-this
|
||||
return new hbs.handlebars.SafeString(result);
|
||||
};
|
||||
|
||||
return renderer(data, options);
|
||||
};
|
||||
|
||||
templates.set(key, localizedRenderer);
|
||||
|
||||
return localizedRenderer;
|
||||
}
|
||||
|
||||
|
||||
async function mergeTemplateIntoLayout(template, layout) {
|
||||
async function mergeTemplateIntoLayout(template, layout, locale) {
|
||||
layout = layout || '{{{body}}}';
|
||||
|
||||
async function readFile(relPath) {
|
||||
return await fs.readFile(path.join(__dirname, '..', 'views', relPath), 'utf-8');
|
||||
return await fs.readFile(await getLocalizedFile(path.join(__dirname, '..', 'views'), relPath, getLangCodeFromExpressLocale(locale)), 'utf-8');
|
||||
}
|
||||
|
||||
// Please dont end your custom messages with .hbs ...
|
||||
|
@ -184,7 +219,6 @@ function getMessageLinks(campaign, list, subscription) {
|
|||
module.exports = {
|
||||
validateEmail,
|
||||
validateEmailGetMessage,
|
||||
mergeTemplateIntoLayout,
|
||||
getTemplate,
|
||||
prepareHtml,
|
||||
getMessageLinks,
|
||||
|
|
|
@ -4,25 +4,24 @@ const config = require('config');
|
|||
const i18n = require("i18next");
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const {convertToFake, langCodes} = require('../../shared/langs');
|
||||
const {convertToFake, getLang} = require('../../shared/langs');
|
||||
|
||||
const resourcesCommon = {};
|
||||
|
||||
function loadLanguage(shortCode) {
|
||||
resourcesCommon[shortCode] = {
|
||||
common: JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'locales', shortCode, 'common.json')))
|
||||
function loadLanguage(longCode) {
|
||||
resourcesCommon[longCode] = {
|
||||
common: JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'locales', longCode, 'common.json')))
|
||||
};
|
||||
}
|
||||
|
||||
loadLanguage('en');
|
||||
loadLanguage('es');
|
||||
resourcesCommon.fake = convertToFake(resourcesCommon.en);
|
||||
loadLanguage('en-US');
|
||||
resourcesCommon['fk-FK'] = convertToFake(resourcesCommon['en-US']);
|
||||
|
||||
const resources = {};
|
||||
for (const lng of config.enabledLanguages) {
|
||||
const shortCode = langCodes[lng].shortCode;
|
||||
resources[shortCode] = {
|
||||
common: resourcesCommon[shortCode]
|
||||
const langDesc = getLang(lng);
|
||||
resources[langDesc.longCode] = {
|
||||
common: resourcesCommon[langDesc.longCode]
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -34,6 +33,9 @@ i18n
|
|||
fallbackLng: config.defaultLanguage,
|
||||
defaultNS: 'common',
|
||||
|
||||
whitelist: config.enabledLanguages,
|
||||
load: 'currentOnly',
|
||||
|
||||
debug: false
|
||||
})
|
||||
|
||||
|
@ -47,18 +49,29 @@ function tLog(key, args) {
|
|||
return JSON.stringify([key, args]);
|
||||
}
|
||||
|
||||
function tUI(key, lang, args) {
|
||||
function tUI(key, locale, args) {
|
||||
if (!args) {
|
||||
args = {};
|
||||
}
|
||||
|
||||
return i18n.t(key, { ...args, lng: lang });
|
||||
return i18n.t(key, { ...args, lng: getLangCodeFromExpressLocale(locale) });
|
||||
}
|
||||
|
||||
function tMark(key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
function getLangCodeFromExpressLocale(locale) {
|
||||
const longCode = locale.toString().replace('_', '-');
|
||||
if (longCode in resources) {
|
||||
return longCode;
|
||||
} else {
|
||||
return config.defaultLanguage
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.tLog = tLog;
|
||||
module.exports.tUI = tUI;
|
||||
module.exports.tMark = tMark;
|
||||
module.exports.tMark = tMark;
|
||||
module.exports.getLangCodeFromExpressLocale = getLangCodeFromExpressLocale;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
const config = require('config');
|
||||
const urllib = require('url');
|
||||
const {anonymousRestrictedAccessToken} = require('../../shared/urls');
|
||||
const {getLangCodeFromExpressLocale} = require('./translate');
|
||||
|
||||
function getTrustedUrlBase() {
|
||||
return urllib.resolve(config.www.trustedUrlBase, '');
|
||||
|
@ -19,8 +20,8 @@ function getPublicUrlBase() {
|
|||
function _getUrl(urlBase, path, opts) {
|
||||
const url = new URL(path || '', urlBase);
|
||||
|
||||
if (opts && opts.language) {
|
||||
url.searchParams.append('lang', opts.language)
|
||||
if (opts && opts.locale) {
|
||||
url.searchParams.append('locale', getLangCodeFromExpressLocale(opts.locale));
|
||||
}
|
||||
|
||||
return url.toString();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue