@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
173 lines (151 loc) • 4.19 kB
JavaScript
/**
* 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);
}
}