@schukai/monster 3.96.3 → 3.97.1

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 (100) hide show
  1. package/CHANGELOG.md +23 -96
  2. package/package.json +1 -1
  3. package/source/components/accessibility/locale-picker.mjs +663 -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 +38 -0
  7. package/source/components/content/stylesheet/copy.mjs +2 -2
  8. package/source/components/datatable/stylesheet/change-button.mjs +2 -2
  9. package/source/components/datatable/stylesheet/column-bar.mjs +2 -2
  10. package/source/components/datatable/stylesheet/dataset.mjs +2 -2
  11. package/source/components/datatable/stylesheet/datasource.mjs +1 -1
  12. package/source/components/datatable/stylesheet/datatable.mjs +1 -1
  13. package/source/components/datatable/stylesheet/embedded-pagination.mjs +2 -2
  14. package/source/components/datatable/stylesheet/filter-button.mjs +1 -1
  15. package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
  16. package/source/components/datatable/stylesheet/filter-date-range.mjs +1 -1
  17. package/source/components/datatable/stylesheet/filter-range.mjs +1 -1
  18. package/source/components/datatable/stylesheet/filter-select.mjs +2 -2
  19. package/source/components/datatable/stylesheet/filter.mjs +2 -2
  20. package/source/components/datatable/stylesheet/pagination.mjs +1 -1
  21. package/source/components/datatable/stylesheet/save-button.mjs +2 -2
  22. package/source/components/datatable/stylesheet/status.mjs +1 -1
  23. package/source/components/form/stylesheet/action-button.mjs +1 -1
  24. package/source/components/form/stylesheet/api-bar.mjs +1 -1
  25. package/source/components/form/stylesheet/api-button.mjs +1 -1
  26. package/source/components/form/stylesheet/button-bar.mjs +1 -1
  27. package/source/components/form/stylesheet/button.mjs +1 -1
  28. package/source/components/form/stylesheet/confirm-button.mjs +1 -1
  29. package/source/components/form/stylesheet/context-error.mjs +1 -1
  30. package/source/components/form/stylesheet/context-help.mjs +1 -1
  31. package/source/components/form/stylesheet/field-set.mjs +1 -1
  32. package/source/components/form/stylesheet/form.mjs +1 -1
  33. package/source/components/form/stylesheet/input-group.mjs +1 -1
  34. package/source/components/form/stylesheet/message-state-button.mjs +1 -1
  35. package/source/components/form/stylesheet/password.mjs +1 -1
  36. package/source/components/form/stylesheet/popper-button.mjs +1 -1
  37. package/source/components/form/stylesheet/select.mjs +1 -1
  38. package/source/components/form/stylesheet/state-button.mjs +1 -1
  39. package/source/components/form/stylesheet/toggle-switch.mjs +1 -1
  40. package/source/components/form/stylesheet/tree-select.mjs +1 -1
  41. package/source/components/host/stylesheet/call-button.mjs +2 -2
  42. package/source/components/host/stylesheet/config-manager.mjs +1 -1
  43. package/source/components/host/stylesheet/host.mjs +2 -2
  44. package/source/components/host/stylesheet/overlay.mjs +2 -2
  45. package/source/components/host/stylesheet/toggle-button.mjs +2 -2
  46. package/source/components/host/stylesheet/viewer.mjs +2 -2
  47. package/source/components/layout/stylesheet/collapse.mjs +2 -2
  48. package/source/components/layout/stylesheet/details.mjs +2 -2
  49. package/source/components/layout/stylesheet/iframe.mjs +1 -1
  50. package/source/components/layout/stylesheet/panel.mjs +2 -2
  51. package/source/components/layout/stylesheet/popper.mjs +1 -1
  52. package/source/components/layout/stylesheet/slider.mjs +2 -2
  53. package/source/components/layout/stylesheet/split-panel.mjs +1 -1
  54. package/source/components/layout/stylesheet/tabs.mjs +2 -2
  55. package/source/components/layout/stylesheet/width-toggle.mjs +1 -1
  56. package/source/components/navigation/stylesheet/table-of-content.mjs +2 -2
  57. package/source/components/notify/stylesheet/message.mjs +2 -2
  58. package/source/components/notify/stylesheet/notify.mjs +1 -1
  59. package/source/components/state/stylesheet/log.mjs +1 -1
  60. package/source/components/state/stylesheet/state.mjs +1 -1
  61. package/source/components/style/property.css +1 -0
  62. package/source/components/style/theme.css +4 -4
  63. package/source/components/stylesheet/badge.mjs +1 -1
  64. package/source/components/stylesheet/border.mjs +1 -1
  65. package/source/components/stylesheet/button.mjs +1 -1
  66. package/source/components/stylesheet/card.mjs +1 -1
  67. package/source/components/stylesheet/color.mjs +1 -1
  68. package/source/components/stylesheet/common.mjs +1 -1
  69. package/source/components/stylesheet/control.mjs +1 -1
  70. package/source/components/stylesheet/data-grid.mjs +1 -1
  71. package/source/components/stylesheet/display.mjs +1 -1
  72. package/source/components/stylesheet/floating-ui.mjs +1 -1
  73. package/source/components/stylesheet/form.mjs +1 -1
  74. package/source/components/stylesheet/host.mjs +1 -1
  75. package/source/components/stylesheet/icons.mjs +1 -1
  76. package/source/components/stylesheet/link.mjs +1 -1
  77. package/source/components/stylesheet/mixin/badge.mjs +1 -1
  78. package/source/components/stylesheet/mixin/button.mjs +1 -1
  79. package/source/components/stylesheet/mixin/hover.mjs +1 -1
  80. package/source/components/stylesheet/mixin/icon.mjs +1 -1
  81. package/source/components/stylesheet/mixin/media.mjs +1 -1
  82. package/source/components/stylesheet/mixin/property.mjs +1 -1
  83. package/source/components/stylesheet/mixin/skeleton.mjs +1 -1
  84. package/source/components/stylesheet/mixin/spinner.mjs +1 -1
  85. package/source/components/stylesheet/mixin/typography.mjs +1 -1
  86. package/source/components/stylesheet/normalize.mjs +1 -1
  87. package/source/components/stylesheet/popper.mjs +1 -1
  88. package/source/components/stylesheet/property.mjs +2 -2
  89. package/source/components/stylesheet/ripple.mjs +1 -1
  90. package/source/components/stylesheet/skeleton.mjs +1 -1
  91. package/source/components/stylesheet/space.mjs +1 -1
  92. package/source/components/stylesheet/spinner.mjs +1 -1
  93. package/source/components/stylesheet/table.mjs +1 -1
  94. package/source/components/stylesheet/theme.mjs +1 -1
  95. package/source/components/stylesheet/typography.mjs +1 -1
  96. package/source/components/tree-menu/stylesheet/tree-menu.mjs +1 -1
  97. package/source/i18n/map/languages.mjs +104 -0
  98. package/source/i18n/util.mjs +147 -0
  99. package/source/monster.mjs +1 -0
  100. package/test/cases/i18n/util.mjs +295 -0
@@ -0,0 +1,295 @@
1
+ import {getGlobal} from "../../../source/types/global.mjs";
2
+
3
+ import * as chai from 'chai';
4
+ import {chaiDom} from "../../util/chai-dom.mjs";
5
+ import {initJSDOM} from "../../util/jsdom.mjs";
6
+
7
+ let expect = chai.expect;
8
+ chai.use(chaiDom);
9
+
10
+ describe('LocalPicker', function () {
11
+
12
+ let LocalPicker, documentLanguage, linkTags, originalLanguages, getPreferredLanguage;
13
+
14
+ before(function (done) {
15
+ initJSDOM().then(() => {
16
+
17
+ documentLanguage = document.documentElement.lang;
18
+ linkTags = Array.from(document.querySelectorAll('link[rel="alternate"]'));
19
+ linkTags.forEach(item => item.remove());
20
+
21
+ import("element-internals-polyfill").catch(e => done(e));
22
+
23
+ import("../../../source/i18n/util.mjs").then((m) => {
24
+
25
+ LocalPicker = m['LocalPicker'];
26
+ getPreferredLanguage = m['detectUserLanguagePreference'];
27
+
28
+ originalLanguages = navigator.languages;
29
+
30
+ done()
31
+ }).catch(e => done(e))
32
+
33
+
34
+ });
35
+ })
36
+
37
+ after(function () {
38
+ document.documentElement.lang = documentLanguage;
39
+
40
+ linkTags.forEach(item => {
41
+ const link = document.createElement('link');
42
+ link.setAttribute('rel', 'alternate');
43
+ link.setAttribute('hreflang', item.hreflang);
44
+ link.setAttribute('href', item.href);
45
+
46
+ // check if already exits
47
+ if (!document.querySelector(`link[hreflang="${item.hreflang}"]`)) {
48
+ document.querySelector('head').appendChild(link);
49
+ }
50
+ });
51
+
52
+
53
+ Object.defineProperty(navigator, 'languages', {
54
+ value: originalLanguages,
55
+ writable: true
56
+ });
57
+
58
+
59
+ })
60
+
61
+ // Hilfsfunktion zum Setup eines JSDOM-Dokuments mit <html> und ggf. link-Tags
62
+ function setupDOM({htmlLang = '', linkHreflangs = [], navLang = ""}) {
63
+
64
+ linkTags = Array.from(document.querySelectorAll('link[rel="alternate"]'));
65
+ linkTags.forEach(item => item.remove());
66
+
67
+ // Links hinzufügen
68
+ const head = window.document.querySelector('head');
69
+ linkHreflangs.forEach(item => {
70
+ const link = window.document.createElement('link');
71
+ link.setAttribute('rel', 'alternate');
72
+ link.setAttribute('hreflang', item.hreflang);
73
+ link.setAttribute('href', item.href);
74
+ head.appendChild(link);
75
+ });
76
+
77
+ window.document.documentElement.lang = htmlLang;
78
+
79
+
80
+ Object.defineProperty(navigator, 'language', {
81
+ value: navLang[0] || "",
82
+ writable: true
83
+ });
84
+
85
+ Object.defineProperty(navigator, 'languages', {
86
+ value: navLang,
87
+ writable: true
88
+ });
89
+ }
90
+
91
+ describe('getPreferredLanguage()', () => {
92
+
93
+ // 1) No document language, no navigator.languages => "No language information available."
94
+ it('should return "No language information available." when no current and no user preferences', () => {
95
+ setupDOM({htmlLang: '', linkHreflangs: [], navLang: []});
96
+
97
+ const result = getPreferredLanguage();
98
+ expect(result).to.have.property('message').that.not.empty;
99
+ });
100
+
101
+ // 2) Document lang is set, but no <link> tags => "No <link> tags with hreflang available."
102
+ it('should return "No <link> tags with hreflang available." when there are no link tags', () => {
103
+ setupDOM({htmlLang: 'en', linkHreflangs: []});
104
+ window.navigator.languages = [];
105
+
106
+ const result = getPreferredLanguage();
107
+ expect(result).to.have.property('current', 'en');
108
+ expect(result).to.have.property('message').that.equals('No <link> tags with hreflang available.');
109
+ });
110
+
111
+ // 3) Document lang 'en', no user preferences, but link tags exist => "None of the preferred languages are available."
112
+ it('should return "None of the preferred languages are available." when there are link tags but no matching user preferences', () => {
113
+ setupDOM({
114
+ htmlLang: 'en',
115
+ linkHreflangs: [
116
+ {hreflang: 'de', href: 'http://example.com/de'},
117
+ {hreflang: 'fr', href: 'http://example.com/fr'}
118
+ ],
119
+ navLang: []
120
+ });
121
+
122
+ const result = getPreferredLanguage();
123
+ expect(result).to.have.property('current', 'en');
124
+ expect(result).to.have.property('message').that.equals('No available languages match the user\'s preferences.');
125
+ expect(result.available).to.be.an('array').that.has.lengthOf(2);
126
+ });
127
+
128
+ // 4) Document lang 'en', user prefers ['en'], link tags with 'en' and 'de' => best match is 'en'
129
+ it('should return best match = "en" when user prefers en', () => {
130
+ setupDOM({
131
+ htmlLang: 'en',
132
+ linkHreflangs: [
133
+ {hreflang: 'en', href: 'http://example.com/en'},
134
+ {hreflang: 'de', href: 'http://example.com/de'}
135
+ ]
136
+ });
137
+ window.navigator.languages = ['en'];
138
+
139
+ const result = getPreferredLanguage();
140
+ expect(result).to.have.property('current', 'en');
141
+ console.log(JSON.stringify(result.preferred));
142
+ expect(result.preferred).to.have.property('full', "en");
143
+ expect(result.preferred).to.have.property('base', "en");
144
+ expect(result.preferred).to.have.property('label', "English");
145
+ expect(result.preferred).to.have.property('href', "http://example.com/en");
146
+ });
147
+
148
+ // 5) Document lang 'de-DE', user prefers ['de-DE'], link tags with 'de-DE' & 'en-US' => best match is 'de-DE'
149
+ it('should return best match = "de-DE" when user prefers de-DE', () => {
150
+ setupDOM({
151
+ htmlLang: 'de-DE',
152
+ linkHreflangs: [
153
+ {hreflang: 'de-DE', href: 'http://example.com/de-DE'},
154
+ {hreflang: 'en-US', href: 'http://example.com/en-US'}
155
+ ]
156
+ });
157
+ window.navigator.languages = ['de-DE'];
158
+
159
+ const result = getPreferredLanguage();
160
+ expect(result).to.have.property('current', 'de-DE');
161
+
162
+ expect(result.preferred).to.have.property('full', "de-DE");
163
+ expect(result.preferred).to.have.property('base', "de");
164
+ expect(result.preferred).to.have.property('label', "Deutsch (Deutschland)");
165
+ expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
166
+
167
+ });
168
+
169
+
170
+ // 5x) Document lang 'de-DE', user prefers ['de-DE'], link tags with 'de-DE' & 'en-US' => best match is 'de-DE'
171
+ it('should return best match = "de-DE" when user prefers de-DE', () => {
172
+ setupDOM({
173
+ htmlLang: 'en',
174
+ linkHreflangs: [
175
+ {hreflang: 'de', href: 'http://example.com/de-DE'},
176
+ {hreflang: 'en', href: 'http://example.com/en-US'}
177
+ ]
178
+ });
179
+ window.navigator.languages = ['de-DE'];
180
+
181
+ const result = getPreferredLanguage();
182
+ expect(result).to.have.property('current', 'en');
183
+
184
+ expect(result.preferred).to.have.property('full', "de");
185
+ expect(result.preferred).to.have.property('base', "de");
186
+ expect(result.preferred).to.have.property('label', "Deutsch");
187
+ expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
188
+
189
+ });
190
+
191
+ // 6) Document lang 'de-DE', user prefers ['en-US', 'en'], link tags with 'en-US' & 'en-GB' => best match = 'en-US'
192
+ it('should return best match = "en-US" for user preferences [en-US, en]', () => {
193
+ setupDOM({
194
+ htmlLang: 'de-DE',
195
+ linkHreflangs: [
196
+ {hreflang: 'en-US', href: 'http://example.com/en-US'},
197
+ {hreflang: 'en-GB', href: 'http://example.com/en-GB'}
198
+ ]
199
+ });
200
+ window.navigator.languages = ['en-US', 'en'];
201
+
202
+ const result = getPreferredLanguage();
203
+ expect(result).to.have.property('current', 'de-DE');
204
+ expect(result.preferred).to.have.property('full', "en-US");
205
+ expect(result.preferred).to.have.property('base', "en");
206
+ expect(result.preferred).to.have.property('label', "English (United States)");
207
+ expect(result.preferred).to.have.property('href', "http://example.com/en-US");
208
+
209
+ });
210
+
211
+ // 7) Document lang 'de-DE', user prefers ['de','en'], link tags with 'de-DE' & 'en-US' => best match = 'de-DE' (baseLang = 'de')
212
+ it('should return best match = "de-DE" when user preferences include its base language "de"', () => {
213
+ setupDOM({
214
+ htmlLang: 'de-DE',
215
+ linkHreflangs: [
216
+ {hreflang: 'de-DE', href: 'http://example.com/de-DE'},
217
+ {hreflang: 'en-US', href: 'http://example.com/en-US'}
218
+ ]
219
+ });
220
+ window.navigator.languages = ['de', 'en'];
221
+
222
+ const result = getPreferredLanguage();
223
+ expect(result).to.have.property('current', 'de-DE');
224
+
225
+ expect(result.preferred).to.have.property('full', "de-DE");
226
+ expect(result.preferred).to.have.property('base', "de");
227
+ expect(result.preferred).to.have.property('label', "Deutsch (Deutschland)");
228
+ expect(result.preferred).to.have.property('href', "http://example.com/de-DE");
229
+
230
+ });
231
+
232
+ // 8) Multiple link tags share the same weight => the first in the sorted array should be returned
233
+ it('should return the first item when multiple link tags have the same weight', () => {
234
+ setupDOM({
235
+ htmlLang: 'en',
236
+ linkHreflangs: [
237
+ {hreflang: 'fr', href: 'http://example.com/fr'},
238
+ {hreflang: 'es', href: 'http://example.com/es'}
239
+ ]
240
+ });
241
+ // Neither "fr" nor "es" is in the user preferences => both have weight = 1
242
+ window.navigator.languages = ['de'];
243
+
244
+ const result = getPreferredLanguage();
245
+ // Both 'fr' and 'es' have weight 1. After sorting, 'fr' appears first (as it was added first).
246
+ expect(result.available[0].fullLang).to.equal('fr');
247
+ expect(result.available[1].fullLang).to.equal('es');
248
+ expect(result.offerable).to.be.undefined;
249
+ expect(result).to.have.property('message', 'No available languages match the user\'s preferences.');
250
+ });
251
+
252
+ // 9) Check that bestURL is returned if a best match is found
253
+ it('should include bestURL when a best match is found', () => {
254
+ setupDOM({
255
+ htmlLang: 'fr',
256
+ linkHreflangs: [
257
+ {hreflang: 'fr-FR', href: 'http://example.com/fr-FR'},
258
+ {hreflang: 'de-DE', href: 'http://example.com/de-DE'}
259
+ ]
260
+ });
261
+ window.navigator.languages = ['fr-FR', 'de-DE'];
262
+
263
+ const result = getPreferredLanguage();
264
+
265
+ expect(result.preferred).to.have.property('full', "fr-FR");
266
+ expect(result.preferred).to.have.property('base', "fr");
267
+ expect(result.preferred).to.have.property('label', "Français (France)");
268
+ expect(result.preferred).to.have.property('href', "http://example.com/fr-FR");
269
+
270
+ });
271
+
272
+ // 10) Check presence of availableLanguages array, ensuring it has weight info
273
+ it('should return availableLanguages with weight for each link', () => {
274
+ setupDOM({
275
+ htmlLang: 'en-GB',
276
+ linkHreflangs: [
277
+ {hreflang: 'en-GB', href: 'http://example.com/en-GB'},
278
+ {hreflang: 'en-US', href: 'http://example.com/en-US'}
279
+ ]
280
+ });
281
+ window.navigator.languages = ['en-GB', 'en', 'en-US'];
282
+
283
+ const result = getPreferredLanguage();
284
+ expect(result.available).to.be.an('array').with.lengthOf(2);
285
+ result.available.forEach(item => {
286
+ expect(item).to.have.property('weight');
287
+ expect(item).to.have.property('fullLang');
288
+ expect(item).to.have.property('baseLang');
289
+ expect(item).to.have.property('href');
290
+ });
291
+ });
292
+
293
+ });
294
+
295
+ })