@schukai/monster 4.26.0 → 4.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/package.json +1 -1
- package/source/components/form/digits.mjs +12 -1
- package/source/dom/customelement.mjs +1 -0
- package/source/i18n/formatter.mjs +1 -1
- package/source/i18n/translations.mjs +214 -212
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
+
## [4.28.0] - 2025-07-04
|
6
|
+
|
7
|
+
### Add Features
|
8
|
+
|
9
|
+
- Improve formatting and clarity in translation handling
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
## [4.27.0] - 2025-07-03
|
14
|
+
|
15
|
+
### Add Features
|
16
|
+
|
17
|
+
- Increase digits option and improve attribute observation [#330](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/330)
|
18
|
+
|
19
|
+
|
20
|
+
|
5
21
|
## [4.26.0] - 2025-07-03
|
6
22
|
|
7
23
|
### Add Features
|
package/package.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.2","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.
|
1
|
+
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.2","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.28.0"}
|
@@ -132,7 +132,7 @@ class Digits extends CustomControl {
|
|
132
132
|
main: getTemplate(),
|
133
133
|
},
|
134
134
|
|
135
|
-
digits:
|
135
|
+
digits: 6,
|
136
136
|
characterSet: "0123456789",
|
137
137
|
|
138
138
|
digitsControls: [],
|
@@ -184,13 +184,20 @@ function initOptionObserver() {
|
|
184
184
|
const self = this;
|
185
185
|
|
186
186
|
let lastValue = this.getOption("value");
|
187
|
+
let lastDigits = this.getOption("digits");
|
187
188
|
|
188
189
|
self.attachObserver(
|
189
190
|
new Observer(function () {
|
191
|
+
|
190
192
|
if (lastValue !== self.getOption("value")) {
|
191
193
|
lastValue = self.getOption("value");
|
192
194
|
updateDigitControls.call(self);
|
193
195
|
}
|
196
|
+
|
197
|
+
if (lastDigits !== self.getOption("digits")) {
|
198
|
+
lastDigits = self.getOption("digits");
|
199
|
+
updateDigitControls.call(self);
|
200
|
+
}
|
194
201
|
}),
|
195
202
|
);
|
196
203
|
}
|
@@ -237,6 +244,10 @@ function initEventHandler() {
|
|
237
244
|
const self = this;
|
238
245
|
const element = this[digitsElementSymbol];
|
239
246
|
|
247
|
+
// this[attributeObserverSymbol]['data-monster-option-digits'] = () => {
|
248
|
+
// this.setOption("digits", );
|
249
|
+
// }
|
250
|
+
|
240
251
|
element.addEventListener("keydown", function (event) {
|
241
252
|
if (event.target.tagName !== "INPUT") return;
|
242
253
|
const inputControl = event.target;
|
@@ -41,7 +41,7 @@ class Formatter extends TextFormatter {
|
|
41
41
|
* @param {object} object
|
42
42
|
* @param {Translations} translation
|
43
43
|
* @param {object} [options]
|
44
|
-
* @throws {TypeError} value is not
|
44
|
+
* @throws {TypeError} value is not an object
|
45
45
|
*/
|
46
46
|
constructor(object, translation, options) {
|
47
47
|
super(object, options);
|
@@ -12,21 +12,21 @@
|
|
12
12
|
* SPDX-License-Identifier: AGPL-3.0
|
13
13
|
*/
|
14
14
|
|
15
|
-
import {
|
16
|
-
import {
|
17
|
-
import {
|
18
|
-
import {
|
19
|
-
import {
|
20
|
-
import {
|
15
|
+
import {instanceSymbol} from "../constants.mjs";
|
16
|
+
import {getLinkedObjects, hasObjectLink} from "../dom/attributes.mjs";
|
17
|
+
import {ATTRIBUTE_OBJECTLINK} from "../dom/constants.mjs";
|
18
|
+
import {getDocument} from "../dom/util.mjs";
|
19
|
+
import {Base} from "../types/base.mjs";
|
20
|
+
import {isObject, isString} from "../types/is.mjs";
|
21
21
|
import {
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
validateInteger,
|
23
|
+
validateObject,
|
24
|
+
validateString,
|
25
25
|
} from "../types/validate.mjs";
|
26
|
-
import {
|
27
|
-
import {
|
26
|
+
import {Locale, parseLocale} from "./locale.mjs";
|
27
|
+
import {translationsLinkSymbol} from "./provider.mjs";
|
28
28
|
|
29
|
-
export {
|
29
|
+
export {Translations, getDocumentTranslations};
|
30
30
|
|
31
31
|
/**
|
32
32
|
* With this class you can manage translations and access the keys.
|
@@ -38,176 +38,178 @@ export { Translations, getDocumentTranslations };
|
|
38
38
|
* @see https://datatracker.ietf.org/doc/html/rfc3066
|
39
39
|
*/
|
40
40
|
class Translations extends Base {
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
41
|
+
/**
|
42
|
+
*
|
43
|
+
* @param {Locale} locale
|
44
|
+
*/
|
45
|
+
constructor(locale) {
|
46
|
+
super();
|
47
|
+
|
48
|
+
if (locale instanceof Locale) {
|
49
|
+
this.locale = locale;
|
50
|
+
} else if (isString(locale)) {
|
51
|
+
this.locale = parseLocale(validateString(locale));
|
52
|
+
} else {
|
53
|
+
this.locale = getDocumentTranslations()
|
54
|
+
}
|
55
|
+
|
56
|
+
this.storage = new Map();
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* This method is called by the `instanceof` operator.
|
61
|
+
* @return {symbol}
|
62
|
+
* @since 3.27.0
|
63
|
+
*/
|
64
|
+
static get [instanceSymbol]() {
|
65
|
+
return Symbol.for("@schukai/monster/i18n/translations@@instance");
|
66
|
+
}
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Fetches a text using the specified key.
|
70
|
+
* If no suitable key is found, `defaultText` is taken.
|
71
|
+
*
|
72
|
+
* @param {string} key
|
73
|
+
* @param {string|undefined} defaultText
|
74
|
+
* @return {string}
|
75
|
+
* @throws {Error} key not found
|
76
|
+
*/
|
77
|
+
getText(key, defaultText) {
|
78
|
+
if (!this.storage.has(key)) {
|
79
|
+
if (defaultText === undefined) {
|
80
|
+
throw new Error(`key ${key} not found`);
|
81
|
+
}
|
82
|
+
|
83
|
+
return validateString(defaultText);
|
84
|
+
}
|
85
|
+
|
86
|
+
const r = this.storage.get(key);
|
87
|
+
if (isObject(r)) {
|
88
|
+
return this.getPluralRuleText(key, "other", defaultText);
|
89
|
+
}
|
90
|
+
|
91
|
+
return this.storage.get(key);
|
92
|
+
}
|
93
|
+
|
94
|
+
/**
|
95
|
+
* A number `count` can be passed to this method. In addition to a number, one of the keywords can also be passed directly.
|
96
|
+
* "zero", "one", "two", "few", "many" and "other". Remember: not every language has all rules.
|
97
|
+
*
|
98
|
+
* The appropriate text for this number is then selected. If no suitable key is found, `defaultText` is taken.
|
99
|
+
*
|
100
|
+
* @param {string} key
|
101
|
+
* @param {integer|string} count
|
102
|
+
* @param {string|undefined} defaultText
|
103
|
+
* @return {string}
|
104
|
+
*/
|
105
|
+
getPluralRuleText(key, count, defaultText) {
|
106
|
+
if (!this.storage.has(key)) {
|
107
|
+
return validateString(defaultText);
|
108
|
+
}
|
109
|
+
|
110
|
+
const r = validateObject(this.storage.get(key));
|
111
|
+
|
112
|
+
let keyword;
|
113
|
+
if (isString(count)) {
|
114
|
+
keyword = count.toLocaleString();
|
115
|
+
} else {
|
116
|
+
count = validateInteger(count);
|
117
|
+
if (count === 0) {
|
118
|
+
// special handling for zero count
|
119
|
+
if (r.hasOwnProperty("zero")) {
|
120
|
+
return validateString(r?.zero);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
keyword = new Intl.PluralRules(this.locale.toString()).select(
|
125
|
+
validateInteger(count),
|
126
|
+
);
|
127
|
+
}
|
128
|
+
|
129
|
+
if (r.hasOwnProperty(keyword)) {
|
130
|
+
return validateString(r[keyword]);
|
131
|
+
}
|
132
|
+
|
133
|
+
// @deprecated since 2023-03-14
|
134
|
+
// DEFAULT_KEY is undefined
|
135
|
+
// if (r.hasOwnProperty(DEFAULT_KEY)) {
|
136
|
+
// return validateString(r[DEFAULT_KEY]);
|
137
|
+
// }
|
138
|
+
|
139
|
+
return validateString(defaultText);
|
140
|
+
}
|
141
|
+
|
142
|
+
/**
|
143
|
+
* Set a text for a key
|
144
|
+
*
|
145
|
+
* ```
|
146
|
+
* translations.setText("text1", "Make my day!");
|
147
|
+
* // plural rules
|
148
|
+
* translations.setText("text6", {
|
149
|
+
* "zero": "There are no files on Disk.",
|
150
|
+
* "one": "There is one file on Disk.",
|
151
|
+
* "other": "There are files on Disk."
|
152
|
+
* "default": "There are files on Disk."
|
153
|
+
* });
|
154
|
+
* ```
|
155
|
+
*
|
156
|
+
* @param {string} key
|
157
|
+
* @param {string|object} text
|
158
|
+
* @return {Translations}
|
159
|
+
* @throws {TypeError} value is not a string or object
|
160
|
+
*/
|
161
|
+
setText(key, text) {
|
162
|
+
if (isString(text) || isObject(text)) {
|
163
|
+
this.storage.set(validateString(key), text);
|
164
|
+
return this;
|
165
|
+
}
|
166
|
+
|
167
|
+
throw new TypeError("value is not a string or object");
|
168
|
+
}
|
169
|
+
|
170
|
+
/**
|
171
|
+
* This method can be used to transfer overlays from an object. The keys are transferred, and the values are entered
|
172
|
+
* as text.
|
173
|
+
*
|
174
|
+
* The values can either be character strings or, in the case of texts with plural forms, objects. The plural forms
|
175
|
+
* must be stored as text via a standard key "zero", "one", "two", "few", "many" and "other".
|
176
|
+
*
|
177
|
+
* Additionally, the key default can be specified, which will be used if no other key fits.
|
178
|
+
*
|
179
|
+
* In some languages, like for example in German, there is no own more number at the value 0. In these languages,
|
180
|
+
* the function applies additionally zero.
|
181
|
+
*
|
182
|
+
* ```
|
183
|
+
* translations.assignTranslations({
|
184
|
+
* "text1": "Make my day!",
|
185
|
+
* "text2": "I'll be back!",
|
186
|
+
* "text6": {
|
187
|
+
* "zero": "There are no files on Disk.",
|
188
|
+
* "one": "There is one file on Disk.",
|
189
|
+
* "other": "There are files on Disk."
|
190
|
+
* "default": "There are files on Disk."
|
191
|
+
* });
|
192
|
+
* ```
|
193
|
+
*
|
194
|
+
* @param {object} translations
|
195
|
+
* @return {Translations}
|
196
|
+
*/
|
197
|
+
assignTranslations(translations) {
|
198
|
+
validateObject(translations);
|
199
|
+
|
200
|
+
if (translations instanceof Translations) {
|
201
|
+
translations.storage.forEach((v, k) => {
|
202
|
+
this.setText(k, v);
|
203
|
+
});
|
204
|
+
return this;
|
205
|
+
}
|
206
|
+
|
207
|
+
for (const [k, v] of Object.entries(translations)) {
|
208
|
+
this.setText(k, v);
|
209
|
+
}
|
210
|
+
|
211
|
+
return this;
|
212
|
+
}
|
211
213
|
}
|
212
214
|
|
213
215
|
/**
|
@@ -221,34 +223,34 @@ class Translations extends Base {
|
|
221
223
|
* @throws {Error} Missing translations.
|
222
224
|
*/
|
223
225
|
function getDocumentTranslations(element) {
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
226
|
+
const d = getDocument();
|
227
|
+
|
228
|
+
if (!(element instanceof HTMLElement)) {
|
229
|
+
element = d.querySelector(
|
230
|
+
`[${ATTRIBUTE_OBJECTLINK}~="${translationsLinkSymbol.toString()}"]`,
|
231
|
+
);
|
232
|
+
if (element === null) {
|
233
|
+
throw new Error(
|
234
|
+
"Cannot find the element with translations. Add the translation object to the document.",
|
235
|
+
);
|
236
|
+
}
|
237
|
+
}
|
238
|
+
|
239
|
+
if (!(element instanceof HTMLElement)) {
|
240
|
+
throw new Error("Element is not an HTMLElement.");
|
241
|
+
}
|
242
|
+
|
243
|
+
if (!hasObjectLink(element, translationsLinkSymbol)) {
|
244
|
+
throw new Error("This element has no translations.");
|
245
|
+
}
|
246
|
+
|
247
|
+
const obj = getLinkedObjects(element, translationsLinkSymbol);
|
248
|
+
|
249
|
+
for (const t of obj) {
|
250
|
+
if (t instanceof Translations) {
|
251
|
+
return t;
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
throw new Error("Missing translations.");
|
254
256
|
}
|