const translation = require("./translation.js").translation; /** * This class repesents phrasebook, which is something like dictionary, * but not for words, for all phrases in app. It give functions which * could find and translates phrases. */ class phrasebook { /** * @var {Map} * This store phrases in flat notation. */ #phrases; /** * @var {?object} * This store object for nested object notation. */ #objects; /** * This create new phrasebook from phrases map, and optional object * for phrases in object notation. * * @param {Map} phrases - This contain phrases in flat notation. * @param {?object} objects - This contain phrases in object notation. */ constructor(phrases, objects = null) { if (!(phrases instanceof Map)) { throw new TypeError("Phrases must an map."); } if (objects !== null && typeof(objects) !== "object") { throw new TypeError("Objects must be null or object."); } this.#phrases = phrases; this.#objects = objects; } /** * This translate given phrase. When phrase is in the nested object * notation, then try to find phrase in objects. When not, try to find * phrase in the flat phrases. When could not find phrase, then return * not translated phrase. Content always is returned as translation * object, which could be also formated wich numbers, dates and * much more. * * @param {string} phrase - Phrase to translate. * @returns {translation} - Translated phrase. */ translate(phrase) { if (typeof(phrase) !== "string") { throw new TypeError("Phrase to translate must be an string."); } if (this.#is_nested(phrase)) { return this.#translate_nested(phrase); } return this.#translate_flat(phrase); } /** * This translate given phrase. When phrase is in the nested object * notation, then try to find phrase in objects. When not, try to find * phrase in the flat phrases. When could not find phrase, then return * not translated phrase. Content always is returned as translation * object, which could be also formated wich numbers, dates and * much more. * * @param {string} phrase - Phrase to translate. * @returns {translation} - Translated phrase. */ get(phrase) { return this.translate(phrase); } /** * Check that phrase is nested or not. * * @param {string} phrase - Phrase to check that is nested * @returns {bool} - True when nested, false when not */ #is_nested(phrase) { return phrase.indexOf(".") !== -1; } /** * This translate object notated phrase. * * @param {string} phrase - Phrase to translate. * @returns {translation} - Translated phrase. */ #translate_nested(phrase) { if (this.#objects === null) { return this.#translate_flat(phrase); } const parts = phrase.trim().split("."); let current = this.#objects; for (const count in parts) { const part = parts[count]; if (!(part in current)) { return new translation(phrase, false); } current = current[part]; } if (typeof(current) !== "string") { return new translation(phrase, false); } return new translation(current, true); } /** * This set phrasebook as default. That mean, it would add own translate * function to global scope, and create _({string}) function in the global * scope. It is useable to minify code with translations. It is not * avairable in the NodeJS, only in the browser. * * @returns {phrasebook} - Object itself to chain loading. */ set_as_default() { NODE: throw new Error("Could not create global function in NodeJS."); const translate = (content) => { return this.translate(content); }; window._ = translate; window.translate = translate; } /** * This translate flat phrase. * * @param {string} phrase - Phrase to translate. * @returns {translation} - Translated phrase. */ #translate_flat(phrase) { const prepared = phrasebook.prepare(phrase); const found = this.#phrases.has(prepared); const translated = found ? this.#phrases.get(prepared) : phrase; return new translation(translated, found); } /** * This prepars phrase, that mean replece all spaces with "_", trim * and also replace all big letters with lowwer. * * @param {string} content - Phrase to preapre. * @return {string} - Prepared phrase. */ static prepare(content) { if (typeof(content) !== "string") { throw new TypeError("Content to prepare must be an string."); } return content .trim() .replaceAll(" ", "_") .replaceAll(".", "_") .toLowerCase(); } } exports.phrasebook = phrasebook;