UNPKG

@apicart/vue-components

Version:

Apicart Vue.Js components for simple e-commerce platform development

206 lines (164 loc) 5.72 kB
// Dependencies import Apicart from '@apicart/core-sdk'; import Vue from 'vue'; import VueI18n from 'vue-i18n'; // Translations import fallbackTranslations from '@apicart/web-components-localization/localization/en.json'; Vue.use(VueI18n); class Translator { private _config: Record<string, any> = { actualLocale: null, fallbackLocale: 'en', localization: {}, // eslint-disable-next-line max-len localizationFilesUrl: 'https://cdn.jsdelivr.net/npm/@apicart/web-components-localization@__APICART_PACKAGES_VERSION__/localization', currencyFormats: { en: { currency: { style: 'currency', currency: 'EUR', currencyDisplay: 'symbol', code: 'EUR' } } } }; private _i18n: VueI18n = null; private _loadedLanguages: string[] = ['en']; private _processedLanguageFiles: Record<string, Promise<any>> = {}; private _downloadUrlsWithError: string[] = []; private _loadingLanguagePromise: Promise<any> = null; private _configurationPromises: Promise<any> = null; constructor() { this.configure(); Apicart.Utils.EventDispatcher.addListener( 'apicart-vueComponentsTranslator-configure', 'apicart:configure', () => { this.configure(); } ); } public async configure(config: Record<string, any> = null): Promise<void> { await this._configurationPromises; config = config || Apicart.getConfigParameter('vueComponentsTranslator') || {}; this._config = Apicart.Utils.Objects.merge(this._config, config); if (!this._config.actualLocale) { this._config.actualLocale = this.detectLocale(); } const configurationPromises = []; configurationPromises.push(await this.loadLocalizationFiles(this._config.actualLocale)); if (this._config.localization) { configurationPromises.push(this.addLocalization(this._config.localization)); } this._configurationPromises = Promise.all(configurationPromises); await this._configurationPromises; if (this._config.currencyFormats) { this.addNumberFormat(this._config.currencyFormats); } } public getActualCurrencyConfig(): Record<string, any> { const currencyConfig = typeof this.getI18n().numberFormats[this.getActualLocale()] === 'undefined' ? this.getI18n().numberFormats[this.getFallbackLocale()] : this.getI18n().numberFormats[this.getActualLocale()]; return typeof currencyConfig === 'undefined' ? {} : currencyConfig.currency; } public getActualLocale(): string { return this.getI18n().locale; } public getFallbackLocale(): string { return this.getI18n().fallbackLocale ? this.getI18n().fallbackLocale : this._config.fallbackLocale; } public getI18n(): VueI18n { if (!this._i18n) { const messages = Apicart.Storage.getItem('apicart-localization') || {}; messages[this._config.fallbackLocale] = fallbackTranslations; this._i18n = new VueI18n({ locale: this.detectLocale(), fallbackLocale: this._config.fallbackLocale, messages: messages, numberFormats: this._config.currencyFormats || this._config.defaultCurrencyFormats }); } return this._i18n; } public async loadLocalizationFiles(lang: string, url: string = null): Promise<string> { await this._loadingLanguagePromise; this._loadingLanguagePromise = this.downloadLocalizationFilesContent( lang, url || this._config.localizationFilesUrl + '/' + lang + '.json' ); await this._loadingLanguagePromise; return this.setI18nLanguage(lang); } public addLocalization(localization: Record<string, string>): void { Apicart.Utils.Loops.forEach(localization, (translationsOrUrl, locale) => { if (typeof translationsOrUrl === 'string') { this.loadLocalizationFiles(locale, translationsOrUrl); } else { this.mergeLocaleMessages(locale, translationsOrUrl); } }); } public addNumberFormat(numberFormat: Record<string, string>): void { Apicart.Utils.Loops.forEach(numberFormat, (numberFormat, locale: string) => { this.getI18n().mergeNumberFormat(locale, numberFormat); }); } private async downloadLocalizationFilesContent(locale: string, url: string): Promise<boolean> { if (this._loadedLanguages.includes(locale)) { return true; } if (this._downloadUrlsWithError.includes(url)) { return false; } if ( ! (url in this._processedLanguageFiles)) { this._processedLanguageFiles[url] = Apicart.Utils.Ajax.get(url); } const response = await this._processedLanguageFiles[url]; const loaded = response && Apicart.Utils.Objects.isObject(response.data); if (loaded) { const localeObject = {}; localeObject[locale] = response.data; Apicart.Storage.updateItem('apicart-localization', localeObject); this.mergeLocaleMessages(locale, response.data); } else { Apicart.Utils.Console.error('Localization file "' + url + '" could not be loaded.'); this._downloadUrlsWithError.push(url); } this._loadedLanguages.push(locale); return loaded; } private setI18nLanguage(lang: string): string { this.getI18n().locale = lang; if (this.isInBrowser()) { document.querySelector('html').setAttribute('lang', lang); } return lang; } private isInBrowser(): boolean { return typeof window !== 'undefined' && typeof document !== 'undefined'; } private detectLocale(): string { if (!this.isInBrowser()) { return this._config.fallbackLocale; } const documentLang = document.documentElement.getAttribute('lang'); return documentLang ? documentLang : navigator.language || (<any>window).navigator.userLanguage; } private mergeLocaleMessages(locale: string, messages: Record<string, any>): void { this.getI18n().mergeLocaleMessage(locale, messages); Apicart.Utils.EventDispatcher.dispatchEvent('apicart:translations:updated'); } } export default new Translator();