/**
* @summary i18n-mixin
* @version 3.0.0
* @since 1.0.0
* @author Arian Khosravi<arian.khosravi@aofl.com>
*/
import {html} from 'lit-html';
import md5 from 'tiny-js-md5';
import {I18n} from '@aofl/i18n';
/**
* Mixin function for I18nMixin class
*
* @memberof module:@aofl/i18n-mixin
* @param {LitElement} superClass
*/
export default (superClass) => {
/**
* @memberof module:@aofl/i18n-mixin
* @extends {superClass}
*/
class I18nMixin extends superClass {
/**
*
*/
constructor(...args) {
super(...args);
this.translationMap = {};
this.i18n = new I18n();
this.observer = this.langListener();
}
/**
* @type {Object}
*/
static get properties() {
return {
lang: {type: String}
};
}
set translations(value) {
this.i18n.translations = value;
}
get translations() {
return this.i18n.translations;
}
/**
* Listens for html lang mutations
* @return {MutationObserver}
*/
langListener() {
const observer = new MutationObserver((mutationList) => {
if (this.getAttribute('lang')) { return; }
this.i18n.lang = mutationList[0].target.lang;
this.requestUpdate();
});
observer.observe(document.documentElement, {attributes: true});
return observer;
}
/**
* Check if templateParts matches previously cached template and
* prevent unnecessary render updates
*
* @param {*} id
* @param {*} templateParts
* @return {templateParts}
*/
getCachedTemplate(id, templateParts) {
if (typeof this.translationMap[id] === 'undefined' ||
this.translationMap[id].strings[0] !== templateParts.strings[0]) {
this.translationMap[id] = templateParts;
}
return this.translationMap[id];
}
/**
* Language translation function.
*
* @param {String} id
* @param {String} str
* @return {String}
*/
async __(id, str) {
const translated = await this.i18n.__(id, str);
const templateParts = html([translated]);
return this.getCachedTemplate(id, templateParts);
}
/**
* Replace function. When invoked it will replace %r(number)% with the number matching the index
* of the arguments passed to the _r function.
*
* @param {String} str
* @param {*} args
* @return {String}
*/
async _r(str, ...args) {
const translated = await this.i18n._r(str, ...args);
const templateParts = html([translated]);
const id = md5(translated);
return this.getCachedTemplate(id, templateParts);
}
/**
* Conditional translation function. When invoked it finds the correct string based on the labels
* specified in ...args.
*
* @param {*} id
* @param {*} str
* @param {*} args
* @return {String}
*/
async _c(id, str, ...args) {
const translated = await this.i18n._c(id, str, ...args);
const templateParts = html([translated]);
return this.getCachedTemplate(id, templateParts);
}
/**
* Sets initial lang
*/
connectedCallback() {
this.i18n.lang = this.getAttribute('lang') || document.documentElement.getAttribute('lang');
super.connectedCallback();
}
/**
* Listen for component's lang attribute mutations
*
* @param {String} name
* @param {String} oldValue
* @param {String} newValue
* @return {void}
*/
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'lang') {
if (!newValue) {
this.i18n.lang = document.documentElement.lang;
} else {
this.i18n.lang = newValue;
}
this.requestUpdate();
}
super.attributeChangedCallback(name, oldValue, newValue);
}
/**
*
* @param {Object} templates
* @param {*} args
* @return {Object}
*/
render(templates, ...args) {
let template = templates.default;
if (typeof templates[this.i18n.lang] !== 'undefined') {
template = templates[this.i18n.lang];
}
return super.render(template.template, template.styles, ...args);
}
/**
*
* @param {*} args
*/
disconnectedCallback(...args) {
super.disconnectedCallback(...args);
this.observer.disconnect();
}
}
return I18nMixin;
};