@schukai/monster 3.96.2 → 3.97.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.
Files changed (119) hide show
  1. package/CHANGELOG.md +23 -94
  2. package/package.json +1 -1
  3. package/source/components/accessibility/locale-picker.mjs +598 -0
  4. package/source/components/accessibility/style/locale-picker.css +1 -0
  5. package/source/components/accessibility/style/locale-picker.pcss +26 -0
  6. package/source/components/accessibility/stylesheet/locale-picker.mjs +31 -0
  7. package/source/components/content/stylesheet/copy.mjs +2 -2
  8. package/source/components/datatable/datasource/rest.mjs +33 -10
  9. package/source/components/datatable/filter.mjs +164 -63
  10. package/source/components/datatable/stylesheet/change-button.mjs +2 -2
  11. package/source/components/datatable/stylesheet/column-bar.mjs +2 -2
  12. package/source/components/datatable/stylesheet/dataset.mjs +2 -2
  13. package/source/components/datatable/stylesheet/datasource.mjs +1 -1
  14. package/source/components/datatable/stylesheet/datatable.mjs +1 -1
  15. package/source/components/datatable/stylesheet/embedded-pagination.mjs +2 -2
  16. package/source/components/datatable/stylesheet/filter-button.mjs +1 -1
  17. package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
  18. package/source/components/datatable/stylesheet/filter-date-range.mjs +1 -1
  19. package/source/components/datatable/stylesheet/filter-range.mjs +1 -1
  20. package/source/components/datatable/stylesheet/filter-select.mjs +2 -2
  21. package/source/components/datatable/stylesheet/filter.mjs +2 -2
  22. package/source/components/datatable/stylesheet/pagination.mjs +1 -1
  23. package/source/components/datatable/stylesheet/save-button.mjs +2 -2
  24. package/source/components/datatable/stylesheet/status.mjs +1 -1
  25. package/source/components/form/form.mjs +4 -2
  26. package/source/components/form/stylesheet/action-button.mjs +1 -1
  27. package/source/components/form/stylesheet/api-bar.mjs +1 -1
  28. package/source/components/form/stylesheet/api-button.mjs +1 -1
  29. package/source/components/form/stylesheet/button-bar.mjs +1 -1
  30. package/source/components/form/stylesheet/button.mjs +1 -1
  31. package/source/components/form/stylesheet/confirm-button.mjs +1 -1
  32. package/source/components/form/stylesheet/context-error.mjs +1 -1
  33. package/source/components/form/stylesheet/context-help.mjs +1 -1
  34. package/source/components/form/stylesheet/field-set.mjs +1 -1
  35. package/source/components/form/stylesheet/form.mjs +1 -1
  36. package/source/components/form/stylesheet/input-group.mjs +1 -1
  37. package/source/components/form/stylesheet/message-state-button.mjs +1 -1
  38. package/source/components/form/stylesheet/password.mjs +1 -1
  39. package/source/components/form/stylesheet/popper-button.mjs +1 -1
  40. package/source/components/form/stylesheet/select.mjs +1 -1
  41. package/source/components/form/stylesheet/state-button.mjs +1 -1
  42. package/source/components/form/stylesheet/toggle-switch.mjs +1 -1
  43. package/source/components/form/stylesheet/tree-select.mjs +1 -1
  44. package/source/components/host/stylesheet/call-button.mjs +2 -2
  45. package/source/components/host/stylesheet/config-manager.mjs +1 -1
  46. package/source/components/host/stylesheet/host.mjs +2 -2
  47. package/source/components/host/stylesheet/overlay.mjs +2 -2
  48. package/source/components/host/stylesheet/toggle-button.mjs +2 -2
  49. package/source/components/host/stylesheet/viewer.mjs +2 -2
  50. package/source/components/layout/stylesheet/collapse.mjs +2 -2
  51. package/source/components/layout/stylesheet/details.mjs +2 -2
  52. package/source/components/layout/stylesheet/iframe.mjs +1 -1
  53. package/source/components/layout/stylesheet/panel.mjs +2 -2
  54. package/source/components/layout/stylesheet/popper.mjs +1 -1
  55. package/source/components/layout/stylesheet/slider.mjs +2 -2
  56. package/source/components/layout/stylesheet/split-panel.mjs +1 -1
  57. package/source/components/layout/stylesheet/tabs.mjs +2 -2
  58. package/source/components/layout/stylesheet/width-toggle.mjs +1 -1
  59. package/source/components/navigation/stylesheet/table-of-content.mjs +2 -2
  60. package/source/components/notify/stylesheet/message.mjs +2 -2
  61. package/source/components/notify/stylesheet/notify.mjs +1 -1
  62. package/source/components/state/stylesheet/log.mjs +1 -1
  63. package/source/components/state/stylesheet/state.mjs +1 -1
  64. package/source/components/style/property.css +1 -0
  65. package/source/components/style/theme.css +4 -4
  66. package/source/components/stylesheet/badge.mjs +1 -1
  67. package/source/components/stylesheet/border.mjs +1 -1
  68. package/source/components/stylesheet/button.mjs +1 -1
  69. package/source/components/stylesheet/card.mjs +1 -1
  70. package/source/components/stylesheet/color.mjs +1 -1
  71. package/source/components/stylesheet/common.mjs +1 -1
  72. package/source/components/stylesheet/control.mjs +1 -1
  73. package/source/components/stylesheet/data-grid.mjs +1 -1
  74. package/source/components/stylesheet/display.mjs +1 -1
  75. package/source/components/stylesheet/floating-ui.mjs +1 -1
  76. package/source/components/stylesheet/form.mjs +1 -1
  77. package/source/components/stylesheet/host.mjs +1 -1
  78. package/source/components/stylesheet/icons.mjs +1 -1
  79. package/source/components/stylesheet/link.mjs +1 -1
  80. package/source/components/stylesheet/mixin/badge.mjs +1 -1
  81. package/source/components/stylesheet/mixin/button.mjs +1 -1
  82. package/source/components/stylesheet/mixin/hover.mjs +1 -1
  83. package/source/components/stylesheet/mixin/icon.mjs +1 -1
  84. package/source/components/stylesheet/mixin/media.mjs +1 -1
  85. package/source/components/stylesheet/mixin/property.mjs +1 -1
  86. package/source/components/stylesheet/mixin/skeleton.mjs +1 -1
  87. package/source/components/stylesheet/mixin/spinner.mjs +1 -1
  88. package/source/components/stylesheet/mixin/typography.mjs +1 -1
  89. package/source/components/stylesheet/normalize.mjs +1 -1
  90. package/source/components/stylesheet/popper.mjs +1 -1
  91. package/source/components/stylesheet/property.mjs +2 -2
  92. package/source/components/stylesheet/ripple.mjs +1 -1
  93. package/source/components/stylesheet/skeleton.mjs +1 -1
  94. package/source/components/stylesheet/space.mjs +1 -1
  95. package/source/components/stylesheet/spinner.mjs +1 -1
  96. package/source/components/stylesheet/table.mjs +1 -1
  97. package/source/components/stylesheet/theme.mjs +1 -1
  98. package/source/components/stylesheet/typography.mjs +1 -1
  99. package/source/components/tree-menu/stylesheet/tree-menu.mjs +1 -1
  100. package/source/constants.mjs +14 -1
  101. package/source/data/extend.mjs +2 -1
  102. package/source/data/transformer.mjs +2 -0
  103. package/source/dom/customelement.mjs +7 -3
  104. package/source/dom/updater.mjs +5 -1
  105. package/source/i18n/locale.mjs +151 -151
  106. package/source/i18n/map/languages.mjs +104 -0
  107. package/source/i18n/util.mjs +139 -0
  108. package/source/monster.mjs +1 -1
  109. package/source/text/formatter.mjs +5 -3
  110. package/source/types/is.mjs +13 -0
  111. package/source/types/proxyobserver.mjs +7 -2
  112. package/source/types/version.mjs +1 -1
  113. package/source/util/clone.mjs +9 -14
  114. package/test/cases/data/pathfinder.mjs +18 -0
  115. package/test/cases/i18n/util.mjs +295 -0
  116. package/test/cases/monster.mjs +1 -1
  117. package/test/cases/text/formatter.mjs +21 -1
  118. package/test/web/test.html +2 -2
  119. package/test/web/tests.js +115 -75
@@ -12,12 +12,12 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import { instanceSymbol } from "../constants.mjs";
16
- import { Base } from "../types/base.mjs";
17
- import { validateString } from "../types/validate.mjs";
18
- import { clone } from "../util/clone.mjs";
15
+ import {instanceSymbol} from "../constants.mjs";
16
+ import {Base} from "../types/base.mjs";
17
+ import {validateString} from "../types/validate.mjs";
18
+ import {clone} from "../util/clone.mjs";
19
19
 
20
- export { Locale, parseLocale };
20
+ export {Locale, parseLocale};
21
21
 
22
22
  /**
23
23
  * @type {symbol}
@@ -69,116 +69,116 @@ const localeStringSymbol = Symbol("localeString");
69
69
  * @see https://datatracker.ietf.org/doc/html/rfc3066
70
70
  */
71
71
  class Locale extends Base {
72
- /**
73
- * @param {string} language
74
- * @param {string} [region]
75
- * @param {string} [script]
76
- * @param {string} [variants]
77
- * @param {string} [extlang]
78
- * @param {string} [privateUse]
79
- * @throws {Error} unsupported locale
80
- */
81
- constructor(language, region, script, variants, extlang, privateUse) {
82
- super();
72
+ /**
73
+ * @param {string} language
74
+ * @param {string} [region]
75
+ * @param {string} [script]
76
+ * @param {string} [variants]
77
+ * @param {string} [extlang]
78
+ * @param {string} [privateUse]
79
+ * @throws {Error} unsupported locale
80
+ */
81
+ constructor(language, region, script, variants, extlang, privateUse) {
82
+ super();
83
83
 
84
- this[propertiesSymbol] = {
85
- language: language === undefined ? undefined : validateString(language),
86
- script: script === undefined ? undefined : validateString(script),
87
- region: region === undefined ? undefined : validateString(region),
88
- variants: variants === undefined ? undefined : validateString(variants),
89
- extlang: extlang === undefined ? undefined : validateString(extlang),
90
- privateUse:
91
- privateUse === undefined ? undefined : validateString(privateUse),
92
- };
84
+ this[propertiesSymbol] = {
85
+ language: language === undefined ? undefined : validateString(language),
86
+ script: script === undefined ? undefined : validateString(script),
87
+ region: region === undefined ? undefined : validateString(region),
88
+ variants: variants === undefined ? undefined : validateString(variants),
89
+ extlang: extlang === undefined ? undefined : validateString(extlang),
90
+ privateUse:
91
+ privateUse === undefined ? undefined : validateString(privateUse),
92
+ };
93
93
 
94
- const s = [];
95
- if (language !== undefined) s.push(language);
96
- if (script !== undefined) s.push(script);
97
- if (region !== undefined) s.push(region);
98
- if (variants !== undefined) s.push(variants);
99
- if (extlang !== undefined) s.push(extlang);
100
- if (privateUse !== undefined) s.push(privateUse);
94
+ const s = [];
95
+ if (language !== undefined) s.push(language);
96
+ if (script !== undefined) s.push(script);
97
+ if (region !== undefined) s.push(region);
98
+ if (variants !== undefined) s.push(variants);
99
+ if (extlang !== undefined) s.push(extlang);
100
+ if (privateUse !== undefined) s.push(privateUse);
101
101
 
102
- if (s.length === 0) {
103
- throw new Error("unsupported locale");
104
- }
102
+ if (s.length === 0) {
103
+ throw new Error("unsupported locale");
104
+ }
105
105
 
106
- this[localeStringSymbol] = s.join("-");
107
- }
106
+ this[localeStringSymbol] = s.join("-");
107
+ }
108
108
 
109
- /**
110
- * This method is called by the `instanceof` operator.
111
- * @return {symbol}
112
- * @since 3.27.0
113
- */
114
- static get [instanceSymbol]() {
115
- return Symbol.for("@schukai/monster/i18n/locale@@instance");
116
- }
109
+ /**
110
+ * This method is called by the `instanceof` operator.
111
+ * @return {symbol}
112
+ * @since 3.27.0
113
+ */
114
+ static get [instanceSymbol]() {
115
+ return Symbol.for("@schukai/monster/i18n/locale@@instance");
116
+ }
117
117
 
118
- /**
119
- * @return {string}
120
- */
121
- get localeString() {
122
- return this[localeStringSymbol];
123
- }
118
+ /**
119
+ * @return {string}
120
+ */
121
+ get localeString() {
122
+ return this[localeStringSymbol];
123
+ }
124
124
 
125
- /**
126
- * @return {string|undefined}
127
- */
128
- get language() {
129
- return this[propertiesSymbol].language;
130
- }
125
+ /**
126
+ * @return {string|undefined}
127
+ */
128
+ get language() {
129
+ return this[propertiesSymbol].language;
130
+ }
131
131
 
132
- /**
133
- * @return {string|undefined}
134
- */
135
- get region() {
136
- return this[propertiesSymbol].region;
137
- }
132
+ /**
133
+ * @return {string|undefined}
134
+ */
135
+ get region() {
136
+ return this[propertiesSymbol].region;
137
+ }
138
138
 
139
- /**
140
- * @return {string|undefined}
141
- */
142
- get script() {
143
- return this[propertiesSymbol].script;
144
- }
139
+ /**
140
+ * @return {string|undefined}
141
+ */
142
+ get script() {
143
+ return this[propertiesSymbol].script;
144
+ }
145
145
 
146
- /**
147
- * @return {string|undefined}
148
- */
149
- get variants() {
150
- return this[propertiesSymbol].variants;
151
- }
146
+ /**
147
+ * @return {string|undefined}
148
+ */
149
+ get variants() {
150
+ return this[propertiesSymbol].variants;
151
+ }
152
152
 
153
- /**
154
- * @return {string|undefined}
155
- */
156
- get extlang() {
157
- return this[propertiesSymbol].extlang;
158
- }
153
+ /**
154
+ * @return {string|undefined}
155
+ */
156
+ get extlang() {
157
+ return this[propertiesSymbol].extlang;
158
+ }
159
159
 
160
- /**
161
- * @return {string|undefined}
162
- */
163
- get privateUse() {
164
- return this[propertiesSymbol].privateValue;
165
- }
160
+ /**
161
+ * @return {string|undefined}
162
+ */
163
+ get privateUse() {
164
+ return this[propertiesSymbol].privateValue;
165
+ }
166
166
 
167
- /**
168
- * @return {string}
169
- */
170
- toString() {
171
- return `${this.localeString}`;
172
- }
167
+ /**
168
+ * @return {string}
169
+ */
170
+ toString() {
171
+ return `${this.localeString}`;
172
+ }
173
173
 
174
- /**
175
- * The structure has the following: language, script, region, variants, extlang, privateUse
176
- *
177
- * @return {Monster.I18n.LocaleMap}
178
- */
179
- getMap() {
180
- return clone(this[propertiesSymbol]);
181
- }
174
+ /**
175
+ * The structure has the following: language, script, region, variants, extlang, privateUse
176
+ *
177
+ * @return {Monster.I18n.LocaleMap}
178
+ */
179
+ getMap() {
180
+ return clone(this[propertiesSymbol]);
181
+ }
182
182
  }
183
183
 
184
184
  /**
@@ -260,63 +260,63 @@ class Locale extends Base {
260
260
  * @throws {Error} unsupported locale
261
261
  */
262
262
  function parseLocale(locale) {
263
- locale = validateString(locale).replace(/_/g, "-");
263
+ locale = validateString(locale).replace(/_/g, "-");
264
264
 
265
- let language;
266
- let region;
267
- let variants;
268
- let parts;
269
- let script;
270
- let extlang;
271
- const regexRegular =
272
- "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)";
273
- const regexIrregular =
274
- "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)";
275
- const regexGrandfathered = `(${regexIrregular}|${regexRegular})`;
276
- const regexPrivateUse = "(x(-[A-Za-z0-9]{1,8})+)";
277
- const regexSingleton = "[0-9A-WY-Za-wy-z]";
278
- const regexExtension = `(${regexSingleton}(-[A-Za-z0-9]{2,8})+)`;
279
- const regexVariant = "([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})";
280
- const regexRegion = "([A-Za-z]{2}|[0-9]{3})";
281
- const regexScript = "([A-Za-z]{4})";
282
- const regexExtlang = "([A-Za-z]{3}(-[A-Za-z]{3}){0,2})";
283
- const regexLanguage = `(([A-Za-z]{2,3}(-${regexExtlang})?)|[A-Za-z]{4}|[A-Za-z]{5,8})`;
284
- const regexLangtag = `(${regexLanguage}(-${regexScript})?(-${regexRegion})?(-${regexVariant})*(-${regexExtension})*(-${regexPrivateUse})?)`;
285
- const regexLanguageTag = `^(${regexGrandfathered}|${regexLangtag}|${regexPrivateUse})$`;
286
- const regex = new RegExp(regexLanguageTag);
287
- let match;
265
+ let language;
266
+ let region;
267
+ let variants;
268
+ let parts;
269
+ let script;
270
+ let extlang;
271
+ const regexRegular =
272
+ "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)";
273
+ const regexIrregular =
274
+ "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)";
275
+ const regexGrandfathered = `(${regexIrregular}|${regexRegular})`;
276
+ const regexPrivateUse = "(x(-[A-Za-z0-9]{1,8})+)";
277
+ const regexSingleton = "[0-9A-WY-Za-wy-z]";
278
+ const regexExtension = `(${regexSingleton}(-[A-Za-z0-9]{2,8})+)`;
279
+ const regexVariant = "([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})";
280
+ const regexRegion = "([A-Za-z]{2}|[0-9]{3})";
281
+ const regexScript = "([A-Za-z]{4})";
282
+ const regexExtlang = "([A-Za-z]{3}(-[A-Za-z]{3}){0,2})";
283
+ const regexLanguage = `(([A-Za-z]{2,3}(-${regexExtlang})?)|[A-Za-z]{4}|[A-Za-z]{5,8})`;
284
+ const regexLangtag = `(${regexLanguage}(-${regexScript})?(-${regexRegion})?(-${regexVariant})*(-${regexExtension})*(-${regexPrivateUse})?)`;
285
+ const regexLanguageTag = `^(${regexGrandfathered}|${regexLangtag}|${regexPrivateUse})$`;
286
+ const regex = new RegExp(regexLanguageTag);
287
+ let match;
288
288
 
289
- if ((match = regex.exec(locale)) !== null) {
290
- if (match.index === regex.lastIndex) {
291
- regex.lastIndex++;
292
- }
293
- }
289
+ if ((match = regex.exec(locale)) !== null) {
290
+ if (match.index === regex.lastIndex) {
291
+ regex.lastIndex++;
292
+ }
293
+ }
294
294
 
295
- if (match === undefined || match === null) {
296
- throw new Error("unsupported locale");
297
- }
295
+ if (match === undefined || match === null) {
296
+ throw new Error("unsupported locale");
297
+ }
298
298
 
299
- if (match[6] !== undefined) {
300
- language = match[6];
299
+ if (match[6] !== undefined) {
300
+ language = match[6];
301
301
 
302
- parts = language.split("-");
303
- if (parts.length > 1) {
304
- language = parts[0];
305
- extlang = parts[1];
306
- }
307
- }
302
+ parts = language.split("-");
303
+ if (parts.length > 1) {
304
+ language = parts[0];
305
+ extlang = parts[1];
306
+ }
307
+ }
308
308
 
309
- if (match[14] !== undefined) {
310
- region = match[14];
311
- }
309
+ if (match[14] !== undefined) {
310
+ region = match[14];
311
+ }
312
312
 
313
- if (match[12] !== undefined) {
314
- script = match[12];
315
- }
313
+ if (match[12] !== undefined) {
314
+ script = match[12];
315
+ }
316
316
 
317
- if (match[16] !== undefined) {
318
- variants = match[16];
319
- }
317
+ if (match[16] !== undefined) {
318
+ variants = match[16];
319
+ }
320
320
 
321
- return new Locale(language, region, script, variants, extlang);
321
+ return new Locale(language, region, script, variants, extlang);
322
322
  }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
3
+ * Node module: @schukai/monster
4
+ *
5
+ * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
6
+ * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
7
+ *
8
+ * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
9
+ * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
10
+ * For more information about purchasing a commercial license, please contact schukai GmbH.
11
+ *
12
+ * SPDX-License-Identifier: AGPL-3.0
13
+ */
14
+
15
+ export const languages = {
16
+ "en": "English",
17
+ "en-GB": "English (United Kingdom)",
18
+ "en-US": "English (United States)",
19
+ "en-CA": "English (Canada)",
20
+ "en-AU": "English (Australia)",
21
+ "es": "Español",
22
+ "es-ES": "Español (España)",
23
+ "es-MX": "Español (México)",
24
+ "es-AR": "Español (Argentina)",
25
+ "zh": "中文",
26
+ "zh-CN": "中文(简体)",
27
+ "zh-TW": "中文(繁體)",
28
+ "zh-HK": "中文(香港)",
29
+ "fr": "Français",
30
+ "fr-FR": "Français (France)",
31
+ "fr-CA": "Français (Canada)",
32
+ "fr-BE": "Français (Belgique)",
33
+ "de": "Deutsch",
34
+ "de-DE": "Deutsch (Deutschland)",
35
+ "de-AT": "Deutsch (Österreich)",
36
+ "de-CH": "Deutsch (Schweiz)",
37
+ "ja": "日本語",
38
+ "ru": "Русский",
39
+ "ru-RU": "Русский (Россия)",
40
+ "it": "Italiano",
41
+ "it-IT": "Italiano (Italia)",
42
+ "pt": "Português",
43
+ "pt-PT": "Português (Portugal)",
44
+ "pt-BR": "Português (Brasil)",
45
+ "ko": "한국어",
46
+ "ar": "العربية",
47
+ "hi": "हिन्दी",
48
+ "bn": "বাংলা",
49
+ "pa": "ਪੰਜਾਬੀ",
50
+ "id": "Bahasa Indonesia",
51
+ "vi": "Tiếng Việt",
52
+ "tr": "Türkçe",
53
+ "tr-TR": "Türkçe (Türkiye)",
54
+ "pl": "Polski",
55
+ "pl-PL": "Polski (Polska)",
56
+ "uk": "Українська",
57
+ "uk-UA": "Українська (Україна)",
58
+ "ro": "Română",
59
+ "ro-RO": "Română (România)",
60
+ "nl": "Nederlands",
61
+ "nl-NL": "Nederlands (Nederland)",
62
+ "el": "Ελληνικά",
63
+ "el-GR": "Ελληνικά (Ελλάδα)",
64
+ "hu": "Magyar",
65
+ "hu-HU": "Magyar (Magyarország)",
66
+ "sv": "Svenska",
67
+ "sv-SE": "Svenska (Sverige)",
68
+ "cs": "Čeština",
69
+ "cs-CZ": "Čeština (Česká republika)",
70
+ "bg": "Български",
71
+ "bg-BG": "Български (България)",
72
+ "da": "Dansk",
73
+ "da-DK": "Dansk (Danmark)",
74
+ "fi": "Suomi",
75
+ "fi-FI": "Suomi (Suomi)",
76
+ "sk": "Slovenčina",
77
+ "sk-SK": "Slovenčina (Slovensko)",
78
+ "he": "עברית",
79
+ "th": "ไทย",
80
+ "sr": "Српски",
81
+ "sr-RS": "Српски (Србија)",
82
+ "no": "Norsk",
83
+ "no-NO": "Norsk (Norge)",
84
+ "lt": "Lietuvių",
85
+ "lt-LT": "Lietuvių (Lietuva)",
86
+ "lv": "Latviešu",
87
+ "lv-LV": "Latviešu (Latvija)",
88
+ "et": "Eesti",
89
+ "et-EE": "Eesti (Eesti)",
90
+ "hr": "Hrvatski",
91
+ "hr-HR": "Hrvatski (Hrvatska)",
92
+ "sl": "Slovenščina",
93
+ "sl-SI": "Slovenščina (Slovenija)",
94
+ "mt": "Malti",
95
+ "mt-MT": "Malti (Malta)",
96
+ "is": "Íslenska",
97
+ "is-IS": "Íslenska (Ísland)",
98
+ "ga": "Gaeilge",
99
+ "ga-IE": "Gaeilge (Éire)",
100
+ "cy": "Cymraeg",
101
+ "cy-GB": "Cymraeg (Y Deyrnas Unedig)",
102
+ "sq": "Shqip",
103
+ "sq-AL": "Shqip (Shqipëria)"
104
+ };
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
3
+ * Node module: @schukai/monster
4
+ *
5
+ * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
6
+ * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
7
+ *
8
+ * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
9
+ * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
10
+ * For more information about purchasing a commercial license, please contact schukai GmbH.
11
+ *
12
+ * SPDX-License-Identifier: AGPL-3.0
13
+ */
14
+
15
+ import {languages} from "./map/languages.mjs";
16
+
17
+ /**
18
+ * Determines the user's preferred language based on browser settings and available language options.
19
+ *
20
+ * It evaluates the current HTML document language, the browser's defined languages, and
21
+ * the language options from `<link>` elements with `hreflang` attributes in the document.
22
+ *
23
+ * @return {Object} An object containing information about the detected language, preferred language, and available languages.
24
+ */
25
+ export function detectUserLanguagePreference() {
26
+ const currentLang = document.documentElement.lang;
27
+
28
+ let preferredLanguages = [];
29
+
30
+ if (typeof navigator.language === "string" && navigator.language.length > 0) {
31
+ preferredLanguages = [navigator.language];
32
+ }
33
+
34
+ if (Array.isArray(navigator.languages) && navigator.languages.length > 0) {
35
+ preferredLanguages = navigator.languages;
36
+ }
37
+
38
+ // add to preferredLanguages all the base languages of the preferred languages
39
+ preferredLanguages = preferredLanguages.concat(preferredLanguages.map(lang => lang.split("-")[0]));
40
+
41
+
42
+ if (!currentLang && preferredLanguages.length === 0) {
43
+ return {
44
+ message: "No language information available.",
45
+ };
46
+ }
47
+
48
+ const linkTags = document.querySelectorAll("link[hreflang]");
49
+ if (linkTags.length === 0) {
50
+ return {
51
+ current: currentLang || null,
52
+ message: "No <link> tags with hreflang available.",
53
+ };
54
+ }
55
+
56
+ const availableLanguages = [...linkTags].map((link) => {
57
+ const fullLang = link.hreflang;
58
+ const baseLang = fullLang.split("-")[0];
59
+ let label = link.getAttribute('data-monster-label')
60
+ if (!label) {
61
+ label = languages?.[fullLang]
62
+ if (!label) {
63
+ label = languages?.[baseLang]
64
+ }
65
+ }
66
+
67
+ return {
68
+ fullLang,
69
+ baseLang,
70
+ label,
71
+ href: link.href,
72
+ };
73
+ });
74
+
75
+ // filter availableLanguages to only include languages that are in the preferredLanguages array
76
+ const offerableLanguages = availableLanguages.filter(lang => preferredLanguages.includes(lang.fullLang) || preferredLanguages.includes(lang.baseLang));
77
+
78
+ if (offerableLanguages.length === 0) {
79
+ return {
80
+ current: currentLang || null,
81
+ message: "No available languages match the user's preferences.",
82
+ available: availableLanguages.map((lang) => ({
83
+ ...lang,
84
+ weight: 1,
85
+ })),
86
+ };
87
+ }
88
+
89
+ // Helper function to determine the "weight" of a language match
90
+ function getWeight(langEntry) {
91
+ // Full match has priority 3
92
+ if (preferredLanguages.includes(langEntry.fullLang)) return 3;
93
+ // Base language match has priority 2
94
+ if (preferredLanguages.includes(langEntry.baseLang)) return 2;
95
+ // No match is priority 1
96
+ return 1;
97
+ }
98
+
99
+ // Sort the available languages by descending weight
100
+ offerableLanguages.sort((a, b) => getWeight(b) - getWeight(a));
101
+
102
+ // The best match is the first in the sorted list
103
+ const bestMatch = offerableLanguages[0];
104
+ const bestMatchWeight = getWeight(bestMatch);
105
+
106
+ const currentLabel = languages?.[currentLang] || currentLang
107
+
108
+ // If we found a language that matches user preferences (weight > 1)
109
+ if (bestMatchWeight > 0) {
110
+ return {
111
+ current: currentLang || null,
112
+ currentLabel: currentLabel,
113
+ preferred: {
114
+ full: bestMatch.fullLang,
115
+ base: bestMatch.baseLang,
116
+ label: bestMatch.label,
117
+ href : bestMatch.href,
118
+ },
119
+ available: availableLanguages.map((lang) => ({
120
+ ...lang,
121
+ weight: getWeight(lang),
122
+ })),
123
+ offerable: offerableLanguages.map((lang) => ({
124
+ ...lang,
125
+ weight: getWeight(lang),
126
+ })),
127
+ };
128
+ }
129
+
130
+ // If no language matched the user's preferences
131
+ return {
132
+ current: currentLang || null,
133
+ message: "None of the preferred languages are available.",
134
+ available: availableLanguages.map((lang) => ({
135
+ ...lang,
136
+ weight: getWeight(lang),
137
+ })),
138
+ };
139
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright © schukai GmbH and all contributing authors, 2024. All rights reserved.
2
+ * Copyright © schukai GmbH and all contributing authors, 2025. All rights reserved.
3
3
  * Node module: @schukai/monster
4
4
  *
5
5
  * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
@@ -276,7 +276,10 @@ function format(text) {
276
276
  * @private
277
277
  * @license AGPLv3
278
278
  * @since 1.12.0
279
- * @param text
279
+ *
280
+ * @param {string} text
281
+ * @param {string} openMarker
282
+ * @param {string} closeMarker
280
283
  * @return {string}
281
284
  */
282
285
  function tokenize(text, openMarker, closeMarker) {
@@ -339,7 +342,7 @@ function tokenize(text, openMarker, closeMarker) {
339
342
  const t1 = key.split("|").shift().trim(); // pipe symbol
340
343
  const t2 = t1.split("::").shift().trim(); // key value delimiter
341
344
  const t3 = t2.split(".").shift().trim(); // path delimiter
342
- const prefix = this[workingDataSymbol]?.[t3] ? "path:" : "static:";
345
+ const prefix = t3 in this[workingDataSymbol] ? "path:" : "static:";
343
346
 
344
347
  let command = "";
345
348
  if (
@@ -362,7 +365,6 @@ function tokenize(text, openMarker, closeMarker) {
362
365
  }
363
366
 
364
367
  formatted.push(validateString(pipe.run(this[workingDataSymbol])));
365
-
366
368
  text = text.substring(endIndex + closeMarker.length);
367
369
  }
368
370
 
@@ -12,6 +12,8 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
+ import { proxyInstanceMarker } from "../constants.mjs";
16
+
15
17
  export {
16
18
  isIterable,
17
19
  isPrimitive,
@@ -23,8 +25,19 @@ export {
23
25
  isArray,
24
26
  isFunction,
25
27
  isInteger,
28
+ isProxy,
26
29
  };
27
30
 
31
+ /**
32
+ * Checks whether the value passed is a Proxy.
33
+ *
34
+ * @param {*} value
35
+ * @returns {boolean}
36
+ */
37
+ function isProxy(value) {
38
+ return value?.[proxyInstanceMarker] === proxyInstanceMarker;
39
+ }
40
+
28
41
  /**
29
42
  * With this function you can check if a value is iterable.
30
43
  *