{ "version": 3, "sources": ["../source/translation.js", "../source/phrasebook.js", "../source/loader.js", "../source/languages.js", "../source/selector.js", "../source/autotranslate.js", "../source/preferences.js", "../source/core.js"], "sourcesContent": ["class translation {\n /**\n * @var {string}\n * This is translated content.\n */\n #content;\n \n /**\n * @var {bool}\n * This is true, when content is translated from dict, and false\n * when could not being found.\n */\n #translated;\n\n /**\n * This create new translation. Translation store content of the \n * translation, make avairable to format translated phrase and also\n * store that translation was found in the phrasebook.\n * \n * @param {string} content - Content of the translation.\n * @param {bool} translated - True when translation could be found.\n */\n constructor(content, translated = true) {\n if (typeof(content) !== \"string\") {\n throw new TypeError(\"Translated content must be string.\");\n }\n\n if (typeof(translated) !== \"boolean\") {\n throw new TypeError(\"Result of translation must be boolean.\");\n }\n\n this.#content = content;\n this.#translated = translated;\n\n Object.freeze(this);\n }\n\n /**\n * This convert transiation to string.\n * \n * @returns {string} - Content of the translation.\n */\n toString() {\n return this.#content;\n }\n\n /**\n * @returns {string} - Content of the translation.\n */\n get text() {\n return this.#content;\n }\n\n /**\n * @returns {bool} - True when translation was found, false when not.\n */\n get valid() {\n return this.translated;\n }\n\n /**\n * This would format ready translation, with numbers, dats, and \n * other content, which could not being statically places into\n * translation. To use it, place name of content object key into\n * \"#{}\" in translation. \n * \n * @example ```\n * Translation: \"I have more than #{how_many} apples!\"\n * Object: { how_many: 10 }\n * Result: \"I have more than 10 apples!\"\n * ```\n * \n * @param {string} content \n * @returns {string}\n */\n format(content) {\n if (typeof(content) !== \"object\") {\n throw new TypeError(\"Content to format from must be object.\");\n }\n\n if (!this.#translated) {\n return this.#content;\n }\n\n return this.#parse_format(content);\n }\n\n /**\n * This infill prepared translation with data from content \n * object.\n * \n * @see format\n * \n * @param {object} content - Content to load data from. \n * @returns {string} - Formater translation.\n */\n #parse_format(content) {\n let parts = this.#content.split(\"#{\");\n let result = parts[0];\n\n for (let count = 1; count < parts.length; ++count) {\n const part = parts[count];\n const splited = part.split(\"}\");\n\n if (splited.length === 1) {\n return result + splited[0];\n }\n\n const name = splited.splice(0, 1)[0].trim();\n const rest = splited.join(\"}\");\n\n if (!(name in content)) {\n DEBUG: throw new RangeError(\n \"Could not find \\\"\" + name + \"\\\".\"\n );\n \n result += rest;\n continue;\n }\n\n result += content[name] + rest;\n }\n\n return result;\n }\n}\n\nexports.translation = translation;", "const translation = require(\"./translation.js\").translation;\n\n/**\n * This class repesents phrasebook, which is something like dictionary,\n * but not for words, for all phrases in app. It give functions which \n * could find and translates phrases.\n */\nclass phrasebook {\n \n /**\n * @var {Map}\n * This store phrases in flat notation.\n */\n #phrases;\n\n /**\n * @var {?object}\n * This store object for nested object notation.\n */\n #objects;\n\n /**\n * This create new phrasebook from phrases map, and optional object\n * for phrases in object notation.\n * \n * @param {Map} phrases - This contain phrases in flat notation.\n * @param {?object} objects - This contain phrases in object notation. \n */\n constructor(phrases, objects = null) {\n if (!(phrases instanceof Map)) {\n throw new TypeError(\"Phrases must an map.\");\n }\n\n if (objects !== null && typeof(objects) !== \"object\") {\n throw new TypeError(\"Objects must be null or object.\");\n }\n \n this.#phrases = phrases;\n this.#objects = objects;\n }\n\n /**\n * This translate given phrase. When phrase is in the nested object \n * notation, then try to find phrase in objects. When not, try to find\n * phrase in the flat phrases. When could not find phrase, then return \n * not translated phrase. Content always is returned as translation\n * object, which could be also formated wich numbers, dates and\n * much more.\n * \n * @param {string} phrase - Phrase to translate. \n * @returns {translation} - Translated phrase.\n */\n translate(phrase) {\n if (typeof(phrase) !== \"string\") {\n throw new TypeError(\"Phrase to translate must be an string.\");\n }\n\n if (this.#is_nested(phrase)) {\n return this.#translate_nested(phrase);\n }\n\n return this.#translate_flat(phrase);\n }\n\n /**\n * This translate given phrase. When phrase is in the nested object \n * notation, then try to find phrase in objects. When not, try to find\n * phrase in the flat phrases. When could not find phrase, then return \n * not translated phrase. Content always is returned as translation\n * object, which could be also formated wich numbers, dates and\n * much more.\n * \n * @param {string} phrase - Phrase to translate. \n * @returns {translation} - Translated phrase.\n */\n get(phrase) {\n return this.translate(phrase);\n }\n\n /**\n * Check that phrase is nested or not.\n * \n * @param {string} phrase - Phrase to check that is nested\n * @returns {bool} - True when nested, false when not \n */\n #is_nested(phrase) {\n return phrase.indexOf(\".\") !== -1;\n }\n\n /**\n * This translate object notated phrase.\n * \n * @param {string} phrase - Phrase to translate.\n * @returns {translation} - Translated phrase. \n */\n #translate_nested(phrase) {\n if (this.#objects === null) {\n return this.#translate_flat(phrase);\n }\n\n const parts = phrase.trim().split(\".\");\n let current = this.#objects;\n\n for (const count in parts) {\n const part = parts[count];\n \n if (!(part in current)) {\n return new translation(phrase, false);\n }\n\n current = current[part];\n }\n\n if (typeof(current) !== \"string\") {\n return new translation(phrase, false);\n }\n\n return new translation(current, true);\n }\n\n /**\n * This set phrasebook as default. That mean, it would add own translate\n * function to global scope, and create _({string}) function in the global\n * scope. It is useable to minify code with translations. It is not \n * avairable in the NodeJS, only in the browser.\n * \n * @returns {phrasebook} - Object itself to chain loading.\n */\n set_as_default() {\n NODE: throw new Error(\"Could not create global function in NodeJS.\");\n \n const translate = (content) => {\n return this.translate(content);\n };\n\n window._ = translate;\n window.translate = translate;\n }\n\n /**\n * This translate flat phrase.\n * \n * @param {string} phrase - Phrase to translate. \n * @returns {translation} - Translated phrase.\n */\n #translate_flat(phrase) {\n const prepared = phrasebook.prepare(phrase);\n const found = this.#phrases.has(prepared);\n const translated = found ? this.#phrases.get(prepared) : phrase;\n \n return new translation(translated, found);\n }\n\n /**\n * This prepars phrase, that mean replece all spaces with \"_\", trim \n * and also replace all big letters with lowwer. \n * \n * @param {string} content - Phrase to preapre.\n * @return {string} - Prepared phrase.\n */ \n static prepare(content) {\n if (typeof(content) !== \"string\") {\n throw new TypeError(\"Content to prepare must be an string.\");\n }\n \n return content\n .trim()\n .replaceAll(\" \", \"_\")\n .replaceAll(\".\", \"_\")\n .toLowerCase();\n }\n}\n\nexports.phrasebook = phrasebook;", "const phrasebook = require(\"./phrasebook.js\").phrasebook;\n\n/**\n * This class fetch and prepare phrasebook from JSON file. That JSON file \n * could be simple flat JSON, which contain string phrases as keys, and \n * its translatedequivalents as values. Also avalirable is format, where\n * phrases not being used, but JSON contain nested objects. End value must\n * being translated string, but then notation like \"a.b.c\" could being used.\n * \n * @example simple flat phrasebook ```JSON\n * JSON:\n * {\n * \"phrase a\": \"Translated phrase a\",\n * \"phrase b\": \"Translated phrase b\"\n * }\n * \n * Results:\n * \"phrase a\" -> \"Translated phrase a\",\n * \"phrase b\" -> \"Translated phrase b\"\n * ```\n * \n * @example simple nested phrasebook ```JSON\n * JSON:\n * {\n * \"phrases\": {\n * \"phrase a\": \"Translated phrase a\"\n * },\n * \"objects\": {\n * \"a\": {\n * \"b\": {\n * \"c\": \"Second object notation\"\n * }\n * } \n * }\n * }\n * \n * Results:\n * \"phrase a\" -> \"Translated phrase a\",\n * \"a.b.c\" -> \"Second object notation\" \n * ``` \n */\nclass loader {\n /**\n * @var {string}\n * This is location of the phrasebook on the server.\n */\n #path;\n\n /**\n * @var {bool}\n * This is true, when must load local file, or false when fetch.\n */\n #local;\n\n /**\n * This create new loader of the phrasebook.\n * \n * @param {string} path - Location of the phrasebook to fetch.\n * @param {bool} local - False when must fetch from remote.\n */\n constructor(path, local = false) {\n if (typeof(path) !== \"string\") {\n throw new TypeError(\"Path of the file must be string.\");\n }\n\n if (typeof(local) !== \"boolean\") {\n throw new TypeError(\"Local must be bool variable.\");\n }\n\n this.#path = path;\n this.#local = local;\n }\n\n /**\n * This load file from path given in the constructor, parse and return it.\n * \n * @returns {phrasebook} - New phrasebook with content from JSON file.\n */\n async #load_remote() {\n const request = await fetch(this.#path);\n const response = await request.json();\n\n return this.#parse(response);\n }\n\n /**\n * This load file from path given in the constructor, parse and return it.\n * \n * @returns {phrasebook} - New phrasebook with content from JSON file.\n */\n async #load_local() {\n let fs = null;\n NODE: fs = require(\"node:fs/promises\");\n\n if (fs === null) {\n throw new Error(\"Could not use ndoe:fs in browser.\");\n }\n\n const content = await fs.readFile(this.#path, { encoding: 'utf8' });\n const response = JSON.parse(content);\n\n return this.#parse(response);\n }\n\n /**\n * This load file from path given in the constructor, parse and return it.\n * \n * @returns {phrasebook} - New phrasebook with content from JSON file.\n */\n load() {\n if (this.#local) {\n return this.#load_local();\n }\n\n return this.#load_remote();\n }\n\n /**\n * This parse phrasebook. When phrasebook contain \"phrases\" or \"objects\" \n * keys, and also \"objects\" is not string, then parse it as nested file,\n * in the other way parse it as flat.\n * \n * @param {object} content - Fetched object with translations. \n * @returns {phrasebook} - Loaded phrasebook.\n */\n #parse(content) {\n const has_objects = (\n \"objects\" in content &&\n typeof(content[\"objects\"]) === \"object\"\n );\n\n const has_phrases = (\n \"phrases\" in content &&\n typeof(content[\"phrases\"]) === \"object\"\n );\n\n const is_nested = has_objects || has_phrases;\n\n if (is_nested) {\n const phrases = has_phrases ? content[\"phrases\"] : {};\n const objects = has_objects ? content[\"objects\"] : {};\n\n return new phrasebook(\n this.#parse_phrases(phrases),\n objects\n );\n }\n\n return new phrasebook(this.#parse_phrases(content));\n }\n\n /**\n * This parse flat phrases object to map.\n * \n * @param {object} content - Flat phrases object to pase.\n * @returns {Map} - Phrases parsed as Map.\n */\n #parse_phrases(content) {\n const phrases = new Map();\n\n Object.keys(content).forEach(phrase => {\n const name = phrasebook.prepare(phrase);\n const translation = content[phrase];\n\n phrases.set(name, translation);\n });\n\n return phrases;\n }\n}\n\nexports.loader = loader;", "const loader = require(\"./loader.js\").loader;\nconst phrasebook = require(\"./phrasebook.js\").phrasebook;\n\n/**\n * This class represents languages library. This store its location on the \n * server, and create loaders for them. It could also load langiage \n * library from json file.\n */\nclass languages {\n /**\n * @var {string} \n * This represents path to directory where phrasebooks had been stored.\n */\n #path;\n\n /**\n * @var {Map}\n * This store languages and its files on server. \n */\n #libs;\n\n /**\n * @var {bool}\n * This store that directory is in the local file system, or remote\n * server. When true, resources would be loaded by node:fs. When \n * false, resources would be fetched.\n */\n #local;\n\n /**\n * This create new languages library. Next, languages could be added to\n * the library by command, or by loading index file.\n * \n * @throws {TypeError} - When parameters is not in correct format.\n * \n * @param {string} path - Path to phrasebooks on the server or filesystem.\n * @param {bool} local - True when phrasebooks dirs would be loaded by \n * node:fs module. False when would be fetch.\n */\n constructor(path, local = false) {\n if (typeof(path) !== \"string\") {\n throw new TypeError(\"Path to the phrasebooks must be string.\");\n }\n\n if (typeof(local) !== \"boolean\") {\n throw new TypeError(\"Local must be bool variable.\");\n }\n\n this.#local = local;\n this.#path = path;\n this.#libs = new Map();\n }\n\n /**\n * This add new language to the library by name. Name must be in form\n * like POSIX locale, like en_US, or pl_PL. That mean first two letter\n * mest be ISO 639-1 and second two letters mst be in ISO 3166-1 alpha-2\n * 2 letter country code format.\n * \n * @see https://www.loc.gov/standards/iso639-2/php/code_list.php\n * @see https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes\n * @see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2\n * @see https://en.wikipedia.org/wiki/Locale_(computer_software)\n * \n * @throws {TypeError} - When tpes of the parameters is not correct.\n * \n * @param {string} name - Name of the language, like \"en_US\".\n * @param {string} file - Name of the file in the directory.\n * @return {languages} - Instnace of this class to chain.\n */\n add(name, file) {\n if (typeof(name) !== \"string\") {\n throw new TypeError(\"Name of the language must be sting.\");\n }\n\n if (typeof(file) !== \"string\") {\n throw new TypeError(\"File on in the directory must be string.\");\n }\n\n if (this.#libs.has(name)) {\n console.error(\"Language \\\"\" + name + \"\\\" already loaded.\");\n console.error(\"It could not being loaded twice.\");\n return this;\n }\n\n if (!this.#valid_locale(name)) {\n console.error(\"Language name \\\"\" + name + \"\\\" invalid formated.\");\n console.error(\"It could not being loaded.\")\n return this;\n }\n \n this.#libs.set(name, file);\n return this;\n }\n\n /**\n * This load all phrasebook given in the index file. Index must be\n * JSON file, which contain one object. That object properties must be\n * languages names in the notation like in add function. Valus of that\n * properties musts being strings which contains names of the phrasebook\n * files in the path directory.\n * \n * @example ``` { \"pl_PL\": \"polish.json\", \"en_US\": \"english.json\" } ```\n * \n * @see add\n * \n * @param {string} index - Index file in the phrasebook directory.\n * @return {languages} - New languages instance with loaded index.\n */\n async load(index) {\n if (typeof(index) !== \"string\") {\n throw new TypeError(\"Name of index file is not string.\");\n }\n\n const response = await this.#load_index(index);\n this.#libs.clear();\n\n Object.keys(response).forEach(name => {\n if (typeof(name) !== \"string\") {\n console.error(\"Name of the language must be string.\");\n console.error(\"Check languages index.\");\n console.error(\"Skipping it.\")\n return;\n }\n\n if (typeof(response[name]) !== \"string\") {\n console.error(\"Name of phrasebook file must be string.\");\n console.error(\"Check languages index.\");\n console.error(\"Skipping it.\");\n return;\n }\n\n this.add(name, response[name]);\n });\n\n return this;\n }\n\n /**\n * This load index object. That check, and when content must be loaded\n * from local filesystem, it use node:fs, or when it must be fetched from\n * remote, then use fetch API.\n * \n * @param {string} index - Name of the index file in library. \n * @returns {object} - Loaded index file content. \n */\n async #load_index(index) {\n const path = this.#full_path(index);\n\n if (this.#local) {\n let fs = null;\n NODE: fs = require(\"node:fs/promises\"); \n \n if (fs === null) {\n throw new Error(\"Could not use ndoe:fs in browser.\");\n }\n\n return JSON.parse(\n await fs.readFile(path, { encoding: \"utf-8\" })\n );\n }\n\n const request = await fetch(path);\n return await request.json();\n }\n\n /**\n * This check that language exists in languages library.\n * \n * @param {string} name - Name of the language to check.\n * @return {bool} - True when language exists, false when not\n */\n has(name) {\n return this.#libs.has(name);\n }\n\n /**\n * This return all avairable languages.\n * \n * @return {Array} - List of all avairable languages.\n */\n get avairable() {\n const alls = new Array();\n\n this.#libs.keys().forEach(name => {\n alls.push(name);\n });\n\n return alls;\n }\n\n /**\n * @returns {string} - Default \n */\n get default() {\n const avairable = this.avairable;\n\n if (avairable.length === 0) {\n throw new Error(\"Languages list is empty. Can not load default.\");\n }\n\n return avairable[0];\n }\n\n /**\n * This load phrasebook with give name.\n * \n * @throws {TypeError} - Param type is not correct.\n * @throws {RangeError} - Language not exists in libs.\n * \n * @param {string} name - Name of the language to load. \n * @returns {phrasebook} - Phrasebook loaded from the file.\n */\n select(name) {\n if (typeof(name) !== \"string\") {\n throw new TypeError(\"Name of the language must be string.\");\n }\n\n if (!this.has(name)) {\n DEBUG: throw new RangeError(\n \"Not found language \\\"\" + name + \"\\\".\"\n );\n\n return new phrasebook(new Map());\n }\n \n const file = this.#libs.get(name);\n const path = this.#full_path(file);\n\n return new loader(path, this.#local).load();\n }\n\n /**\n * This return full path to the file.\n * \n * @param {string} name - Name of the file to get its path\n * @return {string} - Full path of the file\n */\n #full_path(name) {\n let glue = \"/\";\n\n if (this.#path[this.#path.length - 1] === glue) {\n glue = \"\";\n }\n\n return this.#path + glue + name;\n }\n\n /**\n * This check that format is valid POSIX like locale.\n * \n * @param {string} name - Name to check format of.\n * @return {bool} - True when format is valid, false when not.\n */\n #valid_locale(name) {\n const splited = name.split(\"_\");\n\n if (splited.length !== 2) {\n return false;\n }\n\n const first = splited[0];\n const second = splited[1];\n\n if (first.toLowerCase() !== first || first.length !== 2) {\n return false;\n }\n\n if (second.toUpperCase() !== second || second.length !== 2) {\n return false;\n }\n\n return true;\n }\n}\n\nexports.languages = languages;", "const languages = require(\"./languages.js\").languages;\n\n/**\n * This could be used to setup language selector. This require languages\n * container, and could create functional languages selector from it. This \n * add options to select all avaoidable languages in the container.\n */\nclass selector {\n /**\n * @var {languages}\n * This store languages container.\n */\n #languages;\n\n /**\n * @var {?HTMLElement}\n * This store selector HTML container, or null when not created.\n */\n #container;\n\n /**\n * @var {HTMLElement}\n * This store languages HTML selector object.\n */\n #selector;\n\n /**\n * @var {Array}\n * This is array of callbacks which must being called after change.\n */\n #callbacks;\n\n /**\n * This create new selector object, from languages container.\n * \n * @param {languages} languages - Languages container to work on.\n */\n constructor(languages) {\n NODE: throw new Error(\"This module could not beind used in NodeJS.\");\n \n this.#container = null;\n this.#languages = languages;\n this.#callbacks = new Array();\n this.#selector = this.#create_selector();\n }\n\n /**\n * This check that selector is currently inserted anywhere.\n * \n * @returns {bool} - True when selector is inserted anywhere.\n */\n get is_inserted() {\n return this.#container !== null;\n }\n\n /**\n * This inserts selector into given HTML element, or directly into\n * document body, when any element is not specified. It returns \n * itselt, to call more functions inline.\n * \n * @param {?HTMLElement} where - Place to insert selector, or null.\n * @returns {selector} - This object to chain loading.\n */\n insert(where = null) {\n if (this.is_inserted) {\n return this;\n }\n\n if (where === null) {\n where = document.querySelector(\"body\");\n }\n\n this.#container = this.#create_container();\n where.appendChild(this.#container);\n\n return this;\n }\n\n /**\n * This run all functions which was registered as onChange callback.\n */\n #on_change() {\n this.#callbacks.forEach(count => {\n count(this.current);\n });\n }\n\n /**\n * This function remove selector from HTML element, if it is already\n * inserted anywhere.\n * \n * @returns {selector} - This object to chain loading.\n */\n remove() {\n if (!this.is_inserted) {\n return this;\n }\n\n this.#container.remove();\n this.#container = null;\n\n return this;\n }\n\n /**\n * This create new container with selector inside.\n * \n * @returns {HTMLElement} - New container with selector.\n */\n #create_container() {\n const container = document.createElement(\"div\");\n \n container.classList.add(this.class_name);\n container.appendChild(this.#selector);\n \n return container;\n }\n\n /**\n * This add new callback to selector. All callbacks would be called\n * after language change. Callback would get one parameter, which is\n * name of the location.\n * \n * @param {CallableFunction} callback - Function to call on change.\n * @returns \n */\n add_listener(callback) {\n this.#callbacks.push(callback);\n return this;\n }\n\n /**\n * This return HTML class name of selector container.\n * \n * @returns {string} - HTML class name of selector container.\n */\n get class_name() {\n return 'cx-libtranslate-language-selector';\n }\n\n /**\n * This create HTML option element from language name.\n * \n * @param {string} location - Name of single language. \n * @returns {HTMLElement} - New option element.\n */\n #create_option(location) {\n const name = location.split(\"_\").pop();\n const option = document.createElement(\"option\");\n\n option.innerText = name;\n option.value = location;\n\n return option;\n }\n\n /**\n * This return current selected language name.\n * \n * @returns {string} - Current selected language.\n */\n get current() {\n return this.#selector.value;\n }\n\n /**\n * This set current selected language for the selector.\n * \n * @param {string} name - Name of the language to set.\n * @returns {selector} - This to chain loading.\n */\n set_selection(name) {\n if (!this.#languages.has(name)) {\n DEBUG: throw new Error(\n \"Selector has not \\\"\" + name + \"\\\" \" +\n \"language in the container.\"\n );\n }\n\n this.#selector.value = name;\n return this;\n }\n\n /**\n * This reload languages list in the selector. It could be used\n * after change in the languages container.\n * \n * @returns {selector} - Itself to chain loading.\n */\n reload() {\n while (this.#selector.lastChild) {\n this.#selector.lastChild.remove();\n }\n\n this.#languages.avairable.forEach(count => {\n this.#selector.appendChild(this.#create_option(count));\n });\n\n return this;\n }\n\n /**\n * This create new HTML selector object, witch all languages\n * from container inserted as options.\n * \n * @returns {HTMLElement} - New selector object.\n */\n #create_selector() {\n const selector = document.createElement(\"select\");\n\n selector.addEventListener(\"change\", () => {\n this.#on_change();\n });\n\n this.#languages.avairable.forEach(count => {\n selector.appendChild(this.#create_option(count));\n }); \n\n return selector;\n }\n}\n\nexports.selector = selector;", "const { phrasebook } = require(\"./phrasebook\");\n\n/**\n * This class is responsible for automatic translate site content of the \n * HTML elements. It could automatic translate content for all elements \n * which are in the \"translate\" class, and has \"phrase\" attribute. This \n * attrobite store phrase to translate, and insert into element innerText\n * or placeholder (for inputs). It could also observate HTML Node, and\n * automatic update transltions when any item had been changed.\n */\nclass autotranslate {\n /**\n * @var {?phrasebook}\n * This store phrasebook to get translates from, or store null, to get\n * translate content from global translate function.\n */\n #phrasebook;\n\n /**\n * @var {?MutationObserver}\n * This store observer object, when it is connecter and waiting for \n * changaes, or store null, when observer currently not working.\n */\n #observer;\n\n /**\n * This create new autotranslator. It require phrasebook, to loads \n * translations for phrases from. When null had been given, the it \n * use global translate function.\n * \n * @throws {Error} - When trying to use it in the NodeJS.\n * \n * @param {?phrasebook} phrasebook \n */\n constructor(phrasebook = null) {\n NODE: throw new Error(\"It is not avairable in the NodeJS.\");\n this.#observer = null;\n this.#phrasebook = phrasebook;\n }\n\n /**\n * It return class name for elements, which would be translated by \n * autotranslator.\n * \n * @returns {string} - Class name for autotranslating elements.\n */\n static get_class_name() {\n return \"translate\"; \n }\n\n /**\n * This return selector for choose elements which must be autotranslated.\n * \n * @returns {string} - Selector of the elements to translate.\n */\n get #class_selector() {\n return \".\" + autotranslate.get_class_name();\n }\n\n /**\n * This return name of attribute which store phrase to translate.\n * \n * @returns {string} - Name of attribute which store phrase.\n */\n static get_attribute_name() {\n return \"phrase\";\n }\n\n /**\n * This check that autotranslator is connected and waiting to changes.\n * \n * @returns {bool} - True when observer is connected, fakse when not.\n */\n get is_connected() {\n return this.#observer !== null;\n }\n\n /**\n * This search elements which could be translated in the element given\n * in the parameter. When null given, then it search elements in the \n * all document.\n * \n * @param {?HTMLElement} where - Item to load items from or null.\n * @returns {Array} - Array of elements to translate.\n */\n #get_all_items(where = null) {\n if (where === null) {\n where = document;\n }\n\n return Array.from(\n where.querySelectorAll(this.#class_selector)\n );\n }\n\n /**\n * It translate given phrase, baseed on loaded phrasebook, or when not\n * loaded any, then use global translate function. When it also not \n * exists, then throws error in debug mode, or return not translated\n * phrase on production.\n * \n * @throws {Error} - When any option to translate not exists.\n * \n * @param {string} content - Phrase to translate.\n * @returns {string} - Translated content.\n */\n #translate(content) {\n if (this.#phrasebook !== null) {\n return this.#phrasebook.translate(content);\n }\n\n if (_ === undefined) {\n DEBUG: throw new Error(\"All translate options are unavairable.\");\n return content;\n }\n\n return _(content);\n }\n\n /**\n * This add mutable observer to the body. It wait for DOM modifications,\n * and when any new node had been adder, or any phrase attribute had \n * been changed, then it trying to translate it.\n * \n * @returns {autotranslate} - This object to chain load.\n */\n connect() {\n if (this.is_connected) {\n return this;\n }\n\n const body = document.querySelector(\"body\");\n const callback = (targets) => { this.#process(targets); };\n const options = {\n childList: true,\n attributes: true,\n characterData: false,\n subtree: true,\n attributeFilter: [ autotranslate.get_attribute_name() ],\n attributeOldValue: false,\n characterDataOldValue: false\n };\n\n this.#observer = new MutationObserver(callback);\n this.#observer.observe(body, options);\n\n return this;\n }\n\n /**\n * This prcoess all given in the array mutable records. \n * \n * @param {Array} targets - Array with mutable records. \n */\n #process(targets) {\n targets.forEach(count => {\n if (count.type === \"attributes\") {\n this.#update_single(count.target);\n return;\n }\n\n this.#get_all_items(count.target).forEach(count => {\n this.#update_single(count);\n });\n });\n }\n\n /**\n * This disconnect observer, and remove it.\n * \n * @returns {autotranslate} - This object to chain loading.\n */\n disconnect() {\n if (!this.is_connected) {\n return this;\n }\n\n this.#observer.disconnect();\n this.#observer = null;\n return this;\n }\n\n /**\n * This update single element, based on phrase attribute. When element \n * is standard HTMLElement, then it place translated content into \n * innerText, but when element is input, like HTMLInputElement or\n * HTMLTextAreaElement, then it place result into placeholder. When\n * input is button, or submit, then it put content into value.\n * \n * @param {HTMLElement} target - Element to translate \n */\n #update_single(target) {\n const attrobute_name = autotranslate.get_attribute_name();\n const phrase = target.getAttribute(attrobute_name);\n const result = this.#translate(phrase);\n\n if (target instanceof HTMLInputElement) {\n if (target.type === \"button\" || target.type === \"submit\") {\n target.value = result;\n return;\n }\n \n target.placeholder = result;\n return;\n }\n\n if (target instanceof HTMLTextAreaElement) {\n target.placeholder = result;\n return;\n }\n\n target.innerText = result\n }\n\n /**\n * This update translation of all elements in the document. It is useable\n * when new autotranslator is created. \n * \n * @returns {autotranslate} - Instance of object to chain loading.\n */\n update() {\n this.#get_all_items().forEach(count => {\n this.#update_single(count);\n });\n\n return this;\n }\n}\n\nexports.autotranslate = autotranslate;", "\nconst languages = require(\"./languages.js\").languages;\nconst phrasebook = require(\"./phrasebook.js\").phrasebook;\nconst selector = require(\"./selector.js\").selector;\nconst autotranslate = require(\"./autotranslate.js\").autotranslate;\n\n/**\n * This class is responsible for saving and loading user language preferences\n * in the browser localStorage. It is not avairable, when using library in\n * the NodeJS enviroment.\n */\nclass preferences {\n /**\n * @var {languages}\n * This store loaded languages object.\n */\n #languages;\n\n /**\n * @var {?selector}\n * This store selector for preferences.\n */\n #selector;\n\n /**\n * @var {?autotranslate}\n * This store autotranslator, or null.\n */\n #autotranslate;\n\n /**\n * This create new language preferences manager from loaded languages\n * object.\n *\n * @throws {Error} - When trying to use it in NodeJS.\n * \n * @param {languages} target - loaded languages object.\n */\n constructor(target) {\n NODE: throw new Error(\"It could be used only in browser.\");\n this.#selector = null;\n this.#autotranslate = null;\n this.#languages = target;\n }\n\n /**\n * This return name of language key in localStorage.\n * \n * @returns {string} - Name of key in localStorage.\n */\n get #setting_name() {\n return \"cx_libtranslate_lang\";\n }\n\n /**\n * This return current saved language name, or null if any language\n * is not selected yet.\n * \n * @returns {?string} - Saved language or null.\n */\n get #state() {\n return localStorage.getItem(this.#setting_name);\n }\n\n /**\n * This return selector, which could being used in the ui.\n * \n * @returns {selector} - New UI selector of the languages.\n */\n get selector() {\n if (this.#selector !== null) {\n return this.#selector;\n }\n\n this.#selector = new selector(this.#languages)\n .set_selection(this.current)\n .add_listener(target => {\n this.update(target); \n })\n .add_listener(async target => { \n if (this.#autotranslate === null) {\n return;\n }\n\n this.#reload_autotranslate();\n });\n\n return this.#selector;\n }\n\n async #reload_autotranslate() {\n const connected = this.#autotranslate.is_connected;\n\n if (connected) {\n this.#autotranslate.disconnect();\n }\n\n this.#autotranslate = null;\n const created = await this.get_autotranslate();\n \n if (connected) {\n created.connect();\n }\n }\n\n /**\n * This load phrasebook for selected language, create autotranslate\n * for it, and returns it. Autotranslate is cached in this object.\n * \n * @returns {autotranslate} - Autotranslate for phrasebook.\n */\n async get_autotranslate() {\n if (this.#autotranslate !== null) {\n return this.#autotranslate;\n }\n\n const phrasebook = await this.load_choosen_phrasebook();\n this.#autotranslate = new autotranslate(phrasebook);\n this.#autotranslate.update();\n\n return this.#autotranslate;\n }\n\n /**\n * This save new selected language name to localStorage, or remove it \n * from there if null given.\n * \n * @param {?string} content - Name of selected language or null.\n */\n set #state(content) {\n if (content === null) {\n localStorage.removeItem(this.#setting_name);\n return;\n }\n\n localStorage.setItem(this.#setting_name, content);\n }\n\n /**\n * This return current language from localStorage. When any language is\n * not loaded yet, then return default language. It also check that value\n * value from localStorage, and if it not avairable in languages storage,\n * then also return default language.\n * \n * @return {string} - Name of the current language.\n */\n get current() {\n const saved = this.#state;\n\n if (saved === null) {\n return this.#languages.default;\n }\n\n if (this.#languages.has(saved)) {\n return saved;\n }\n\n return this.#languages.default;\n }\n\n /**\n * This load phrasebook for current selected language.\n * \n * @returns {phrasebook} - Phrasebook for current language.\n */\n async load_choosen_phrasebook() {\n return await this.#languages.select(this.current);\n }\n\n /**\n * This return loaded languages container.\n * \n * @returns {languages} - Languages container.\n */\n get languages() {\n return this.#languages;\n }\n\n /**\n * This set new language for user. It also check that language exists \n * in the language container. When not exists, throws error.\n * \n * @throws {Error} - When language not exists in container.\n * \n * @param {string} name - New language to select.\n * @returns {preferences} - This object to chain.\n */\n update(name) {\n DEBUG: if (!this.#languages.has(name)) {\n let error = \"Can not set language \\\"\" + name + \"\\\" \";\n error += \"because not exists in languages container.\";\n\n throw new Error(error);\n }\n\n this.#state = name;\n return this;\n }\n}\n\nexports.preferences = preferences;", "if (typeof(module) !== \"undefined\" && module.exports) {\n /* Load for NodeJS */\n module.exports.phrasebook = require(\"./phrasebook.js\").phrasebook;\n module.exports.loader = require(\"./loader.js\").loader;\n module.exports.languages = require(\"./languages.js\").languages;\n module.exports.loader = require(\"./loader.js\").loader;\n module.exports.preferences = require(\"./preferences.js\").preferences;\n module.exports.selector = require(\"./selector.js\").selector;\n module.exports.autotranslate = require(\"./autotranslate.js\").autotranslate;\n} else {\n /* Load for web browser */\n window.cx_libtranslate = {\n phrasebook: require(\"./phrasebook.js\").phrasebook,\n loader: require(\"./loader.js\").loader,\n languages: require(\"./languages.js\").languages,\n translation: require(\"./translation.js\").translation,\n preferences: require(\"./preferences.js\").preferences,\n selector: require(\"./selector.js\").selector,\n autotranslate: require(\"./autotranslate.js\").autotranslate\n };\n}\n"], "mappings": "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", "names": ["require_translation", "__commonJSMin", "exports", "translation", "#content", "#translated", "content", "translated", "#parse_format", "parts", "result", "count", "splited", "name", "rest", "require_phrasebook", "__commonJSMin", "exports", "translation", "phrasebook", "_phrasebook", "#phrases", "#objects", "phrases", "objects", "phrase", "#is_nested", "#translate_nested", "#translate_flat", "parts", "current", "count", "part", "translate", "content", "prepared", "found", "translated", "require_loader", "__commonJSMin", "exports", "phrasebook", "loader", "#path", "#local", "path", "local", "#load_remote", "response", "#parse", "#load_local", "fs", "content", "has_objects", "has_phrases", "phrases", "objects", "#parse_phrases", "phrase", "name", "translation", "require_languages", "__commonJSMin", "exports", "loader", "phrasebook", "languages", "#path", "#libs", "#local", "path", "local", "name", "file", "#valid_locale", "index", "response", "#load_index", "#full_path", "fs", "alls", "avairable", "glue", "splited", "first", "second", "require_selector", "__commonJSMin", "exports", "languages", "selector", "#languages", "#container", "#selector", "#callbacks", "#create_selector", "where", "#create_container", "#on_change", "count", "container", "callback", "#create_option", "location", "name", "option", "require_autotranslate", "__commonJSMin", "exports", "phrasebook", "autotranslate", "_autotranslate", "#phrasebook", "#observer", "#class_selector", "#get_all_items", "where", "#translate", "content", "body", "callback", "targets", "#process", "options", "count", "#update_single", "target", "attrobute_name", "phrase", "result", "require_preferences", "__commonJSMin", "exports", "languages", "phrasebook", "selector", "autotranslate", "preferences", "#languages", "#selector", "#autotranslate", "target", "#setting_name", "#state", "#reload_autotranslate", "connected", "created", "content", "saved", "name", "require_core", "__commonJSMin", "exports", "module"] }