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;