UNPKG

@jupri-lab/i18n-core

Version:

Speak Easy. Effortless Internationalization for Your JavaScript Apps

151 lines (146 loc) 5.01 kB
class EventManager { constructor() { this.listeners = {}; } on(eventName, callback) { if (!this.listeners[eventName]) { this.listeners[eventName] = []; } this.listeners[eventName].push(callback); } off(eventName, callback) { const eventListeners = this.listeners[eventName]; if (eventListeners.length) { const index = eventListeners.indexOf(callback); if (index !== -1) { eventListeners.splice(index, 1); } } } trigger(eventName, ...args) { if (this.listeners[eventName]) { for (const listener of this.listeners[eventName]) { listener(...args); } } } } class LanguageManager { constructor(args) { this.queryParam = "lang"; this.enableQueryParams = false; this.currentLanguage = args.initialLanguage; this.languages = args.languages; this.enableQueryParams = args.enableQueryParams; this.queryParam = args.queryParam; } getLanguages() { return this.languages; } getCurrentLanguage() { if (this.enableQueryParams) { const urlParams = new URLSearchParams(window.location.search); const param = urlParams.get(this.queryParam); if (param) { this.currentLanguage = param; } } return this.currentLanguage; } changeLanguage(language, eventManager) { if (this.currentLanguage !== language) { this.currentLanguage = language; if (this.enableQueryParams) this.appendQueryParams(this.queryParam, language); eventManager.trigger("language_changed"); } } appendQueryParams(key, value) { const newURL = new URL(window.location.href); newURL.searchParams.set(key, value); window.history.replaceState({}, "", newURL.href); } } class TranslationManager { constructor(resources) { this.resources = resources; } translate(params) { try { const currentTranslation = this.resources[params.currentLanguage]; if (currentTranslation) { const parts = params.identifier.split("."); let currentObject = currentTranslation; for (const part of parts) { currentObject = currentObject[part]; } if (params.interpolation) { return this.interpolate(currentObject, params.interpolation, params.escapeHTML); } if (typeof params.escapeHTML === "boolean" && params.escapeHTML) return this.escapeHTMLTags(currentObject); return currentObject; } } catch (_) { throw new Error("i18n resource is not initialized"); } } interpolate(string, values, escapeHTML = true) { return string.replace(/\[(.*?)\]/g, (match, key) => { const value = values[key.trim()] || match; return escapeHTML ? this.escapeHTMLTags(value) : value; }); } escapeHTMLTags(string) { return string.replace(/[&<>"'`=/]/g, (match) => { const escapeMap = { // eslint-disable-next-line quotes '"': "&quot;", "&": "&amp;", "'": "&#39;", "/": "&#47;", "<": "&lt;", "=": "&#61;", ">": "&gt;", "`": "&#96;", }; return escapeMap[match]; }); } } class i18n { constructor(configs) { const { enableQueryParams = false, queryParam = "lang" } = configs; this.eventManager = new EventManager(); this.languageManager = new LanguageManager({ enableQueryParams, initialLanguage: configs.languages[0], languages: configs.languages, queryParam, }); this.translationManager = new TranslationManager(configs.resources); } getCurrentLanguage() { return this.languageManager.getCurrentLanguage(); } getChangeLanguageHandler(language) { if (language && !this.languageManager.getLanguages().includes(language)) throw new Error("Language is not recognized in the supported languages"); if (language) this.languageManager.changeLanguage(language, this.eventManager); } translate(identifier, data = { escapeHTML: true }) { const { escapeHTML = true, interpolation } = data; return this.translationManager.translate({ currentLanguage: this.languageManager.getCurrentLanguage(), escapeHTML, identifier, interpolation, }); } on(eventName, callback) { this.eventManager.on(eventName, callback); } } export { i18n as default };