From af7f65c29c8a9adeb383984b809786f38e87becf Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 1 Jul 2025 12:06:08 +0200 Subject: [PATCH 1/2] [task-343] [int] --- data/localization/de.json | 17 +++ data/localization/en.json | 17 +++ ivaldi.json | 1 + source/conf.ts | 214 ++++++++++++++++++++++++-------------- source/main.ts | 11 ++ source/types.ts | 11 -- 6 files changed, 181 insertions(+), 90 deletions(-) create mode 100644 data/localization/de.json create mode 100644 data/localization/en.json diff --git a/data/localization/de.json b/data/localization/de.json new file mode 100644 index 0000000..35e5036 --- /dev/null +++ b/data/localization/de.json @@ -0,0 +1,17 @@ +{ + "meta": { + "identifier": "de", + "name": "Deutsch" + }, + "tree": { + "event": "Termin", + "events": "Termine", + "reminder": "Erinnerung", + "title_long": "Titel", + "title_short": "was", + "time_long": "Datum und Uhrzeit", + "time_short": "wann", + "location_long": "Ort", + "location_short": "wo" + } +} diff --git a/data/localization/en.json b/data/localization/en.json new file mode 100644 index 0000000..c8140d3 --- /dev/null +++ b/data/localization/en.json @@ -0,0 +1,17 @@ +{ + "meta": { + "identifier": "en", + "name": "English" + }, + "tree": { + "event": "event", + "events": "events", + "reminder": "reminder", + "title_long": "title", + "title_short": "what", + "time_long": "date and time", + "time_short": "when", + "location_long": "location", + "location_short": "where" + } +} diff --git a/ivaldi.json b/ivaldi.json index c3c033f..9b52f35 100644 --- a/ivaldi.json +++ b/ivaldi.json @@ -16,6 +16,7 @@ "file", "conf", "log", + "translate", "args" ] } diff --git a/source/conf.ts b/source/conf.ts index fdb581f..c43fb7f 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -315,11 +315,69 @@ namespace _munin.conf events : string; }; }; - + /** */ - export type type_conf = type_conf_v5; + type type_conf_v6 = { + sources : Array< + ( + { + kind : "ical_feed"; + data : { + url : string; + filtration : { + category_whitelist : (null | Array); + category_blacklist : (null | Array); + title_whitelist : (null | Array); + title_blacklist : (null | Array); + } + } + } + ) + >; + targets : Array< + ( + { + kind : "email"; + data : { + smtp_host : string; + smtp_port : int; + smtp_username : string; + smtp_password : string; + sender : string; + receivers : Array; + hide_tags : boolean; + /** + * in hours + */ + reminders : Array; + } + } + | + { + kind : "telegram_bot"; + data : { + bot_token : string; + chat_id : int; + hide_tags : boolean; + /** + * in hours + */ + reminders : Array; + } + } + ) + >; + settings : { + interval : float; + }; + }; + + + /** + */ + export type type_conf = type_conf_v6; /** @@ -538,6 +596,25 @@ namespace _munin.conf } + /** + */ + function convert_from_v5( + conf_v5 : type_conf_v5 + ) : type_conf_v6 + { + lib_plankton.log._notice( + "munin.conf.dropping_labels", + { + } + ); + return { + "source": conf_v5.sources, + "targets": conf_v5.targets, + "settings": conf_v5.settings, + }; + } + + /** */ function schema_source_kalender_digital( @@ -695,7 +772,8 @@ namespace _munin.conf ) : lib_plankton.conf.type_schema { switch (version) { - case "1": { + case "1": + { return { "nullable": false, "type": "array", @@ -709,7 +787,8 @@ namespace _munin.conf break; } default: - case "2": { + case "2": + { return { "nullable": false, "type": "array", @@ -743,7 +822,6 @@ namespace _munin.conf "type": "integer", }; } - case "5": default: { return { @@ -802,7 +880,6 @@ namespace _munin.conf { return [24]; } - case "5": default: { return [ @@ -915,27 +992,54 @@ namespace _munin.conf "data": { "nullable": false, "type": "object", - "properties": { - "bot_token": { - "nullable": false, - "type": "string", + "properties": Object.assign( + { + "bot_token": { + "nullable": false, + "type": "string", + }, + "chat_id": { + "nullable": false, + "type": "integer", + }, + "hide_tags": { + "nullable": false, + "type": "boolean", + "default": false, + }, + "reminders": { + "nullable": false, + "type": "array", + "items": schema_reminder(version), + "default": default_reminder(version), + }, }, - "chat_id": { - "nullable": false, - "type": "integer", - }, - "hide_tags": { - "nullable": false, - "type": "boolean", - "default": false, - }, - "reminders": { - "nullable": false, - "type": "array", - "items": schema_reminder(version), - "default": default_reminder(version), - }, - }, + (() => { + switch (version) + { + case "1": + case "2": + case "3": + case "4": + case "5": + { + return {}; + break; + } + default: + { + return { + "language": { + "nullable": false, + "type": "string", + "default": "de" + }, + }; + break; + } + } + }) () + ), "additionalProperties": false, "required": [ "bot_token", @@ -973,8 +1077,6 @@ namespace _munin.conf ]; break; } - case "4": - case "5": default: { return [ @@ -1015,54 +1117,10 @@ namespace _munin.conf } - /** - */ - function schema_labels( - version : string - ) : lib_plankton.conf.type_schema - { - return { - "nullable": false, - "type": "object", - "properties": { - "head": { - "nullable": false, - "type": "string", - "default": "Termin-Erinnerung" - }, - "title": { - "nullable": false, - "type": "string", - "default": "was" - }, - "time": { - "nullable": false, - "type": "string", - "default": "wann" - }, - "location": { - "nullable": false, - "type": "string", - "default": "wo" - }, - "events": { - "nullable": false, - "type": "string", - "default": "Termine" - }, - }, - "additionalProperties": false, - "required": [ - ], - "default": {} - }; - } - - /** */ export function schema( - version : string = "5" + version : string = "6" ) : lib_plankton.conf.type_schema { switch (version) { @@ -1088,10 +1146,7 @@ namespace _munin.conf }; break; } - case "2": - case "3": - case "4": - case "5": + default: { return { "nullable": false, @@ -1128,7 +1183,8 @@ namespace _munin.conf "2": {"target": "3", "function": convert_from_v2}, "3": {"target": "4", "function": convert_from_v3}, "4": {"target": "5", "function": convert_from_v4}, - "5": null, + "5": {"target": "6", "function": convert_from_v5}, + "6": null, } ); @@ -1166,7 +1222,7 @@ namespace _munin.conf } } */ - return (conf_raw.content as type_conf_v5); + return (conf_raw.content as type_conf_v6); } } diff --git a/source/main.ts b/source/main.ts index af737a4..fd85b7c 100644 --- a/source/main.ts +++ b/source/main.ts @@ -108,6 +108,17 @@ namespace _munin args_raw.join(" ") ); + await lib_plankton.translate.initialize( + { + "packages": [ + lib_plankton.json.decode( + await lib_plankton.file.read("localization/de.json"), + await lib_plankton.file.read("localization/en.json"), + ), + ], + } + ); + if (args.help) { process.stdout.write( arg_handler.generate_help( diff --git a/source/types.ts b/source/types.ts index 14b2cb6..2174f3c 100644 --- a/source/types.ts +++ b/source/types.ts @@ -30,17 +30,6 @@ namespace _munin monthly = "monthly", } - - /** - */ - export type type_labels = { - head : string; - title : string; - time : string; - location : string; - events : string; - }; - /** */ -- 2.39.5 From 49b8b4189ec0f43f36d9e6f6af3d5f0b65e8b228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Tue, 1 Jul 2025 17:04:41 +0000 Subject: [PATCH 2/2] [task-343] --- data/localization/de.json | 17 -- data/localization/deu.json | 25 +++ data/localization/en.json | 17 -- data/localization/eng.json | 25 +++ libs/plankton/plankton.d.ts | 99 ++++++++- libs/plankton/plankton.js | 366 ++++++++++++++++++++++++++++++++- source/conf.ts | 123 ++++++----- source/logic.ts | 2 +- source/main.ts | 62 ++++-- source/targets/email.ts | 52 +++-- source/targets/telegram_bot.ts | 41 +++- source/types.ts | 5 +- 12 files changed, 701 insertions(+), 133 deletions(-) delete mode 100644 data/localization/de.json create mode 100644 data/localization/deu.json delete mode 100644 data/localization/en.json create mode 100644 data/localization/eng.json diff --git a/data/localization/de.json b/data/localization/de.json deleted file mode 100644 index 35e5036..0000000 --- a/data/localization/de.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "meta": { - "identifier": "de", - "name": "Deutsch" - }, - "tree": { - "event": "Termin", - "events": "Termine", - "reminder": "Erinnerung", - "title_long": "Titel", - "title_short": "was", - "time_long": "Datum und Uhrzeit", - "time_short": "wann", - "location_long": "Ort", - "location_short": "wo" - } -} diff --git a/data/localization/deu.json b/data/localization/deu.json new file mode 100644 index 0000000..ded9340 --- /dev/null +++ b/data/localization/deu.json @@ -0,0 +1,25 @@ +{ + "meta": { + "identifier": "deu", + "name": "Deutsch" + }, + "tree": { + "core.event.event": "Termin", + "core.event.events": "Termine", + "core.event.title.long": "Titel", + "core.event.title.short": "was", + "core.event.time.long": "Datum und Uhrzeit", + "core.event.time.short": "wann", + "core.event.location.long": "Ort", + "core.event.location.short": "wo", + "core.reminder.reminder": "Erinnerung", + "args.action.description": "auszuführende Aktion", + "args.conf_path.description": "Pfad zur Konfigurations-Datei", + "args.conf_schema.description": "nur das Konfigurations-Schema in einer spezifischen Version ausgeben (jüngste Version mittels '{{arg}}')", + "args.conf_expose.description": "die vervollständigte Konfiguration ausgeben", + "args.single_run.description": "nur einen Durchlauf ausführen", + "args.dry_run.description": "das Senden von Benachrichtigungen überspringen", + "args.help.description": "nur die Hilfe-Seite anzeigen", + "help.description": "sendet Erinnerungen zu anstehenden Terminen" + } +} diff --git a/data/localization/en.json b/data/localization/en.json deleted file mode 100644 index c8140d3..0000000 --- a/data/localization/en.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "meta": { - "identifier": "en", - "name": "English" - }, - "tree": { - "event": "event", - "events": "events", - "reminder": "reminder", - "title_long": "title", - "title_short": "what", - "time_long": "date and time", - "time_short": "when", - "location_long": "location", - "location_short": "where" - } -} diff --git a/data/localization/eng.json b/data/localization/eng.json new file mode 100644 index 0000000..9bd8702 --- /dev/null +++ b/data/localization/eng.json @@ -0,0 +1,25 @@ +{ + "meta": { + "identifier": "eng", + "name": "English" + }, + "tree": { + "core.event.event": "event", + "core.event.events": "events", + "core.event.title.long": "title", + "core.event.title.short": "what", + "core.event.time.long": "date and time", + "core.event.time.short": "when", + "core.event.location.long": "location", + "core.event.location.short": "where", + "core.reminder.reminder": "reminder", + "args.action.description": "what to do", + "args.conf_path.description": "path to configuration file", + "args.conf_schema.description": "only print the configuration schema in a specific version (latest version via argument '{{arg}}')", + "args.conf_expose.description": "whether to expose the full configuration", + "args.single_run.description": "whether to only execute one iteration at run", + "args.dry_run.description": "whether to skip the sending of reminders (logs will be written)", + "args.help.description": "only print the help page", + "help.description": "sends reminders about upcoming events" + } +} diff --git a/libs/plankton/plankton.d.ts b/libs/plankton/plankton.d.ts index 80a8f89..2c3ea8f 100644 --- a/libs/plankton/plankton.d.ts +++ b/libs/plankton/plankton.d.ts @@ -1,11 +1,11 @@ /** * @author fenris */ -declare type int = number; +type int = number; /** * @author fenris */ -declare type float = number; +type float = number; declare var process: any; declare var require: any; declare class Buffer { @@ -22,7 +22,7 @@ declare namespace lib_plankton.base { /** * @author fenris */ -declare type type_pseudopointer = { +type type_pseudopointer = { value: type_value; }; /** @@ -2701,6 +2701,99 @@ declare namespace lib_plankton.conf { */ function load_versioned(path: string, get_schema: ((version: string) => type_schema), migrations: Record>): Promise>; } +declare namespace lib_plankton.translate { + /** + * @author fenris + */ + type type_package_meta = { + identifier: string; + name?: string; + }; + /** + * @author fenris + */ + type type_package = { + meta: type_package_meta; + tree: { + [id: string]: string; + }; + }; + /** + * @desc the level of verbosity, specifiying how much output the system shall provide about its actions + * @author fenris + */ + var _verbosity: int; + /** + * @desc moves a language to the top of the order, making it the primary one + * @author fenris + */ + function promote(identifier: string): void; + /** + * @desc adds a package to the sytem + * @author fenris + */ + function add(package_: type_package): void; + /** + * @desc integrates a package to the system, i.e. creates a new one if none existed so far or merges with an existing one + * @author fenris + */ + function feed(package_: type_package): void; + /** + * @desc tries to retrieve a translation for a specific package identifier + * @author fenris + */ + function fetch(identifier: string, path: string, args?: { + [id: string]: string; + }): lib_plankton.pod.type_pod; + /** + * @desc retrieves a string by going through the order and trying to fetch it for the current entry + * @author fenris + * @todo rename to "get" + */ + function get_new(path: string, { "args": args, "preferred_language": preferred_language, "fallback": fallback, }?: { + args?: Record; + preferred_language?: (null | string); + fallback?: string; + }): string; + /** + * @desc retrieves a string by going through the order and trying to fetch it for the current entry + * @author fenris + * @deprecated use "get_new" + * @todo remove + */ + function get(path: string, args?: { + [id: string]: string; + }, fallback?: string): string; + /** + * @author fenris + */ + function list(): Array; + /** + * @author fenris + * @todo get rid of this; it's currenly needed only for the cdh-internal lib_completion + */ + function paths(): Array; + /** + * @author fenris + */ + function initialize({ "logprefix": logprefix, "verbosity": verbosity, "packages": packages, "order": order, "autopromote": autopromote, }?: { + logprefix?: string; + verbosity?: int; + packages?: Array; + order?: Array; + autopromote?: boolean; + }): Promise; +} +declare namespace lib_plankton.translate { + /** + * @author fenris + */ + function iso_639_1_to_iso_639_2(iso6391: string): string; + /** + * @author fenris + */ + function stance(str: string): string; +} declare namespace lib_plankton.args { /** */ diff --git a/libs/plankton/plankton.js b/libs/plankton/plankton.js index 450f4c3..f3c8734 100644 --- a/libs/plankton/plankton.js +++ b/libs/plankton/plankton.js @@ -1486,7 +1486,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -8060,6 +8060,370 @@ var lib_plankton; })(conf = lib_plankton.conf || (lib_plankton.conf = {})); })(lib_plankton || (lib_plankton = {})); /* +This file is part of »bacterio-plankton:translate«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:translate« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:translate« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:translate«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var translate; + (function (translate) { + /** + * @desc contains the sets of strings + * @author fenris + */ + var _packages = {}; + /** + * @desc specifies in which order the languages shall be queried; if getting a string from language #0 fails, the + * system tries to get it from language #1, and so on + * @author fenris + */ + var _order = []; + /** + * @desc whether to automatically promote the language of a newly added package + * @author fenris + */ + var _autopromote = false; + /** + * @desc the level of verbosity, specifiying how much output the system shall provide about its actions + * @author fenris + */ + translate._verbosity = 1; + /** + * @desc which initial string to use for log-outputs + * @author fenris + */ + var _logprefix = "[lib_translate]"; + /** + * @desc moves a language to the top of the order, making it the primary one + * @author fenris + */ + function promote(identifier) { + if (Object.keys(_packages).indexOf(identifier) < 0) { + if (translate._verbosity >= 1) { + console.warn(`${_logprefix} package '${identifier}' doesn't exist yet`); + } + } + let position = _order.indexOf(identifier); + if (position >= 0) { + if (translate._verbosity >= 2) { + console.info(`${_logprefix} '${identifier}' already in order; will promote it`); + } + _order.splice(position, 1); + } + _order.unshift(identifier); + if (translate._verbosity >= 2) { + console.info(`${_logprefix} order is now ${_order.toString()}`); + } + } + translate.promote = promote; + /** + * @desc adds a package to the sytem + * @author fenris + */ + function add(package_) { + let identifier = package_.meta.identifier; + if (identifier in _packages) { + if (translate._verbosity >= 1) { + console.warn(`${_logprefix} package '${identifier}' has already been added; will overwrite`); + } + } + else { + if (translate._verbosity >= 2) { + console.log(`${_logprefix} got package '${identifier}'`); + } + } + _packages[identifier] = package_; + if (_autopromote) { + promote(identifier); + } + } + translate.add = add; + /** + * @desc integrates a package to the system, i.e. creates a new one if none existed so far or merges with an existing one + * @author fenris + */ + function feed(package_) { + let identifier = package_.meta.identifier; + if (identifier in _packages) { + lib_plankton.object.patch(_packages[identifier].tree, package_.tree, { + "deep": true, + }); + } + else { + if (translate._verbosity >= 2) { + console.info(`${_logprefix} package '${identifier}' didn't exist so far; will create it now`); + } + add(package_); + } + } + translate.feed = feed; + /** + * @desc tries to retrieve a translation for a specific package identifier + * @author fenris + */ + function fetch(identifier, path, args = {}) { + if (!(identifier in _packages)) { + if (translate._verbosity >= 1) { + console.warn(`${_logprefix} no package '${identifier}'`); + } + return (lib_plankton.pod.make_empty()); + } + else { + // let str : string = lib_plankton.object.path_read(_packages[identifier].tree, path); + let str = _packages[identifier].tree[path]; + if (str == undefined) { + if (translate._verbosity >= 1) { + console.warn(`${_logprefix} string '${path}' missing in package '${identifier}'`); + } + return (lib_plankton.pod.make_empty()); + } + else { + // resolve references + { + let regexp_reference = new RegExp("#\\(([\\w\\.]*)(?:\\?(\\w+)=(\\w+)(?:&(\\w+)=(\\w+))*)?\\)"); + while (true) { + let matching = regexp_reference.exec(str); + if (matching != null) { + let path_ = matching[1]; + let args_ = {}; + if (translate._verbosity >= 2) { + // console.info(`${_logprefix} found reference to '${path_}' with args ${JSON.stringify(args_)}`); + console.info(`${_logprefix} found reference to '${path_}'`); + } + // parse args + { + for (let index = 2; index <= matching.length - 1; index += 2) { + let id = matching[index + 0]; + let value = matching[index + 1]; + if (id != undefined) { + args_[id] = value; + } + } + } + // fetch referenced string + { + let result_ = fetch(identifier, path_, args_); + if (lib_plankton.pod.is_filled(result_)) { + let front = str.slice(0, matching.index); + let back = str.slice(matching.index + matching[0].length); + str = (front + lib_plankton.pod.cull(result_) + back); + } + else { + return (lib_plankton.pod.make_empty()); + break; + } + } + } + else { + break; + } + } + } + // insert arguments + { + str = lib_plankton.string.coin(str, args); + } + return (lib_plankton.pod.make_filled(str)); + } + } + } + translate.fetch = fetch; + /** + * @desc retrieves a string by going through the order and trying to fetch it for the current entry + * @author fenris + * @todo rename to "get" + */ + function get_new(path, { "args": args = {}, "preferred_language": preferred_language = null, "fallback": fallback = null, } = {}) { + if (fallback == null) { + fallback = `{${path}}`; + } + if (translate._verbosity >= 2) { + console.info(`${_logprefix} getting translation for string '${path}' with arguments ${JSON.stringify(args)} …`); + } + let result = lib_plankton.pod.make_empty(); + const order = ((preferred_language === null) + ? + _order + : + ([preferred_language].concat(_order.filter(x => (x !== preferred_language))))); + const found = order.some(identifier => { + if (translate._verbosity >= 2) { + console.info(`${_logprefix} trying package '${identifier}' …`); + } + const result_ = fetch(identifier, path, args); + if (lib_plankton.pod.is_filled(result_)) { + result = result_; + return true; + } + else { + return false; + } + }); + if (found) { + const str = lib_plankton.pod.cull(result); + if (translate._verbosity >= 3) { + console.info(`${_logprefix} found translation: '${str}'`); + } + return str; + } + else { + const str = fallback; + if (translate._verbosity >= 1) { + console.warn(`${_logprefix} no package provides a translation for string '${path}'; will use the fallback translation '${str}'`); + } + return str; + } + } + translate.get_new = get_new; + /** + * @desc retrieves a string by going through the order and trying to fetch it for the current entry + * @author fenris + * @deprecated use "get_new" + * @todo remove + */ + function get(path, args = {}, fallback = null) { + return get_new(path, { + "args": args, + "fallback": fallback, + }); + } + translate.get = get; + /** + * @author fenris + */ + function list() { + return lib_plankton.object.to_array(_packages).map(x => x.value.meta); + } + translate.list = list; + /** + * @author fenris + * @todo get rid of this; it's currenly needed only for the cdh-internal lib_completion + */ + function paths() { + return lib_plankton.object.keys(lib_plankton.object.flatten(_packages[_order[0]].tree)); + } + translate.paths = paths; + /** + * @author fenris + */ + function initialize({ "logprefix": logprefix = undefined, "verbosity": verbosity = undefined, "packages": packages = [], "order": order = undefined, "autopromote": autopromote = undefined, } = {}) { + return (Promise.resolve(undefined) + // set variables + .then(_ => { + if (logprefix != undefined) + _logprefix = logprefix; + if (verbosity != undefined) + translate._verbosity = verbosity; + // _packages = {}; + if (order != undefined) + _order = order; + if (autopromote != undefined) + _autopromote = autopromote; + return Promise.resolve(undefined); + }) + // feed + .then(_ => { + packages.forEach(feed); + return Promise.resolve(undefined); + })); + } + translate.initialize = initialize; + })(translate = lib_plankton.translate || (lib_plankton.translate = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:translate«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:translate« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»bacterio-plankton:translate« is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:translate«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var translate; + (function (translate) { + /** + * @author fenris + */ + function iso_639_1_to_iso_639_2(iso6391) { + let mapping = { + "af": "afr", + "ar": "ara", + "bg": "bul", + "cs": "ces", + "da": "dan", + "de": "deu", + "el": "ell", + "en": "eng", + "eo": "epo", + "es": "esp", + "fa": "fas", + "fi": "fin", + "fr": "fra", + "hi": "hin", + "hr": "hrv", + "hu": "hun", + "is": "isl", + "it": "ita", + "ja": "jpn", + "ko": "kor", + "nb": "nob", + "nl": "nld", + "nn": "nno", + "pt": "por", + "pl": "pol", + "ro": "ron", + "ru": "rus", + "sk": "slk", + "sv": "swe", + "zh": "zho", + }; + return mapping[iso6391]; + } + translate.iso_639_1_to_iso_639_2 = iso_639_1_to_iso_639_2; + /** + * @author fenris + */ + function stance(str) { + let regexp = new RegExp("^translate:(.*)$"); + let matching = regexp.exec(str); + if (matching != null) { + return translate.get(matching[1]); + } + else { + return str; + } + } + translate.stance = stance; + })(translate = lib_plankton.translate || (lib_plankton.translate = {})); +})(lib_plankton || (lib_plankton = {})); +/* This file is part of »bacterio-plankton:args«. Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' diff --git a/source/conf.ts b/source/conf.ts index c43fb7f..8e0dff9 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -608,7 +608,7 @@ namespace _munin.conf } ); return { - "source": conf_v5.sources, + "sources": conf_v5.sources, "targets": conf_v5.targets, "settings": conf_v5.settings, }; @@ -954,6 +954,11 @@ namespace _munin.conf "items": schema_reminder(version), "default": default_reminder(version), }, + "language": { + "nullable": false, + "type": "string", + "default": "deu" + }, }, "additionalProperties": false, "required": [ @@ -992,54 +997,32 @@ namespace _munin.conf "data": { "nullable": false, "type": "object", - "properties": Object.assign( - { - "bot_token": { - "nullable": false, - "type": "string", - }, - "chat_id": { - "nullable": false, - "type": "integer", - }, - "hide_tags": { - "nullable": false, - "type": "boolean", - "default": false, - }, - "reminders": { - "nullable": false, - "type": "array", - "items": schema_reminder(version), - "default": default_reminder(version), - }, + "properties": { + "bot_token": { + "nullable": false, + "type": "string", }, - (() => { - switch (version) - { - case "1": - case "2": - case "3": - case "4": - case "5": - { - return {}; - break; - } - default: - { - return { - "language": { - "nullable": false, - "type": "string", - "default": "de" - }, - }; - break; - } - } - }) () - ), + "chat_id": { + "nullable": false, + "type": "integer", + }, + "hide_tags": { + "nullable": false, + "type": "boolean", + "default": false, + }, + "reminders": { + "nullable": false, + "type": "array", + "items": schema_reminder(version), + "default": default_reminder(version), + }, + "language": { + "nullable": false, + "type": "string", + "default": "deu" + }, + }, "additionalProperties": false, "required": [ "bot_token", @@ -1117,6 +1100,50 @@ namespace _munin.conf } + /** + */ + function schema_labels( + version : string + ) : lib_plankton.conf.type_schema + { + return { + "nullable": false, + "type": "object", + "properties": { + "head": { + "nullable": false, + "type": "string", + "default": "Termin-Erinnerung" + }, + "title": { + "nullable": false, + "type": "string", + "default": "was" + }, + "time": { + "nullable": false, + "type": "string", + "default": "wann" + }, + "location": { + "nullable": false, + "type": "string", + "default": "wo" + }, + "events": { + "nullable": false, + "type": "string", + "default": "Termine" + }, + }, + "additionalProperties": false, + "required": [ + ], + "default": {} + }; + } + + /** */ export function schema( diff --git a/source/logic.ts b/source/logic.ts index 2f5c874..90c206d 100644 --- a/source/logic.ts +++ b/source/logic.ts @@ -203,7 +203,7 @@ namespace _munin.logic { try { - await target.send(conf.labels, events); + await target.send(events); } catch (error) { diff --git a/source/main.ts b/source/main.ts index fd85b7c..3bbb69e 100644 --- a/source/main.ts +++ b/source/main.ts @@ -27,6 +27,31 @@ namespace _munin args_raw : Array ): Promise { + // init + const language_codes : Array = [ + "deu", + "eng", + ]; + const packages = await Promise.all( + language_codes + .map>( + code => ( + Promise.resolve(code) + .then(code => Promise.resolve(lib_plankton.string.coin("data/localization/{{code}}.json", {"code": code}))) + .then(path => lib_plankton.file.read(path)) + .then(content => Promise.resolve(lib_plankton.json.decode(content))) + ) + ) + ); + await lib_plankton.translate.initialize( + { + "verbosity": 1, + "packages": packages, + "order": language_codes, + "autopromote": false, + } + ); + // args const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler( { @@ -35,7 +60,12 @@ namespace _munin "type": lib_plankton.args.enum_type.string, "mode": lib_plankton.args.enum_mode.replace, "default": "run", - "info": "what to do : test | run", + "info": lib_plankton.string.coin( + "{{core}} : test | run", + { + "core": lib_plankton.translate.get("args.action.description"), + } + ), "name": "action", }), "conf_path": lib_plankton.args.class_argument.volatile({ @@ -44,7 +74,7 @@ namespace _munin "type": lib_plankton.args.enum_type.string, "mode": lib_plankton.args.enum_mode.replace, "default": "munin.json", - "info": "path to configuration file", + "info": lib_plankton.translate.get("args.conf_path.description"), "name": "conf-path", }), "conf_schema": lib_plankton.args.class_argument.volatile({ @@ -53,7 +83,12 @@ namespace _munin "type": lib_plankton.args.enum_type.string, "mode": lib_plankton.args.enum_mode.replace, "default": "", - "info": "only print the configuration schema in a specific version (latest version via argument '_')", + "info": lib_plankton.string.coin( + lib_plankton.translate.get("args.conf_schema.description"), + { + "arg": "_", + } + ), "name": "conf-schema", }), "conf_expose": lib_plankton.args.class_argument.volatile({ @@ -62,7 +97,7 @@ namespace _munin "type": lib_plankton.args.enum_type.boolean, "mode": lib_plankton.args.enum_mode.replace, "default": false, - "info": "whether to expose the full configuration", + "info": lib_plankton.translate.get("args.conf_expose.description"), "name": "conf-expose", }), "single_run": lib_plankton.args.class_argument.volatile({ @@ -71,7 +106,7 @@ namespace _munin "type": lib_plankton.args.enum_type.boolean, "mode": lib_plankton.args.enum_mode.replace, "default": false, - "info": "whether to only execute one iteration at run", + "info": lib_plankton.translate.get("args.single_run.description"), "name": "single-run", }), "verbosity": lib_plankton.args.class_argument.volatile({ @@ -89,7 +124,7 @@ namespace _munin "type": lib_plankton.args.enum_type.boolean, "mode": lib_plankton.args.enum_mode.replace, "default": false, - "info": "whether to skip the sending of reminders (logs will be written)", + "info": lib_plankton.translate.get("args.dry_run.description"), "name": "dry-run", }), "help": lib_plankton.args.class_argument.volatile({ @@ -98,7 +133,7 @@ namespace _munin "type": lib_plankton.args.enum_type.boolean, "mode": lib_plankton.args.enum_mode.replace, "default": false, - "info": "alias for action 'help'", + "info": lib_plankton.translate.get("args.help.description"), "name": "help", }), } @@ -108,23 +143,12 @@ namespace _munin args_raw.join(" ") ); - await lib_plankton.translate.initialize( - { - "packages": [ - lib_plankton.json.decode( - await lib_plankton.file.read("localization/de.json"), - await lib_plankton.file.read("localization/en.json"), - ), - ], - } - ); - if (args.help) { process.stdout.write( arg_handler.generate_help( { "programname": "munin", - "description": "sends reminders about upcoming events", + "description": lib_plankton.translate.get("help.description"), "executable": "node build/munin", } ) diff --git a/source/targets/email.ts b/source/targets/email.ts index 4e29c7c..2b00d4d 100644 --- a/source/targets/email.ts +++ b/source/targets/email.ts @@ -32,21 +32,43 @@ namespace _munin.targets.email receivers : Array; hide_tags : boolean; reminders : Array<_munin.type_reminder>; + language : string; }; + /** + */ + function get_translation( + parameters : type_parameters, + path : string + ) : string + { + return lib_plankton.translate.get_new( + path, + { + "preferred_language": parameters.language, + } + ); + } + + /** */ function summarize_event( parameters : type_parameters, - labels : _munin.type_labels, event : _munin.type_event ) : string { return lib_plankton.string.coin( "[{{head}}] {{date}} : {{macro_tags}}{{title}}", { - "head": labels.head, + "head": lib_plankton.string.coin( + "{{event}}-{{reminder}}", + { + "event": get_translation(parameters, "core.event.event").toLowerCase(), + "reminder": get_translation(parameters, "core.reminder.reminder").toLowerCase(), + } + ), "date": lib_plankton.pit.date_format( event.begin.date ), @@ -67,14 +89,13 @@ namespace _munin.targets.email */ function render_event( parameters : type_parameters, - labels : _munin.type_labels, event : _munin.type_event ) : string { return lib_plankton.string.coin( "{{title_label}} | {{macro_tags}}{{title_value}}\n{{time_label}} | {{time_value}}{{macro_location}}{{macro_description}}", { - "title_label": labels.title.toUpperCase(), + "title_label": get_translation(parameters, "core.event.title.short").toUpperCase(), "macro_tags": ( (parameters.hide_tags || (event.tags === null)) ? @@ -83,7 +104,7 @@ namespace _munin.targets.email (event.tags.map(tag => ("{" + tag + "}")).join(" ") + " ") ), "title_value": event.title, - "time_label": labels.time.toUpperCase(), + "time_label": get_translation(parameters, "core.event.time.short").toUpperCase(), "time_value": lib_plankton.pit.timespan_format( event.begin, event.end, @@ -99,7 +120,7 @@ namespace _munin.targets.email lib_plankton.string.coin( "\n{{location_label}} | {{location_value}}", { - "location_label": labels.location.toUpperCase(), + "location_label": get_translation(parameters, "core.event.location.short").toUpperCase(), "location_value": event.location, } ) @@ -126,7 +147,6 @@ namespace _munin.targets.email */ async function send( parameters : type_parameters, - labels : _munin.type_labels, events : Array<_munin.type_event> ) : Promise { @@ -142,21 +162,27 @@ namespace _munin.targets.email ( (events.length === 1) ? - summarize_event(parameters, labels, events[0]) + summarize_event(parameters, events[0]) : lib_plankton.string.coin( "[{{head}}] {{count}} {{events}}", { - "head": labels.head, + "head": lib_plankton.string.coin( + "{{event}}-{{reminder}}", + { + "event": get_translation(parameters, "core.event.event").toLowerCase(), + "reminder": get_translation(parameters, "core.reminder.reminder").toLowerCase(), + } + ), "count": events.length.toFixed(0), - "events": labels.events, + "events": get_translation(parameters, "core.event.events"), } ) ), ( events - .map(event => render_event(parameters, labels, event)) - .join("\n\n---\n\n") + .map(event => render_event(parameters, event)) + .join("\n\n--------\n\n") ) ); } @@ -176,7 +202,7 @@ namespace _munin.targets.email "receivers": parameters.receivers.join(","), } ), - "send": (labels, events) => send(parameters, labels, events), + "send": (events) => send(parameters, events), }; } diff --git a/source/targets/telegram_bot.ts b/source/targets/telegram_bot.ts index f46c164..e4ecf54 100644 --- a/source/targets/telegram_bot.ts +++ b/source/targets/telegram_bot.ts @@ -28,14 +28,30 @@ namespace _munin.targets.telegram_bot chat_id : int; hide_tags : boolean; reminders : Array<_munin.type_reminder>; + language : string; }; + /** + */ + function get_translation( + parameters : type_parameters, + path : string + ) : string + { + return lib_plankton.translate.get_new( + path, + { + "preferred_language": parameters.language, + } + ); + } + + /** */ function render_event( parameters : type_parameters, - labels : _munin.type_labels, event : _munin.type_event ) : string { @@ -49,9 +65,9 @@ namespace _munin.targets.telegram_bot : (event.tags.map(tag => ("{" + tag + "}")).join(" ") + " ") ), - "title_label": labels.title.toUpperCase(), + "title_label": get_translation(parameters, "core.event.title.short").toUpperCase(), "title_value": event.title, - "time_label": labels.time.toUpperCase(), + "time_label": get_translation(parameters, "core.event.time.short").toUpperCase(), "time_value": lib_plankton.pit.timespan_format( event.begin, event.end, @@ -67,7 +83,7 @@ namespace _munin.targets.telegram_bot lib_plankton.string.coin( "\n{{location_label}} | {{location_value}}", { - "location_label": labels.location.toUpperCase(), + "location_label": get_translation(parameters, "core.event.location.short").toUpperCase(), "location_value": event.location, } ) @@ -93,7 +109,6 @@ namespace _munin.targets.telegram_bot */ async function send( parameters : type_parameters, - labels : _munin.type_labels, events : Array<_munin.type_event> ) : Promise { @@ -103,7 +118,13 @@ namespace _munin.targets.telegram_bot lib_plankton.string.coin( "*{{head_core}}{{head_extra}}*\n\n{{events}}", { - "head_core": labels.head, + "head_core": lib_plankton.string.coin( + "{{event}}-{{reminder}}", + { + "event": lib_plankton.string.capitalize(get_translation(parameters, "core.event.event")), + "reminder": lib_plankton.string.capitalize(get_translation(parameters, "core.reminder.reminder")), + } + ), "head_extra": ( (events.length <= 1) ? @@ -113,14 +134,14 @@ namespace _munin.targets.telegram_bot " ({{count}} {{events}})", { "count": events.length.toFixed(0), - "events": labels.events, + "events": get_translation(parameters, "core.event.events"), } ) ), "events": ( events - .map(event => render_event(parameters, labels, event)) - .join("\n\n---\n\n") + .map(event => render_event(parameters, event)) + .join("\n\n--------\n\n") ), } ), @@ -145,7 +166,7 @@ namespace _munin.targets.telegram_bot "chat_id": parameters.chat_id.toFixed(0), } ), - "send": (labels, events) => send(parameters, labels, events), + "send": (events) => send(parameters, events), }; } diff --git a/source/types.ts b/source/types.ts index 2174f3c..4fe4250 100644 --- a/source/types.ts +++ b/source/types.ts @@ -72,10 +72,7 @@ namespace _munin reminders : Array; show : (() => string); send : ( - ( - labels : type_labels, - events : Array - ) + (events : Array) => Promise ); -- 2.39.5