/** * Copyright schukai GmbH and contributors 2023. All Rights Reserved. * Node module: @schukai/monster * This file is licensed under the AGPLv3 License. * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html */ import { instanceSymbol, internalSymbol } from "../constants.mjs"; import { extend } from "../data/extend.mjs"; import { Formatter as TextFormatter } from "../text/formatter.mjs"; import { validateInstance, validateString } from "../types/validate.mjs"; import { Translations } from "./translations.mjs"; export { Formatter }; /** * @private * @type {symbol} */ const internalTranslationSymbol = Symbol("internalTranslation"); /** * The Formatter extends the Text.Formatter with the possibility to replace the key by a translation. * * @externalExample ../../example/i18n/formatter.mjs * @license AGPLv3 * @since 1.26.0 * @copyright schukai GmbH * @memberOf Monster.I18n */ class Formatter extends TextFormatter { /** * Default values for the markers are `${` and `}` * * @param {object} object * @throws {TypeError} value is not a object */ constructor(object, translation, options) { super(object, options); this[internalTranslationSymbol] = validateInstance(translation, Translations); } /** * This method is called by the `instanceof` operator. * @returns {symbol} * @since 3.27.0 */ static get [instanceSymbol]() { return Symbol.for("@schukai/monster/i18n/formatter@@instance"); } /** * @property {object} marker * @property {array} marker.open=["i18n{","${"] * @property {array} marker.close=["${"] * @property {object} parameter * @property {string} parameter.delimiter="::" * @property {string} parameter.assignment="=" * @property {object} callbacks * @property {function} callbacks.i18n=()=>{} */ get defaults() { const self = this; return extend({}, super.defaults, { callbacks: { i18n: (value) => { return self[internalTranslationSymbol].getText(validateString(value)); }, }, marker: { open: ["i18n{", "${"], close: ["}"], }, }); } /** * * @param {string} text * @return {string} * @throws {TypeError} value is not a string * @throws {Error} too deep nesting * @throws {Error} key not found * @throws {Error} the closing marker is missing */ format(text) { validateString(text); const openMarker = this[internalSymbol]["marker"]["open"]?.[0]; const closeMarker = this[internalSymbol]["marker"]["close"]?.[0]; if (text.indexOf(openMarker) === 0) { text = text.substring(openMarker.length); if (text.indexOf(closeMarker) === text.length - closeMarker.length) { text = text.substring(0, text.length - closeMarker.length); } else { throw new Error("the closing marker is missing"); } } const parts = validateString(text).split("::"); const translationKey = parts.shift().trim(); // key value delimiter const parameter = parts.join("::").trim(); let assembledText = `${openMarker}static:${translationKey} | call:i18n`; if (parameter.length > 0) { assembledText += `::${parameter}`; } assembledText += closeMarker; return super.format(assembledText); } }