Skip to content
Snippets Groups Projects
Select Git revision
  • 97963b1d59a6ff62d94f225989eb548279e75b76
  • master default protected
  • 1.31
  • 4.34.1
  • 4.34.0
  • 4.33.1
  • 4.33.0
  • 4.32.2
  • 4.32.1
  • 4.32.0
  • 4.31.0
  • 4.30.1
  • 4.30.0
  • 4.29.1
  • 4.29.0
  • 4.28.0
  • 4.27.0
  • 4.26.0
  • 4.25.5
  • 4.25.4
  • 4.25.3
  • 4.25.2
  • 4.25.1
23 results

formatter.mjs

Blame
  • formatter.mjs 3.49 KiB
    /**
     * 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);
        }
    }