144 lines
3.8 KiB
JavaScript
144 lines
3.8 KiB
JavaScript
const Vue = require('vue');
|
|
const VueI18n = require('vue-i18n');
|
|
const renderer = require('vue-server-renderer').createRenderer();
|
|
Vue.use(VueI18n);
|
|
|
|
const fs = require('fs');
|
|
const yaml = require('js-yaml');
|
|
const juice = require('juice');
|
|
const path = require('path');
|
|
const config = require('./config');
|
|
|
|
class Component {
|
|
constructor(name) {
|
|
this.name = name;
|
|
}
|
|
|
|
get path() {
|
|
return `./components/${this.name}`;
|
|
}
|
|
|
|
get template() {
|
|
const templatePath = `${this.path}/${this.name}.html`;
|
|
const fullPath = path.resolve(__dirname, templatePath);
|
|
|
|
return fs.readFileSync(fullPath, 'utf8');
|
|
}
|
|
|
|
get locale() {
|
|
if (!this._locale)
|
|
this._locale = this.getLocales();
|
|
|
|
return this._locale;
|
|
}
|
|
|
|
getLocales() {
|
|
const mergedLocales = {messages: {}};
|
|
const localePath = path.resolve(__dirname, `${this.path}/locale`);
|
|
|
|
if (!fs.existsSync(localePath))
|
|
return mergedLocales;
|
|
|
|
const localeDir = fs.readdirSync(localePath);
|
|
for (const locale of localeDir) {
|
|
const fullPath = path.join(localePath, '/', locale);
|
|
const yamlLocale = fs.readFileSync(fullPath, 'utf8');
|
|
const jsonLocale = yaml.safeLoad(yamlLocale);
|
|
const localeName = locale.replace('.yml', '');
|
|
|
|
mergedLocales.messages[localeName] = jsonLocale;
|
|
}
|
|
|
|
return mergedLocales;
|
|
}
|
|
|
|
async getUserLocale() {
|
|
let lang = this.args.lang;
|
|
|
|
// Fetches user locale from mixing method getLocale()
|
|
if (this.args.recipientId) {
|
|
const component = await this.component();
|
|
lang = await component.getLocale(this.args.recipientId);
|
|
}
|
|
|
|
const messages = this.locale.messages;
|
|
const userTranslations = messages[lang];
|
|
|
|
if (!userTranslations) {
|
|
const fallbackLang = config.i18n.fallbackLocale;
|
|
|
|
return messages[fallbackLang];
|
|
}
|
|
|
|
return userTranslations;
|
|
}
|
|
|
|
get stylesheet() {
|
|
let mergedStyles = '';
|
|
const stylePath = path.resolve(__dirname, `${this.path}/assets/css`);
|
|
|
|
if (!fs.existsSync(stylePath))
|
|
return mergedStyles;
|
|
|
|
return require(`${stylePath}/import`);
|
|
}
|
|
|
|
get attachments() {
|
|
const attachmentsPath = `${this.path}/attachments.json`;
|
|
const fullPath = path.resolve(__dirname, attachmentsPath);
|
|
|
|
if (!fs.existsSync(fullPath))
|
|
return [];
|
|
|
|
return require(fullPath);
|
|
}
|
|
|
|
build() {
|
|
const fullPath = path.resolve(__dirname, this.path);
|
|
if (!fs.existsSync(fullPath))
|
|
throw new Error(`Template "${this.name}" not found`);
|
|
|
|
const component = require(`${this.path}/${this.name}`);
|
|
component.i18n = this.locale;
|
|
component.attachments = this.attachments;
|
|
component.template = juice.inlineContent(this.template, this.stylesheet, {
|
|
inlinePseudoElements: true
|
|
});
|
|
const tplPath = this.path;
|
|
if (!component.computed) component.computed = {};
|
|
component.computed.path = function() {
|
|
return tplPath;
|
|
};
|
|
|
|
return component;
|
|
}
|
|
|
|
component() {
|
|
if (this._component)
|
|
return this._component;
|
|
|
|
const component = this.build();
|
|
const i18n = new VueI18n(config.i18n);
|
|
const props = {...this.args};
|
|
this._component = new Vue({
|
|
i18n: i18n,
|
|
render: h => h(component, {
|
|
props: props
|
|
})
|
|
});
|
|
|
|
return this._component;
|
|
}
|
|
|
|
/**
|
|
* @return {Promise} Rendered component
|
|
*/
|
|
async render() {
|
|
return renderer.renderToString(
|
|
this.component()
|
|
);
|
|
}
|
|
}
|
|
|
|
module.exports = Component;
|