UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

173 lines (151 loc) 4.19 kB
/** * Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved. * Node module: @schukai/monster * * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3). * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html * * For those who do not wish to adhere to the AGPLv3, a commercial license is available. * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms. * For more information about purchasing a commercial license, please contact Volker Schukai. * * SPDX-License-Identifier: AGPL-3.0 */ import { internalSymbol } from "../../constants.mjs"; import { extend } from "../../data/extend.mjs"; import { getDocument } from "../../dom/util.mjs"; import { isString } from "../../types/is.mjs"; import { validateObject, validateString } from "../../types/validate.mjs"; import { parseLocale } from "../locale.mjs"; import { Provider } from "../provider.mjs"; import { Translations } from "../translations.mjs"; export { Embed }; /** * The Embed provider retrieves a JSON file from the given Script Tag. * * @externalExample ../../../example/i18n/providers/embed.mjs * @license AGPLv3 * @since 1.13.0 * @copyright Volker Schukai * @see {@link https://datatracker.ietf.org/doc/html/rfc3066} */ class Embed extends Provider { /** * ```html * <script id="translations" type="application/json"> * { * "hello": "Hallo" * } * </script> * ``` * * * ```javascript * new Embed('translations') * ``` * * @param {HTMLElement|string} elementOrId * @param {Object} options */ constructor(elementOrId, options) { super(options); if (options === undefined) { options = {}; } if (elementOrId instanceof HTMLElement) { /** * @property {HTMLElement|string} */ this.translateElement = elementOrId; } else { /** * @property {HTMLElement|string} */ this.translateElement = getDocument().getElementById( validateString(elementOrId), ); } /** * @private * @property {Object} options */ this[internalSymbol] = extend( {}, super.defaults, this.defaults, validateObject(options), ); } /** * Defaults * * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API} */ get defaults() { return extend({}, super.defaults); } /** * * @param {Locale|string} locale * @return {Promise} */ getTranslations(locale) { if (isString(locale)) { locale = parseLocale(locale); } return new Promise((resolve, reject) => { if (this.translateElement === null) { reject(new Error("Text not found")); return; } if (!(this.translateElement instanceof HTMLScriptElement)) { reject(new Error("Element is not a script tag")); return; } if (this.translateElement.type !== "application/json") { reject( new Error("Element is not a script tag with type application/json"), ); return; } let translations = null; try { translations = JSON.parse(this.translateElement.innerHTML.trim()); } catch (e) { reject(e); return; } if (translations === null) { reject(new Error("Translations not found or invalid")); return; } const t = new Translations(locale); t.assignTranslations(translations); resolve(t); }); } /** * Initializes the translations for the current document. * * `script[data-monster-role=translations]` is searched for and the translations are assigned to the element. * * @param element * @returns {Promise<Awaited<*[]>>|Promise<Awaited<unknown>[]>} */ static assignTranslationsToElement(element) { const d = getDocument(); if (!(element instanceof HTMLElement)) { element = d.querySelector("body"); } const list = d.querySelectorAll("script[data-monster-role=translations]"); if (list === null) { return Promise.resolve([]); } const promises = []; list.forEach((translationElement) => { const p = new Embed(translationElement, {}); promises.push(p.assignToElement(undefined, element)); }); return Promise.all(promises); } }