@schukai/monster 4.38.4 → 4.38.5

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.
@@ -19,9 +19,9 @@ import { getDocument } from "../dom/util.mjs";
19
19
  import { Base } from "../types/base.mjs";
20
20
  import { isObject, isString } from "../types/is.mjs";
21
21
  import {
22
- validateInteger,
23
- validateObject,
24
- validateString,
22
+ validateInteger,
23
+ validateObject,
24
+ validateString,
25
25
  } from "../types/validate.mjs";
26
26
  import { Locale, parseLocale } from "./locale.mjs";
27
27
  import { translationsLinkSymbol } from "./provider.mjs";
@@ -40,185 +40,185 @@ export { Translations, getDocumentTranslations };
40
40
  * @see https://datatracker.ietf.org/doc/html/rfc3066
41
41
  */
42
42
  class Translations extends Base {
43
- /**
44
- *
45
- * @param {Locale} locale
46
- */
47
- constructor(locale) {
48
- super();
49
-
50
- try {
51
- if (locale instanceof Locale) {
52
- this.locale = locale;
53
- } else if (isString(locale)) {
54
- this.locale = parseLocale(validateString(locale));
55
- } else {
56
- this.locale = getLocaleOfDocument();
57
- }
58
- } catch (e) {
59
- } finally {
60
- if (!(this.locale instanceof Locale)) {
61
- this.locale = new Locale("en");
62
- }
63
- }
64
-
65
- this.storage = new Map();
66
- }
67
-
68
- /**
69
- * This method is called by the `instanceof` operator.
70
- * @return {symbol}
71
- * @since 3.27.0
72
- */
73
- static get [instanceSymbol]() {
74
- return Symbol.for("@schukai/monster/i18n/translations@@instance");
75
- }
76
-
77
- /**
78
- * Fetches a text using the specified key.
79
- * If no suitable key is found, `defaultText` is taken.
80
- *
81
- * @param {string} key
82
- * @param {string|undefined} defaultText
83
- * @return {string}
84
- * @throws {Error} key not found
85
- */
86
- getText(key, defaultText) {
87
- if (!this.storage.has(key)) {
88
- if (defaultText === undefined) {
89
- throw new Error(`key ${key} not found`);
90
- }
91
-
92
- return validateString(defaultText);
93
- }
94
-
95
- const r = this.storage.get(key);
96
- if (isObject(r)) {
97
- return this.getPluralRuleText(key, "other", defaultText);
98
- }
99
-
100
- return this.storage.get(key);
101
- }
102
-
103
- /**
104
- * A number `count` can be passed to this method. In addition to a number, one of the keywords can also be passed directly.
105
- * "zero", "one", "two", "few", "many" and "other". Remember: not every language has all rules.
106
- *
107
- * The appropriate text for this number is then selected. If no suitable key is found, `defaultText` is taken.
108
- *
109
- * @param {string} key
110
- * @param {integer|string} count
111
- * @param {string|undefined} defaultText
112
- * @return {string}
113
- */
114
- getPluralRuleText(key, count, defaultText) {
115
- if (!this.storage.has(key)) {
116
- return validateString(defaultText);
117
- }
118
-
119
- const r = validateObject(this.storage.get(key));
120
-
121
- let keyword;
122
- if (isString(count)) {
123
- keyword = count.toLocaleString();
124
- } else {
125
- count = validateInteger(count);
126
- if (count === 0) {
127
- // special handling for zero count
128
- if (r.hasOwnProperty("zero")) {
129
- return validateString(r?.zero);
130
- }
131
- }
132
-
133
- keyword = new Intl.PluralRules(this.locale.toString()).select(
134
- validateInteger(count),
135
- );
136
- }
137
-
138
- if (r.hasOwnProperty(keyword)) {
139
- return validateString(r[keyword]);
140
- }
141
-
142
- // @deprecated since 2023-03-14
143
- // DEFAULT_KEY is undefined
144
- // if (r.hasOwnProperty(DEFAULT_KEY)) {
145
- // return validateString(r[DEFAULT_KEY]);
146
- // }
147
-
148
- return validateString(defaultText);
149
- }
150
-
151
- /**
152
- * Set a text for a key
153
- *
154
- * ```
155
- * translations.setText("text1", "Make my day!");
156
- * // plural rules
157
- * translations.setText("text6", {
158
- * "zero": "There are no files on Disk.",
159
- * "one": "There is one file on Disk.",
160
- * "other": "There are files on Disk."
161
- * "default": "There are files on Disk."
162
- * });
163
- * ```
164
- *
165
- * @param {string} key
166
- * @param {string|object} text
167
- * @return {Translations}
168
- * @throws {TypeError} value is not a string or object
169
- */
170
- setText(key, text) {
171
- if (isString(text) || isObject(text)) {
172
- this.storage.set(validateString(key), text);
173
- return this;
174
- }
175
-
176
- throw new TypeError("value is not a string or object");
177
- }
178
-
179
- /**
180
- * This method can be used to transfer overlays from an object. The keys are transferred, and the values are entered
181
- * as text.
182
- *
183
- * The values can either be character strings or, in the case of texts with plural forms, objects. The plural forms
184
- * must be stored as text via a standard key "zero", "one", "two", "few", "many" and "other".
185
- *
186
- * Additionally, the key default can be specified, which will be used if no other key fits.
187
- *
188
- * In some languages, like for example in German, there is no own more number at the value 0. In these languages,
189
- * the function applies additionally zero.
190
- *
191
- * ```
192
- * translations.assignTranslations({
193
- * "text1": "Make my day!",
194
- * "text2": "I'll be back!",
195
- * "text6": {
196
- * "zero": "There are no files on Disk.",
197
- * "one": "There is one file on Disk.",
198
- * "other": "There are files on Disk."
199
- * "default": "There are files on Disk."
200
- * });
201
- * ```
202
- *
203
- * @param {object} translations
204
- * @return {Translations}
205
- */
206
- assignTranslations(translations) {
207
- validateObject(translations);
208
-
209
- if (translations instanceof Translations) {
210
- translations.storage.forEach((v, k) => {
211
- this.setText(k, v);
212
- });
213
- return this;
214
- }
215
-
216
- for (const [k, v] of Object.entries(translations)) {
217
- this.setText(k, v);
218
- }
219
-
220
- return this;
221
- }
43
+ /**
44
+ *
45
+ * @param {Locale} locale
46
+ */
47
+ constructor(locale) {
48
+ super();
49
+
50
+ try {
51
+ if (locale instanceof Locale) {
52
+ this.locale = locale;
53
+ } else if (isString(locale)) {
54
+ this.locale = parseLocale(validateString(locale));
55
+ } else {
56
+ this.locale = getLocaleOfDocument();
57
+ }
58
+ } catch (e) {
59
+ } finally {
60
+ if (!(this.locale instanceof Locale)) {
61
+ this.locale = new Locale("en");
62
+ }
63
+ }
64
+
65
+ this.storage = new Map();
66
+ }
67
+
68
+ /**
69
+ * This method is called by the `instanceof` operator.
70
+ * @return {symbol}
71
+ * @since 3.27.0
72
+ */
73
+ static get [instanceSymbol]() {
74
+ return Symbol.for("@schukai/monster/i18n/translations@@instance");
75
+ }
76
+
77
+ /**
78
+ * Fetches a text using the specified key.
79
+ * If no suitable key is found, `defaultText` is taken.
80
+ *
81
+ * @param {string} key
82
+ * @param {string|undefined} defaultText
83
+ * @return {string}
84
+ * @throws {Error} key not found
85
+ */
86
+ getText(key, defaultText) {
87
+ if (!this.storage.has(key)) {
88
+ if (defaultText === undefined) {
89
+ throw new Error(`key ${key} not found`);
90
+ }
91
+
92
+ return validateString(defaultText);
93
+ }
94
+
95
+ const r = this.storage.get(key);
96
+ if (isObject(r)) {
97
+ return this.getPluralRuleText(key, "other", defaultText);
98
+ }
99
+
100
+ return this.storage.get(key);
101
+ }
102
+
103
+ /**
104
+ * A number `count` can be passed to this method. In addition to a number, one of the keywords can also be passed directly.
105
+ * "zero", "one", "two", "few", "many" and "other". Remember: not every language has all rules.
106
+ *
107
+ * The appropriate text for this number is then selected. If no suitable key is found, `defaultText` is taken.
108
+ *
109
+ * @param {string} key
110
+ * @param {integer|string} count
111
+ * @param {string|undefined} defaultText
112
+ * @return {string}
113
+ */
114
+ getPluralRuleText(key, count, defaultText) {
115
+ if (!this.storage.has(key)) {
116
+ return validateString(defaultText);
117
+ }
118
+
119
+ const r = validateObject(this.storage.get(key));
120
+
121
+ let keyword;
122
+ if (isString(count)) {
123
+ keyword = count.toLocaleString();
124
+ } else {
125
+ count = validateInteger(count);
126
+ if (count === 0) {
127
+ // special handling for zero count
128
+ if (r.hasOwnProperty("zero")) {
129
+ return validateString(r?.zero);
130
+ }
131
+ }
132
+
133
+ keyword = new Intl.PluralRules(this.locale.toString()).select(
134
+ validateInteger(count),
135
+ );
136
+ }
137
+
138
+ if (r.hasOwnProperty(keyword)) {
139
+ return validateString(r[keyword]);
140
+ }
141
+
142
+ // @deprecated since 2023-03-14
143
+ // DEFAULT_KEY is undefined
144
+ // if (r.hasOwnProperty(DEFAULT_KEY)) {
145
+ // return validateString(r[DEFAULT_KEY]);
146
+ // }
147
+
148
+ return validateString(defaultText);
149
+ }
150
+
151
+ /**
152
+ * Set a text for a key
153
+ *
154
+ * ```
155
+ * translations.setText("text1", "Make my day!");
156
+ * // plural rules
157
+ * translations.setText("text6", {
158
+ * "zero": "There are no files on Disk.",
159
+ * "one": "There is one file on Disk.",
160
+ * "other": "There are files on Disk."
161
+ * "default": "There are files on Disk."
162
+ * });
163
+ * ```
164
+ *
165
+ * @param {string} key
166
+ * @param {string|object} text
167
+ * @return {Translations}
168
+ * @throws {TypeError} value is not a string or object
169
+ */
170
+ setText(key, text) {
171
+ if (isString(text) || isObject(text)) {
172
+ this.storage.set(validateString(key), text);
173
+ return this;
174
+ }
175
+
176
+ throw new TypeError("value is not a string or object");
177
+ }
178
+
179
+ /**
180
+ * This method can be used to transfer overlays from an object. The keys are transferred, and the values are entered
181
+ * as text.
182
+ *
183
+ * The values can either be character strings or, in the case of texts with plural forms, objects. The plural forms
184
+ * must be stored as text via a standard key "zero", "one", "two", "few", "many" and "other".
185
+ *
186
+ * Additionally, the key default can be specified, which will be used if no other key fits.
187
+ *
188
+ * In some languages, like for example in German, there is no own more number at the value 0. In these languages,
189
+ * the function applies additionally zero.
190
+ *
191
+ * ```
192
+ * translations.assignTranslations({
193
+ * "text1": "Make my day!",
194
+ * "text2": "I'll be back!",
195
+ * "text6": {
196
+ * "zero": "There are no files on Disk.",
197
+ * "one": "There is one file on Disk.",
198
+ * "other": "There are files on Disk."
199
+ * "default": "There are files on Disk."
200
+ * });
201
+ * ```
202
+ *
203
+ * @param {object} translations
204
+ * @return {Translations}
205
+ */
206
+ assignTranslations(translations) {
207
+ validateObject(translations);
208
+
209
+ if (translations instanceof Translations) {
210
+ translations.storage.forEach((v, k) => {
211
+ this.setText(k, v);
212
+ });
213
+ return this;
214
+ }
215
+
216
+ for (const [k, v] of Object.entries(translations)) {
217
+ this.setText(k, v);
218
+ }
219
+
220
+ return this;
221
+ }
222
222
  }
223
223
 
224
224
  /**
@@ -232,35 +232,35 @@ class Translations extends Base {
232
232
  * @throws {Error} Missing translations.
233
233
  */
234
234
  function getDocumentTranslations(element) {
235
- const d = getDocument();
235
+ const d = getDocument();
236
236
 
237
- if (!(element instanceof HTMLElement)) {
238
- element = d.querySelector(
239
- `[${ATTRIBUTE_OBJECTLINK}~="${translationsLinkSymbol.toString()}"]`,
240
- );
237
+ if (!(element instanceof HTMLElement)) {
238
+ element = d.querySelector(
239
+ `[${ATTRIBUTE_OBJECTLINK}~="${translationsLinkSymbol.toString()}"]`,
240
+ );
241
241
 
242
- if (element === null) {
243
- throw new Error(
244
- "Cannot find the element with translations. Add the translation object to the document.",
245
- );
246
- }
247
- }
242
+ if (element === null) {
243
+ throw new Error(
244
+ "Cannot find the element with translations. Add the translation object to the document.",
245
+ );
246
+ }
247
+ }
248
248
 
249
- if (!(element instanceof HTMLElement)) {
250
- throw new Error("Element is not an HTMLElement.");
251
- }
249
+ if (!(element instanceof HTMLElement)) {
250
+ throw new Error("Element is not an HTMLElement.");
251
+ }
252
252
 
253
- if (!hasObjectLink(element, translationsLinkSymbol)) {
254
- throw new Error("This element has no translations.");
255
- }
253
+ if (!hasObjectLink(element, translationsLinkSymbol)) {
254
+ throw new Error("This element has no translations.");
255
+ }
256
256
 
257
- const obj = getLinkedObjects(element, translationsLinkSymbol);
257
+ const obj = getLinkedObjects(element, translationsLinkSymbol);
258
258
 
259
- for (const t of obj) {
260
- if (t instanceof Translations) {
261
- return t;
262
- }
263
- }
259
+ for (const t of obj) {
260
+ if (t instanceof Translations) {
261
+ return t;
262
+ }
263
+ }
264
264
 
265
- throw new Error("Missing translations.");
265
+ throw new Error("Missing translations.");
266
266
  }