willba-component-library 0.3.26 → 0.4.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 (159) hide show
  1. package/README.md +75 -113
  2. package/lib/components/FilterBar/FilterBar.d.ts +1 -1
  3. package/lib/components/FilterCalendar/FilterCalendar.d.ts +1 -1
  4. package/lib/core/i18n/I18nProvider.d.ts +6 -0
  5. package/lib/core/i18n/index.d.ts +1 -0
  6. package/lib/embed.d.ts +18 -0
  7. package/lib/embed.esm.js +74 -0
  8. package/lib/embed.esm.js.map +1 -0
  9. package/lib/embed.umd.js +74 -0
  10. package/lib/embed.umd.js.map +1 -0
  11. package/lib/i18n.d.ts +2 -2
  12. package/lib/index.d.ts +2 -2
  13. package/lib/index.esm.js +1112 -931
  14. package/lib/index.esm.js.map +1 -1
  15. package/lib/index.js +1111 -930
  16. package/lib/index.js.map +1 -1
  17. package/package.json +9 -1
  18. package/.nvmrc +0 -1
  19. package/.storybook/main.ts +0 -17
  20. package/.storybook/preview.ts +0 -15
  21. package/lib/components/FilterBar/components/buttons/index.d.ts +0 -4
  22. package/lib/components/FilterBar/components/buttons/select-button/SelectButton.d.ts +0 -13
  23. package/lib/components/FilterBar/components/buttons/tab-button/TabButton.d.ts +0 -10
  24. package/lib/components/FilterBar/components/cards/image-card/ImageCard.d.ts +0 -11
  25. package/lib/components/FilterBar/components/cards/index.d.ts +0 -1
  26. package/lib/components/FilterBar/components/categories/Categories.d.ts +0 -8
  27. package/lib/components/FilterBar/components/common/FilterSectionHeader.d.ts +0 -8
  28. package/lib/components/FilterBar/components/dates/Dates.d.ts +0 -17
  29. package/lib/components/FilterBar/components/dates/index.d.ts +0 -1
  30. package/lib/components/FilterBar/components/guests/GuestCount/GuestCount.d.ts +0 -4
  31. package/lib/components/FilterBar/components/guests/Guests.d.ts +0 -12
  32. package/lib/components/FilterBar/components/locations/Locations.d.ts +0 -14
  33. package/lib/components/FilterBar/hooks/useFilterBar.d.ts +0 -32
  34. package/lib/components/FilterBar/hooks/useFilterUi.d.ts +0 -8
  35. package/lib/components/FilterBar/utils/calculateDropdownPosition.d.ts +0 -12
  36. package/lib/components/FilterBar/utils/getLocalizedContent.d.ts +0 -8
  37. package/lib/core/components/buttons/close-button/CloseButton.d.ts +0 -7
  38. package/lib/core/components/buttons/submit-button/SubmitButton.d.ts +0 -14
  39. package/lib/index.umd.js +0 -12489
  40. package/lib/index.umd.js.map +0 -1
  41. package/prettier.config.js +0 -6
  42. package/rollup.config.mjs +0 -63
  43. package/src/assets/IconsSvg.tsx +0 -69
  44. package/src/components/Button/Button.stories.tsx +0 -34
  45. package/src/components/Button/Button.tsx +0 -56
  46. package/src/components/Button/button.css +0 -30
  47. package/src/components/Button/index.ts +0 -1
  48. package/src/components/FilterBar/FilterBar.css +0 -35
  49. package/src/components/FilterBar/FilterBar.stories.tsx +0 -116
  50. package/src/components/FilterBar/FilterBar.tsx +0 -64
  51. package/src/components/FilterBar/FilterBarTypes.ts +0 -71
  52. package/src/components/FilterBar/components/Divider/Divider.css +0 -14
  53. package/src/components/FilterBar/components/Divider/Divider.tsx +0 -7
  54. package/src/components/FilterBar/components/FilterControls/FilterControls.css +0 -22
  55. package/src/components/FilterBar/components/FilterControls/FilterControls.tsx +0 -139
  56. package/src/components/FilterBar/components/FilterPanels/Categories/Categories.css +0 -21
  57. package/src/components/FilterBar/components/FilterPanels/Categories/Categories.tsx +0 -49
  58. package/src/components/FilterBar/components/FilterPanels/Dates/Dates.css +0 -9
  59. package/src/components/FilterBar/components/FilterPanels/Dates/Dates.tsx +0 -60
  60. package/src/components/FilterBar/components/FilterPanels/FilterPanels.css +0 -22
  61. package/src/components/FilterBar/components/FilterPanels/FilterPanels.tsx +0 -111
  62. package/src/components/FilterBar/components/FilterPanels/Guests/GuestCount/GuestCount.css +0 -58
  63. package/src/components/FilterBar/components/FilterPanels/Guests/GuestCount/GuestCount.tsx +0 -85
  64. package/src/components/FilterBar/components/FilterPanels/Guests/Guests.css +0 -24
  65. package/src/components/FilterBar/components/FilterPanels/Guests/Guests.tsx +0 -59
  66. package/src/components/FilterBar/components/FilterPanels/Locations/Locations.css +0 -16
  67. package/src/components/FilterBar/components/FilterPanels/Locations/Locations.tsx +0 -94
  68. package/src/components/FilterBar/components/FilterPanels/SectionHeader/SectionHeader.css +0 -34
  69. package/src/components/FilterBar/components/FilterPanels/SectionHeader/SectionHeader.tsx +0 -17
  70. package/src/components/FilterBar/components/FilterTabs/FilterTabs.css +0 -10
  71. package/src/components/FilterBar/components/FilterTabs/FilterTabs.tsx +0 -50
  72. package/src/components/FilterBar/components/ImageCard/ImageCard.css +0 -30
  73. package/src/components/FilterBar/components/ImageCard/ImageCard.tsx +0 -45
  74. package/src/components/FilterBar/components/SelectButton/SelectButton.css +0 -76
  75. package/src/components/FilterBar/components/SelectButton/SelectButton.tsx +0 -54
  76. package/src/components/FilterBar/components/TabButton/TabButton.css +0 -36
  77. package/src/components/FilterBar/components/TabButton/TabButton.tsx +0 -23
  78. package/src/components/FilterBar/components/index.ts +0 -6
  79. package/src/components/FilterBar/hooks/index.ts +0 -5
  80. package/src/components/FilterBar/hooks/useFilterActions.tsx +0 -126
  81. package/src/components/FilterBar/hooks/useFilterRefs.tsx +0 -21
  82. package/src/components/FilterBar/hooks/useFilterState.tsx +0 -86
  83. package/src/components/FilterBar/hooks/usePanelPosition.tsx +0 -52
  84. package/src/components/FilterBar/hooks/useScrollInToView.tsx +0 -29
  85. package/src/components/FilterBar/index.ts +0 -3
  86. package/src/components/FilterBar/providers/FilterBarProvider.tsx +0 -172
  87. package/src/components/FilterBar/providers/index.ts +0 -1
  88. package/src/components/FilterBar/utils/ageCategoriesRules.ts +0 -27
  89. package/src/components/FilterBar/utils/index.tsx +0 -3
  90. package/src/components/FilterBar/utils/parseGuests.tsx +0 -65
  91. package/src/components/FilterBar/utils/parseLocations.ts +0 -28
  92. package/src/components/FilterCalendar/FilterCalendar.css +0 -109
  93. package/src/components/FilterCalendar/FilterCalendar.stories.tsx +0 -554
  94. package/src/components/FilterCalendar/FilterCalendar.tsx +0 -115
  95. package/src/components/FilterCalendar/FilterCalendarTypes.ts +0 -11
  96. package/src/components/FilterCalendar/components/Footer.tsx +0 -96
  97. package/src/components/FilterCalendar/hooks/useFilterCalendar.ts +0 -163
  98. package/src/components/FilterCalendar/index.ts +0 -3
  99. package/src/core/components/buttons/CloseButton/CloseButton.css +0 -33
  100. package/src/core/components/buttons/CloseButton/CloseButton.tsx +0 -16
  101. package/src/core/components/buttons/SubmitButton/SubmitButton.css +0 -54
  102. package/src/core/components/buttons/SubmitButton/SubmitButton.tsx +0 -42
  103. package/src/core/components/calendar/Calendar.css +0 -280
  104. package/src/core/components/calendar/Calendar.tsx +0 -253
  105. package/src/core/components/calendar/CalendarTypes.ts +0 -48
  106. package/src/core/components/calendar/hooks/index.ts +0 -3
  107. package/src/core/components/calendar/hooks/useCalendarLoadingSpinner.tsx +0 -19
  108. package/src/core/components/calendar/hooks/useCalendarTooltips.tsx +0 -125
  109. package/src/core/components/calendar/hooks/useUpdateDisabledDates.tsx +0 -105
  110. package/src/core/components/calendar/utils/calendarSelectionRules.tsx +0 -180
  111. package/src/core/components/calendar/utils/checkForContinuousSelection.tsx +0 -86
  112. package/src/core/components/calendar/utils/disabledDatesByPage.tsx +0 -31
  113. package/src/core/components/calendar/utils/handleCalendarModifiers.tsx +0 -118
  114. package/src/core/components/calendar/utils/handleRangeContextDisabledDates.tsx +0 -75
  115. package/src/core/components/calendar/utils/index.ts +0 -8
  116. package/src/core/components/calendar/utils/nightsCount.tsx +0 -19
  117. package/src/core/components/calendar/utils/parseDate.tsx +0 -17
  118. package/src/core/components/calendar/utils/parseDates.tsx +0 -12
  119. package/src/core/components/index.ts +0 -7
  120. package/src/core/hooks/index.ts +0 -4
  121. package/src/core/hooks/useAutoFocus.tsx +0 -27
  122. package/src/core/hooks/useAwaitRender.tsx +0 -12
  123. package/src/core/hooks/useCloseFilterSection.tsx +0 -29
  124. package/src/core/hooks/useUpdateTranslations.tsx +0 -14
  125. package/src/i18n.ts +0 -27
  126. package/src/index.ts +0 -8
  127. package/src/locales/en/common.json +0 -18
  128. package/src/locales/en/filterBar.json +0 -33
  129. package/src/locales/fi/common.json +0 -19
  130. package/src/locales/fi/filterBar.json +0 -33
  131. package/src/themes/Default.css +0 -69
  132. package/src/themes/useTheme.tsx +0 -27
  133. package/stories/Button.stories.ts +0 -50
  134. package/stories/Button.tsx +0 -53
  135. package/stories/Configure.mdx +0 -364
  136. package/stories/Header.stories.ts +0 -27
  137. package/stories/Header.tsx +0 -70
  138. package/stories/Page.stories.ts +0 -29
  139. package/stories/Page.tsx +0 -91
  140. package/stories/assets/accessibility.png +0 -0
  141. package/stories/assets/accessibility.svg +0 -5
  142. package/stories/assets/addon-library.png +0 -0
  143. package/stories/assets/assets.png +0 -0
  144. package/stories/assets/context.png +0 -0
  145. package/stories/assets/discord.svg +0 -15
  146. package/stories/assets/docs.png +0 -0
  147. package/stories/assets/figma-plugin.png +0 -0
  148. package/stories/assets/github.svg +0 -3
  149. package/stories/assets/share.png +0 -0
  150. package/stories/assets/styling.png +0 -0
  151. package/stories/assets/testing.png +0 -0
  152. package/stories/assets/theming.png +0 -0
  153. package/stories/assets/tutorials.svg +0 -12
  154. package/stories/assets/youtube.svg +0 -4
  155. package/stories/button.css +0 -30
  156. package/stories/header.css +0 -32
  157. package/stories/page.css +0 -69
  158. package/tsconfig.json +0 -29
  159. /package/lib/components/FilterBar/components/{divider → Divider}/Divider.d.ts +0 -0
package/lib/index.js CHANGED
@@ -242,6 +242,331 @@ var useAwaitRender = function () {
242
242
  return null;
243
243
  };
244
244
 
245
+ function warn() {
246
+ if (console && console.warn) {
247
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
248
+ args[_key] = arguments[_key];
249
+ }
250
+ if (typeof args[0] === 'string') args[0] = `react-i18next:: ${args[0]}`;
251
+ console.warn(...args);
252
+ }
253
+ }
254
+ const alreadyWarned = {};
255
+ function warnOnce() {
256
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
257
+ args[_key2] = arguments[_key2];
258
+ }
259
+ if (typeof args[0] === 'string' && alreadyWarned[args[0]]) return;
260
+ if (typeof args[0] === 'string') alreadyWarned[args[0]] = new Date();
261
+ warn(...args);
262
+ }
263
+ const loadedClb = (i18n, cb) => () => {
264
+ if (i18n.isInitialized) {
265
+ cb();
266
+ } else {
267
+ const initialized = () => {
268
+ setTimeout(() => {
269
+ i18n.off('initialized', initialized);
270
+ }, 0);
271
+ cb();
272
+ };
273
+ i18n.on('initialized', initialized);
274
+ }
275
+ };
276
+ function loadNamespaces(i18n, ns, cb) {
277
+ i18n.loadNamespaces(ns, loadedClb(i18n, cb));
278
+ }
279
+ function loadLanguages(i18n, lng, ns, cb) {
280
+ if (typeof ns === 'string') ns = [ns];
281
+ ns.forEach(n => {
282
+ if (i18n.options.ns.indexOf(n) < 0) i18n.options.ns.push(n);
283
+ });
284
+ i18n.loadLanguages(lng, loadedClb(i18n, cb));
285
+ }
286
+ function oldI18nextHasLoadedNamespace(ns, i18n) {
287
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
288
+ const lng = i18n.languages[0];
289
+ const fallbackLng = i18n.options ? i18n.options.fallbackLng : false;
290
+ const lastLng = i18n.languages[i18n.languages.length - 1];
291
+ if (lng.toLowerCase() === 'cimode') return true;
292
+ const loadNotPending = (l, n) => {
293
+ const loadState = i18n.services.backendConnector.state[`${l}|${n}`];
294
+ return loadState === -1 || loadState === 2;
295
+ };
296
+ if (options.bindI18n && options.bindI18n.indexOf('languageChanging') > -1 && i18n.services.backendConnector.backend && i18n.isLanguageChangingTo && !loadNotPending(i18n.isLanguageChangingTo, ns)) return false;
297
+ if (i18n.hasResourceBundle(lng, ns)) return true;
298
+ if (!i18n.services.backendConnector.backend || i18n.options.resources && !i18n.options.partialBundledLanguages) return true;
299
+ if (loadNotPending(lng, ns) && (!fallbackLng || loadNotPending(lastLng, ns))) return true;
300
+ return false;
301
+ }
302
+ function hasLoadedNamespace(ns, i18n) {
303
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
304
+ if (!i18n.languages || !i18n.languages.length) {
305
+ warnOnce('i18n.languages were undefined or empty', i18n.languages);
306
+ return true;
307
+ }
308
+ const isNewerI18next = i18n.options.ignoreJSONStructure !== undefined;
309
+ if (!isNewerI18next) {
310
+ return oldI18nextHasLoadedNamespace(ns, i18n, options);
311
+ }
312
+ return i18n.hasLoadedNamespace(ns, {
313
+ lng: options.lng,
314
+ precheck: (i18nInstance, loadNotPending) => {
315
+ if (options.bindI18n && options.bindI18n.indexOf('languageChanging') > -1 && i18nInstance.services.backendConnector.backend && i18nInstance.isLanguageChangingTo && !loadNotPending(i18nInstance.isLanguageChangingTo, ns)) return false;
316
+ }
317
+ });
318
+ }
319
+
320
+ const matchHtmlEntity = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g;
321
+ const htmlEntities = {
322
+ '&amp;': '&',
323
+ '&#38;': '&',
324
+ '&lt;': '<',
325
+ '&#60;': '<',
326
+ '&gt;': '>',
327
+ '&#62;': '>',
328
+ '&apos;': "'",
329
+ '&#39;': "'",
330
+ '&quot;': '"',
331
+ '&#34;': '"',
332
+ '&nbsp;': ' ',
333
+ '&#160;': ' ',
334
+ '&copy;': '©',
335
+ '&#169;': '©',
336
+ '&reg;': '®',
337
+ '&#174;': '®',
338
+ '&hellip;': '…',
339
+ '&#8230;': '…',
340
+ '&#x2F;': '/',
341
+ '&#47;': '/'
342
+ };
343
+ const unescapeHtmlEntity = m => htmlEntities[m];
344
+ const unescape = text => text.replace(matchHtmlEntity, unescapeHtmlEntity);
345
+
346
+ let defaultOptions$1 = {
347
+ bindI18n: 'languageChanged',
348
+ bindI18nStore: '',
349
+ transEmptyNodeValue: '',
350
+ transSupportBasicHtmlNodes: true,
351
+ transWrapTextNodes: '',
352
+ transKeepBasicHtmlNodesFor: ['br', 'strong', 'i', 'p'],
353
+ useSuspense: true,
354
+ unescape
355
+ };
356
+ function setDefaults() {
357
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
358
+ defaultOptions$1 = {
359
+ ...defaultOptions$1,
360
+ ...options
361
+ };
362
+ }
363
+ function getDefaults() {
364
+ return defaultOptions$1;
365
+ }
366
+
367
+ let i18nInstance;
368
+ function setI18n(instance) {
369
+ i18nInstance = instance;
370
+ }
371
+ function getI18n() {
372
+ return i18nInstance;
373
+ }
374
+
375
+ const initReactI18next = {
376
+ type: '3rdParty',
377
+ init(instance) {
378
+ setDefaults(instance.options.react);
379
+ setI18n(instance);
380
+ }
381
+ };
382
+
383
+ const I18nContext = React.createContext();
384
+ class ReportNamespaces {
385
+ constructor() {
386
+ this.usedNamespaces = {};
387
+ }
388
+ addUsedNamespaces(namespaces) {
389
+ namespaces.forEach(ns => {
390
+ if (!this.usedNamespaces[ns]) this.usedNamespaces[ns] = true;
391
+ });
392
+ }
393
+ getUsedNamespaces() {
394
+ return Object.keys(this.usedNamespaces);
395
+ }
396
+ }
397
+
398
+ const usePrevious = (value, ignore) => {
399
+ const ref = React.useRef();
400
+ React.useEffect(() => {
401
+ ref.current = ignore ? ref.current : value;
402
+ }, [value, ignore]);
403
+ return ref.current;
404
+ };
405
+ function useTranslation(ns) {
406
+ let props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
407
+ const {
408
+ i18n: i18nFromProps
409
+ } = props;
410
+ const {
411
+ i18n: i18nFromContext,
412
+ defaultNS: defaultNSFromContext
413
+ } = React.useContext(I18nContext) || {};
414
+ const i18n = i18nFromProps || i18nFromContext || getI18n();
415
+ if (i18n && !i18n.reportNamespaces) i18n.reportNamespaces = new ReportNamespaces();
416
+ if (!i18n) {
417
+ warnOnce('You will need to pass in an i18next instance by using initReactI18next');
418
+ const notReadyT = (k, optsOrDefaultValue) => {
419
+ if (typeof optsOrDefaultValue === 'string') return optsOrDefaultValue;
420
+ if (optsOrDefaultValue && typeof optsOrDefaultValue === 'object' && typeof optsOrDefaultValue.defaultValue === 'string') return optsOrDefaultValue.defaultValue;
421
+ return Array.isArray(k) ? k[k.length - 1] : k;
422
+ };
423
+ const retNotReady = [notReadyT, {}, false];
424
+ retNotReady.t = notReadyT;
425
+ retNotReady.i18n = {};
426
+ retNotReady.ready = false;
427
+ return retNotReady;
428
+ }
429
+ if (i18n.options.react && i18n.options.react.wait !== undefined) warnOnce('It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.');
430
+ const i18nOptions = {
431
+ ...getDefaults(),
432
+ ...i18n.options.react,
433
+ ...props
434
+ };
435
+ const {
436
+ useSuspense,
437
+ keyPrefix
438
+ } = i18nOptions;
439
+ let namespaces = ns || defaultNSFromContext || i18n.options && i18n.options.defaultNS;
440
+ namespaces = typeof namespaces === 'string' ? [namespaces] : namespaces || ['translation'];
441
+ if (i18n.reportNamespaces.addUsedNamespaces) i18n.reportNamespaces.addUsedNamespaces(namespaces);
442
+ const ready = (i18n.isInitialized || i18n.initializedStoreOnce) && namespaces.every(n => hasLoadedNamespace(n, i18n, i18nOptions));
443
+ function getT() {
444
+ return i18n.getFixedT(props.lng || null, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix);
445
+ }
446
+ const [t, setT] = React.useState(getT);
447
+ let joinedNS = namespaces.join();
448
+ if (props.lng) joinedNS = `${props.lng}${joinedNS}`;
449
+ const previousJoinedNS = usePrevious(joinedNS);
450
+ const isMounted = React.useRef(true);
451
+ React.useEffect(() => {
452
+ const {
453
+ bindI18n,
454
+ bindI18nStore
455
+ } = i18nOptions;
456
+ isMounted.current = true;
457
+ if (!ready && !useSuspense) {
458
+ if (props.lng) {
459
+ loadLanguages(i18n, props.lng, namespaces, () => {
460
+ if (isMounted.current) setT(getT);
461
+ });
462
+ } else {
463
+ loadNamespaces(i18n, namespaces, () => {
464
+ if (isMounted.current) setT(getT);
465
+ });
466
+ }
467
+ }
468
+ if (ready && previousJoinedNS && previousJoinedNS !== joinedNS && isMounted.current) {
469
+ setT(getT);
470
+ }
471
+ function boundReset() {
472
+ if (isMounted.current) setT(getT);
473
+ }
474
+ if (bindI18n && i18n) i18n.on(bindI18n, boundReset);
475
+ if (bindI18nStore && i18n) i18n.store.on(bindI18nStore, boundReset);
476
+ return () => {
477
+ isMounted.current = false;
478
+ if (bindI18n && i18n) bindI18n.split(' ').forEach(e => i18n.off(e, boundReset));
479
+ if (bindI18nStore && i18n) bindI18nStore.split(' ').forEach(e => i18n.store.off(e, boundReset));
480
+ };
481
+ }, [i18n, joinedNS]);
482
+ const isInitial = React.useRef(true);
483
+ React.useEffect(() => {
484
+ if (isMounted.current && !isInitial.current) {
485
+ setT(getT);
486
+ }
487
+ isInitial.current = false;
488
+ }, [i18n, keyPrefix]);
489
+ const ret = [t, i18n, ready];
490
+ ret.t = t;
491
+ ret.i18n = i18n;
492
+ ret.ready = ready;
493
+ if (ready) return ret;
494
+ if (!ready && !useSuspense) return ret;
495
+ throw new Promise(resolve => {
496
+ if (props.lng) {
497
+ loadLanguages(i18n, props.lng, namespaces, () => resolve());
498
+ } else {
499
+ loadNamespaces(i18n, namespaces, () => resolve());
500
+ }
501
+ });
502
+ }
503
+
504
+ function I18nextProvider(_ref) {
505
+ let {
506
+ i18n,
507
+ defaultNS,
508
+ children
509
+ } = _ref;
510
+ const value = React.useMemo(() => ({
511
+ i18n,
512
+ defaultNS
513
+ }), [i18n, defaultNS]);
514
+ return React.createElement(I18nContext.Provider, {
515
+ value
516
+ }, children);
517
+ }
518
+
519
+ var useUpdateTranslations = function (_a) {
520
+ var language = _a.language;
521
+ var i18n = useTranslation().i18n;
522
+ React.useEffect(function () {
523
+ if (language && i18n.language !== language) {
524
+ i18n.changeLanguage(language);
525
+ }
526
+ }, [language, i18n]);
527
+ };
528
+
529
+ // TODO - Refactor and rename this hook
530
+ var useCloseFilterSection = function (_a) {
531
+ var handleSelectedFilter = _a.handleSelectedFilter;
532
+ var filterSectionRef = React.useRef(null);
533
+ React.useEffect(function () {
534
+ var handleClickOutside = function (event) {
535
+ if (filterSectionRef.current &&
536
+ !filterSectionRef.current.contains(event.target)) {
537
+ handleSelectedFilter(false);
538
+ }
539
+ };
540
+ document.addEventListener('mousedown', handleClickOutside);
541
+ return function () {
542
+ document.removeEventListener('mousedown', handleClickOutside);
543
+ };
544
+ }, [filterSectionRef]);
545
+ return { filterSectionRef: filterSectionRef };
546
+ };
547
+
548
+ var useAutoFocus = function (autoFocus) {
549
+ var ref = React.useRef(null);
550
+ React.useEffect(function () {
551
+ if (!autoFocus || !ref.current)
552
+ return;
553
+ var attemptFocus = function (attempts) {
554
+ if (attempts === void 0) { attempts = 0; }
555
+ if (attempts > 20 || !ref.current)
556
+ return;
557
+ var focusable = ref.current.querySelector('button:not([disabled]), [tabindex]:not([tabindex="-1"])');
558
+ if (focusable) {
559
+ focusable.focus();
560
+ }
561
+ else {
562
+ requestAnimationFrame(function () { return attemptFocus(attempts + 1); });
563
+ }
564
+ };
565
+ requestAnimationFrame(function () { return attemptFocus(); });
566
+ }, [autoFocus]);
567
+ return ref;
568
+ };
569
+
245
570
  const isString = obj => typeof obj === 'string';
246
571
  const defer = () => {
247
572
  let res;
@@ -302,7 +627,7 @@ const setPath = (object, path, newValue) => {
302
627
  e = `${p[p.length - 1]}.${e}`;
303
628
  p = p.slice(0, p.length - 1);
304
629
  last = getLastOfPath(object, p, Object);
305
- if (last?.obj && typeof last.obj[`${last.k}.${e}`] !== 'undefined') {
630
+ if (last && last.obj && typeof last.obj[`${last.k}.${e}`] !== 'undefined') {
306
631
  last.obj = undefined;
307
632
  }
308
633
  }
@@ -322,7 +647,6 @@ const getPath = (object, path) => {
322
647
  k
323
648
  } = getLastOfPath(object, path);
324
649
  if (!obj) return undefined;
325
- if (!Object.prototype.hasOwnProperty.call(obj, k)) return undefined;
326
650
  return obj[k];
327
651
  };
328
652
  const getPathWithDefaults = (data, defaultData, key) => {
@@ -400,12 +724,10 @@ const looksLikeObjectPath = (key, nsSeparator, keySeparator) => {
400
724
  }
401
725
  return matched;
402
726
  };
403
- const deepFind = (obj, path, keySeparator = '.') => {
727
+ const deepFind = function (obj, path) {
728
+ let keySeparator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '.';
404
729
  if (!obj) return undefined;
405
- if (obj[path]) {
406
- if (!Object.prototype.hasOwnProperty.call(obj, path)) return undefined;
407
- return obj[path];
408
- }
730
+ if (obj[path]) return obj[path];
409
731
  const tokens = path.split(keySeparator);
410
732
  let current = obj;
411
733
  for (let i = 0; i < tokens.length;) {
@@ -432,7 +754,7 @@ const deepFind = (obj, path, keySeparator = '.') => {
432
754
  }
433
755
  return current;
434
756
  };
435
- const getCleanedCode = code => code?.replace('_', '-');
757
+ const getCleanedCode = code => code && code.replace('_', '-');
436
758
 
437
759
  const consoleLogger = {
438
760
  type: 'logger',
@@ -446,29 +768,43 @@ const consoleLogger = {
446
768
  this.output('error', args);
447
769
  },
448
770
  output(type, args) {
449
- console?.[type]?.apply?.(console, args);
771
+ if (console && console[type]) console[type].apply(console, args);
450
772
  }
451
773
  };
452
774
  class Logger {
453
- constructor(concreteLogger, options = {}) {
775
+ constructor(concreteLogger) {
776
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
454
777
  this.init(concreteLogger, options);
455
778
  }
456
- init(concreteLogger, options = {}) {
779
+ init(concreteLogger) {
780
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
457
781
  this.prefix = options.prefix || 'i18next:';
458
782
  this.logger = concreteLogger || consoleLogger;
459
783
  this.options = options;
460
784
  this.debug = options.debug;
461
785
  }
462
- log(...args) {
786
+ log() {
787
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
788
+ args[_key] = arguments[_key];
789
+ }
463
790
  return this.forward(args, 'log', '', true);
464
791
  }
465
- warn(...args) {
792
+ warn() {
793
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
794
+ args[_key2] = arguments[_key2];
795
+ }
466
796
  return this.forward(args, 'warn', '', true);
467
797
  }
468
- error(...args) {
798
+ error() {
799
+ for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
800
+ args[_key3] = arguments[_key3];
801
+ }
469
802
  return this.forward(args, 'error', '');
470
803
  }
471
- deprecate(...args) {
804
+ deprecate() {
805
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
806
+ args[_key4] = arguments[_key4];
807
+ }
472
808
  return this.forward(args, 'warn', 'WARNING DEPRECATED: ', true);
473
809
  }
474
810
  forward(args, lvl, prefix, debugOnly) {
@@ -512,10 +848,14 @@ class EventEmitter {
512
848
  }
513
849
  this.observers[event].delete(listener);
514
850
  }
515
- emit(event, ...args) {
851
+ emit(event) {
852
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
853
+ args[_key - 1] = arguments[_key];
854
+ }
516
855
  if (this.observers[event]) {
517
856
  const cloned = Array.from(this.observers[event].entries());
518
- cloned.forEach(([observer, numTimesAdded]) => {
857
+ cloned.forEach(_ref => {
858
+ let [observer, numTimesAdded] = _ref;
519
859
  for (let i = 0; i < numTimesAdded; i++) {
520
860
  observer(...args);
521
861
  }
@@ -523,7 +863,8 @@ class EventEmitter {
523
863
  }
524
864
  if (this.observers['*']) {
525
865
  const cloned = Array.from(this.observers['*'].entries());
526
- cloned.forEach(([observer, numTimesAdded]) => {
866
+ cloned.forEach(_ref2 => {
867
+ let [observer, numTimesAdded] = _ref2;
527
868
  for (let i = 0; i < numTimesAdded; i++) {
528
869
  observer.apply(observer, [event, ...args]);
529
870
  }
@@ -533,10 +874,11 @@ class EventEmitter {
533
874
  }
534
875
 
535
876
  class ResourceStore extends EventEmitter {
536
- constructor(data, options = {
537
- ns: ['translation'],
538
- defaultNS: 'translation'
539
- }) {
877
+ constructor(data) {
878
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
879
+ ns: ['translation'],
880
+ defaultNS: 'translation'
881
+ };
540
882
  super();
541
883
  this.data = data || {};
542
884
  this.options = options;
@@ -558,7 +900,8 @@ class ResourceStore extends EventEmitter {
558
900
  this.options.ns.splice(index, 1);
559
901
  }
560
902
  }
561
- getResource(lng, ns, key, options = {}) {
903
+ getResource(lng, ns, key) {
904
+ let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
562
905
  const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
563
906
  const ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure;
564
907
  let path;
@@ -583,11 +926,12 @@ class ResourceStore extends EventEmitter {
583
926
  key = path.slice(2).join('.');
584
927
  }
585
928
  if (result || !ignoreJSONStructure || !isString(key)) return result;
586
- return deepFind(this.data?.[lng]?.[ns], key, keySeparator);
929
+ return deepFind(this.data && this.data[lng] && this.data[lng][ns], key, keySeparator);
587
930
  }
588
- addResource(lng, ns, key, value, options = {
589
- silent: false
590
- }) {
931
+ addResource(lng, ns, key, value) {
932
+ let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {
933
+ silent: false
934
+ };
591
935
  const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
592
936
  let path = [lng, ns];
593
937
  if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key);
@@ -600,9 +944,10 @@ class ResourceStore extends EventEmitter {
600
944
  setPath(this.data, path, value);
601
945
  if (!options.silent) this.emit('added', lng, ns, key, value);
602
946
  }
603
- addResources(lng, ns, resources, options = {
604
- silent: false
605
- }) {
947
+ addResources(lng, ns, resources) {
948
+ let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
949
+ silent: false
950
+ };
606
951
  for (const m in resources) {
607
952
  if (isString(resources[m]) || Array.isArray(resources[m])) this.addResource(lng, ns, m, resources[m], {
608
953
  silent: true
@@ -610,10 +955,11 @@ class ResourceStore extends EventEmitter {
610
955
  }
611
956
  if (!options.silent) this.emit('added', lng, ns, resources);
612
957
  }
613
- addResourceBundle(lng, ns, resources, deep, overwrite, options = {
614
- silent: false,
615
- skipCopy: false
616
- }) {
958
+ addResourceBundle(lng, ns, resources, deep, overwrite) {
959
+ let options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {
960
+ silent: false,
961
+ skipCopy: false
962
+ };
617
963
  let path = [lng, ns];
618
964
  if (lng.indexOf('.') > -1) {
619
965
  path = lng.split('.');
@@ -647,6 +993,10 @@ class ResourceStore extends EventEmitter {
647
993
  }
648
994
  getResourceBundle(lng, ns) {
649
995
  if (!ns) ns = this.options.defaultNS;
996
+ if (this.options.compatibilityAPI === 'v1') return {
997
+ ...{},
998
+ ...this.getResource(lng, ns)
999
+ };
650
1000
  return this.getResource(lng, ns);
651
1001
  }
652
1002
  getDataByLanguage(lng) {
@@ -669,37 +1019,16 @@ var postProcessor = {
669
1019
  },
670
1020
  handle(processors, value, key, options, translator) {
671
1021
  processors.forEach(processor => {
672
- value = this.processors[processor]?.process(value, key, options, translator) ?? value;
1022
+ if (this.processors[processor]) value = this.processors[processor].process(value, key, options, translator);
673
1023
  });
674
1024
  return value;
675
1025
  }
676
1026
  };
677
1027
 
678
- const PATH_KEY = Symbol('i18next/PATH_KEY');
679
- function createProxy() {
680
- const state = [];
681
- const handler = Object.create(null);
682
- let proxy;
683
- handler.get = (target, key) => {
684
- proxy?.revoke?.();
685
- if (key === PATH_KEY) return state;
686
- state.push(key);
687
- proxy = Proxy.revocable(target, handler);
688
- return proxy.proxy;
689
- };
690
- return Proxy.revocable(Object.create(null), handler).proxy;
691
- }
692
- function keysFromSelector(selector, opts) {
693
- const {
694
- [PATH_KEY]: path
695
- } = selector(createProxy());
696
- return path.join(opts?.keySeparator ?? '.');
697
- }
698
-
699
1028
  const checkedLoadedFor = {};
700
- const shouldHandleAsObject = res => !isString(res) && typeof res !== 'boolean' && typeof res !== 'number';
701
1029
  class Translator extends EventEmitter {
702
- constructor(services, options = {}) {
1030
+ constructor(services) {
1031
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
703
1032
  super();
704
1033
  copy(['resourceStore', 'languageUtils', 'pluralResolver', 'interpolator', 'backendConnector', 'i18nFormat', 'utils'], services, this);
705
1034
  this.options = options;
@@ -711,28 +1040,23 @@ class Translator extends EventEmitter {
711
1040
  changeLanguage(lng) {
712
1041
  if (lng) this.language = lng;
713
1042
  }
714
- exists(key, o = {
715
- interpolation: {}
716
- }) {
717
- const opt = {
718
- ...o
1043
+ exists(key) {
1044
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
1045
+ interpolation: {}
719
1046
  };
720
- if (key == null) return false;
721
- const resolved = this.resolve(key, opt);
722
- if (resolved?.res === undefined) return false;
723
- const isObject = shouldHandleAsObject(resolved.res);
724
- if (opt.returnObjects === false && isObject) {
1047
+ if (key === undefined || key === null) {
725
1048
  return false;
726
1049
  }
727
- return true;
1050
+ const resolved = this.resolve(key, options);
1051
+ return resolved && resolved.res !== undefined;
728
1052
  }
729
- extractFromKey(key, opt) {
730
- let nsSeparator = opt.nsSeparator !== undefined ? opt.nsSeparator : this.options.nsSeparator;
1053
+ extractFromKey(key, options) {
1054
+ let nsSeparator = options.nsSeparator !== undefined ? options.nsSeparator : this.options.nsSeparator;
731
1055
  if (nsSeparator === undefined) nsSeparator = ':';
732
- const keySeparator = opt.keySeparator !== undefined ? opt.keySeparator : this.options.keySeparator;
733
- let namespaces = opt.ns || this.options.defaultNS || [];
1056
+ const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
1057
+ let namespaces = options.ns || this.options.defaultNS || [];
734
1058
  const wouldCheckForNsInKey = nsSeparator && key.indexOf(nsSeparator) > -1;
735
- const seemsNaturalLanguage = !this.options.userDefinedKeySeparator && !opt.keySeparator && !this.options.userDefinedNsSeparator && !opt.nsSeparator && !looksLikeObjectPath(key, nsSeparator, keySeparator);
1059
+ const seemsNaturalLanguage = !this.options.userDefinedKeySeparator && !options.keySeparator && !this.options.userDefinedNsSeparator && !options.nsSeparator && !looksLikeObjectPath(key, nsSeparator, keySeparator);
736
1060
  if (wouldCheckForNsInKey && !seemsNaturalLanguage) {
737
1061
  const m = key.match(this.interpolator.nestingRegexp);
738
1062
  if (m && m.length > 0) {
@@ -750,36 +1074,28 @@ class Translator extends EventEmitter {
750
1074
  namespaces: isString(namespaces) ? [namespaces] : namespaces
751
1075
  };
752
1076
  }
753
- translate(keys, o, lastKey) {
754
- let opt = typeof o === 'object' ? {
755
- ...o
756
- } : o;
757
- if (typeof opt !== 'object' && this.options.overloadTranslationOptionHandler) {
758
- opt = this.options.overloadTranslationOptionHandler(arguments);
1077
+ translate(keys, options, lastKey) {
1078
+ if (typeof options !== 'object' && this.options.overloadTranslationOptionHandler) {
1079
+ options = this.options.overloadTranslationOptionHandler(arguments);
759
1080
  }
760
- if (typeof opt === 'object') opt = {
761
- ...opt
1081
+ if (typeof options === 'object') options = {
1082
+ ...options
762
1083
  };
763
- if (!opt) opt = {};
764
- if (keys == null) return '';
765
- if (typeof keys === 'function') keys = keysFromSelector(keys, {
766
- ...this.options,
767
- ...opt
768
- });
1084
+ if (!options) options = {};
1085
+ if (keys === undefined || keys === null) return '';
769
1086
  if (!Array.isArray(keys)) keys = [String(keys)];
770
- const returnDetails = opt.returnDetails !== undefined ? opt.returnDetails : this.options.returnDetails;
771
- const keySeparator = opt.keySeparator !== undefined ? opt.keySeparator : this.options.keySeparator;
1087
+ const returnDetails = options.returnDetails !== undefined ? options.returnDetails : this.options.returnDetails;
1088
+ const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
772
1089
  const {
773
1090
  key,
774
1091
  namespaces
775
- } = this.extractFromKey(keys[keys.length - 1], opt);
1092
+ } = this.extractFromKey(keys[keys.length - 1], options);
776
1093
  const namespace = namespaces[namespaces.length - 1];
777
- let nsSeparator = opt.nsSeparator !== undefined ? opt.nsSeparator : this.options.nsSeparator;
778
- if (nsSeparator === undefined) nsSeparator = ':';
779
- const lng = opt.lng || this.language;
780
- const appendNamespaceToCIMode = opt.appendNamespaceToCIMode || this.options.appendNamespaceToCIMode;
781
- if (lng?.toLowerCase() === 'cimode') {
1094
+ const lng = options.lng || this.language;
1095
+ const appendNamespaceToCIMode = options.appendNamespaceToCIMode || this.options.appendNamespaceToCIMode;
1096
+ if (lng && lng.toLowerCase() === 'cimode') {
782
1097
  if (appendNamespaceToCIMode) {
1098
+ const nsSeparator = options.nsSeparator || this.options.nsSeparator;
783
1099
  if (returnDetails) {
784
1100
  return {
785
1101
  res: `${namespace}${nsSeparator}${key}`,
@@ -787,7 +1103,7 @@ class Translator extends EventEmitter {
787
1103
  exactUsedKey: key,
788
1104
  usedLng: lng,
789
1105
  usedNS: namespace,
790
- usedParams: this.getUsedParamsDetails(opt)
1106
+ usedParams: this.getUsedParamsDetails(options)
791
1107
  };
792
1108
  }
793
1109
  return `${namespace}${nsSeparator}${key}`;
@@ -799,84 +1115,69 @@ class Translator extends EventEmitter {
799
1115
  exactUsedKey: key,
800
1116
  usedLng: lng,
801
1117
  usedNS: namespace,
802
- usedParams: this.getUsedParamsDetails(opt)
1118
+ usedParams: this.getUsedParamsDetails(options)
803
1119
  };
804
1120
  }
805
1121
  return key;
806
1122
  }
807
- const resolved = this.resolve(keys, opt);
808
- let res = resolved?.res;
809
- const resUsedKey = resolved?.usedKey || key;
810
- const resExactUsedKey = resolved?.exactUsedKey || key;
1123
+ const resolved = this.resolve(keys, options);
1124
+ let res = resolved && resolved.res;
1125
+ const resUsedKey = resolved && resolved.usedKey || key;
1126
+ const resExactUsedKey = resolved && resolved.exactUsedKey || key;
1127
+ const resType = Object.prototype.toString.apply(res);
811
1128
  const noObject = ['[object Number]', '[object Function]', '[object RegExp]'];
812
- const joinArrays = opt.joinArrays !== undefined ? opt.joinArrays : this.options.joinArrays;
1129
+ const joinArrays = options.joinArrays !== undefined ? options.joinArrays : this.options.joinArrays;
813
1130
  const handleAsObjectInI18nFormat = !this.i18nFormat || this.i18nFormat.handleAsObject;
814
- const needsPluralHandling = opt.count !== undefined && !isString(opt.count);
815
- const hasDefaultValue = Translator.hasDefaultValue(opt);
816
- const defaultValueSuffix = needsPluralHandling ? this.pluralResolver.getSuffix(lng, opt.count, opt) : '';
817
- const defaultValueSuffixOrdinalFallback = opt.ordinal && needsPluralHandling ? this.pluralResolver.getSuffix(lng, opt.count, {
818
- ordinal: false
819
- }) : '';
820
- const needsZeroSuffixLookup = needsPluralHandling && !opt.ordinal && opt.count === 0;
821
- const defaultValue = needsZeroSuffixLookup && opt[`defaultValue${this.options.pluralSeparator}zero`] || opt[`defaultValue${defaultValueSuffix}`] || opt[`defaultValue${defaultValueSuffixOrdinalFallback}`] || opt.defaultValue;
822
- let resForObjHndl = res;
823
- if (handleAsObjectInI18nFormat && !res && hasDefaultValue) {
824
- resForObjHndl = defaultValue;
825
- }
826
- const handleAsObject = shouldHandleAsObject(resForObjHndl);
827
- const resType = Object.prototype.toString.apply(resForObjHndl);
828
- if (handleAsObjectInI18nFormat && resForObjHndl && handleAsObject && noObject.indexOf(resType) < 0 && !(isString(joinArrays) && Array.isArray(resForObjHndl))) {
829
- if (!opt.returnObjects && !this.options.returnObjects) {
1131
+ const handleAsObject = !isString(res) && typeof res !== 'boolean' && typeof res !== 'number';
1132
+ if (handleAsObjectInI18nFormat && res && handleAsObject && noObject.indexOf(resType) < 0 && !(isString(joinArrays) && Array.isArray(res))) {
1133
+ if (!options.returnObjects && !this.options.returnObjects) {
830
1134
  if (!this.options.returnedObjectHandler) {
831
1135
  this.logger.warn('accessing an object - but returnObjects options is not enabled!');
832
1136
  }
833
- const r = this.options.returnedObjectHandler ? this.options.returnedObjectHandler(resUsedKey, resForObjHndl, {
834
- ...opt,
1137
+ const r = this.options.returnedObjectHandler ? this.options.returnedObjectHandler(resUsedKey, res, {
1138
+ ...options,
835
1139
  ns: namespaces
836
1140
  }) : `key '${key} (${this.language})' returned an object instead of string.`;
837
1141
  if (returnDetails) {
838
1142
  resolved.res = r;
839
- resolved.usedParams = this.getUsedParamsDetails(opt);
1143
+ resolved.usedParams = this.getUsedParamsDetails(options);
840
1144
  return resolved;
841
1145
  }
842
1146
  return r;
843
1147
  }
844
1148
  if (keySeparator) {
845
- const resTypeIsArray = Array.isArray(resForObjHndl);
1149
+ const resTypeIsArray = Array.isArray(res);
846
1150
  const copy = resTypeIsArray ? [] : {};
847
1151
  const newKeyToUse = resTypeIsArray ? resExactUsedKey : resUsedKey;
848
- for (const m in resForObjHndl) {
849
- if (Object.prototype.hasOwnProperty.call(resForObjHndl, m)) {
1152
+ for (const m in res) {
1153
+ if (Object.prototype.hasOwnProperty.call(res, m)) {
850
1154
  const deepKey = `${newKeyToUse}${keySeparator}${m}`;
851
- if (hasDefaultValue && !res) {
852
- copy[m] = this.translate(deepKey, {
853
- ...opt,
854
- defaultValue: shouldHandleAsObject(defaultValue) ? defaultValue[m] : undefined,
855
- ...{
856
- joinArrays: false,
857
- ns: namespaces
858
- }
859
- });
860
- } else {
861
- copy[m] = this.translate(deepKey, {
862
- ...opt,
863
- ...{
864
- joinArrays: false,
865
- ns: namespaces
866
- }
867
- });
868
- }
869
- if (copy[m] === deepKey) copy[m] = resForObjHndl[m];
1155
+ copy[m] = this.translate(deepKey, {
1156
+ ...options,
1157
+ ...{
1158
+ joinArrays: false,
1159
+ ns: namespaces
1160
+ }
1161
+ });
1162
+ if (copy[m] === deepKey) copy[m] = res[m];
870
1163
  }
871
1164
  }
872
1165
  res = copy;
873
1166
  }
874
1167
  } else if (handleAsObjectInI18nFormat && isString(joinArrays) && Array.isArray(res)) {
875
1168
  res = res.join(joinArrays);
876
- if (res) res = this.extendTranslation(res, keys, opt, lastKey);
1169
+ if (res) res = this.extendTranslation(res, keys, options, lastKey);
877
1170
  } else {
878
1171
  let usedDefault = false;
879
1172
  let usedKey = false;
1173
+ const needsPluralHandling = options.count !== undefined && !isString(options.count);
1174
+ const hasDefaultValue = Translator.hasDefaultValue(options);
1175
+ const defaultValueSuffix = needsPluralHandling ? this.pluralResolver.getSuffix(lng, options.count, options) : '';
1176
+ const defaultValueSuffixOrdinalFallback = options.ordinal && needsPluralHandling ? this.pluralResolver.getSuffix(lng, options.count, {
1177
+ ordinal: false
1178
+ }) : '';
1179
+ const needsZeroSuffixLookup = needsPluralHandling && !options.ordinal && options.count === 0 && this.pluralResolver.shouldUseIntlApi();
1180
+ const defaultValue = needsZeroSuffixLookup && options[`defaultValue${this.options.pluralSeparator}zero`] || options[`defaultValue${defaultValueSuffix}`] || options[`defaultValue${defaultValueSuffixOrdinalFallback}`] || options.defaultValue;
880
1181
  if (!this.isValidLookup(res) && hasDefaultValue) {
881
1182
  usedDefault = true;
882
1183
  res = defaultValue;
@@ -885,47 +1186,47 @@ class Translator extends EventEmitter {
885
1186
  usedKey = true;
886
1187
  res = key;
887
1188
  }
888
- const missingKeyNoValueFallbackToKey = opt.missingKeyNoValueFallbackToKey || this.options.missingKeyNoValueFallbackToKey;
1189
+ const missingKeyNoValueFallbackToKey = options.missingKeyNoValueFallbackToKey || this.options.missingKeyNoValueFallbackToKey;
889
1190
  const resForMissing = missingKeyNoValueFallbackToKey && usedKey ? undefined : res;
890
1191
  const updateMissing = hasDefaultValue && defaultValue !== res && this.options.updateMissing;
891
1192
  if (usedKey || usedDefault || updateMissing) {
892
1193
  this.logger.log(updateMissing ? 'updateKey' : 'missingKey', lng, namespace, key, updateMissing ? defaultValue : res);
893
1194
  if (keySeparator) {
894
1195
  const fk = this.resolve(key, {
895
- ...opt,
1196
+ ...options,
896
1197
  keySeparator: false
897
1198
  });
898
1199
  if (fk && fk.res) this.logger.warn('Seems the loaded translations were in flat JSON format instead of nested. Either set keySeparator: false on init or make sure your translations are published in nested format.');
899
1200
  }
900
1201
  let lngs = [];
901
- const fallbackLngs = this.languageUtils.getFallbackCodes(this.options.fallbackLng, opt.lng || this.language);
1202
+ const fallbackLngs = this.languageUtils.getFallbackCodes(this.options.fallbackLng, options.lng || this.language);
902
1203
  if (this.options.saveMissingTo === 'fallback' && fallbackLngs && fallbackLngs[0]) {
903
1204
  for (let i = 0; i < fallbackLngs.length; i++) {
904
1205
  lngs.push(fallbackLngs[i]);
905
1206
  }
906
1207
  } else if (this.options.saveMissingTo === 'all') {
907
- lngs = this.languageUtils.toResolveHierarchy(opt.lng || this.language);
1208
+ lngs = this.languageUtils.toResolveHierarchy(options.lng || this.language);
908
1209
  } else {
909
- lngs.push(opt.lng || this.language);
1210
+ lngs.push(options.lng || this.language);
910
1211
  }
911
1212
  const send = (l, k, specificDefaultValue) => {
912
1213
  const defaultForMissing = hasDefaultValue && specificDefaultValue !== res ? specificDefaultValue : resForMissing;
913
1214
  if (this.options.missingKeyHandler) {
914
- this.options.missingKeyHandler(l, namespace, k, defaultForMissing, updateMissing, opt);
915
- } else if (this.backendConnector?.saveMissing) {
916
- this.backendConnector.saveMissing(l, namespace, k, defaultForMissing, updateMissing, opt);
1215
+ this.options.missingKeyHandler(l, namespace, k, defaultForMissing, updateMissing, options);
1216
+ } else if (this.backendConnector && this.backendConnector.saveMissing) {
1217
+ this.backendConnector.saveMissing(l, namespace, k, defaultForMissing, updateMissing, options);
917
1218
  }
918
1219
  this.emit('missingKey', l, namespace, k, res);
919
1220
  };
920
1221
  if (this.options.saveMissing) {
921
1222
  if (this.options.saveMissingPlurals && needsPluralHandling) {
922
1223
  lngs.forEach(language => {
923
- const suffixes = this.pluralResolver.getSuffixes(language, opt);
924
- if (needsZeroSuffixLookup && opt[`defaultValue${this.options.pluralSeparator}zero`] && suffixes.indexOf(`${this.options.pluralSeparator}zero`) < 0) {
1224
+ const suffixes = this.pluralResolver.getSuffixes(language, options);
1225
+ if (needsZeroSuffixLookup && options[`defaultValue${this.options.pluralSeparator}zero`] && suffixes.indexOf(`${this.options.pluralSeparator}zero`) < 0) {
925
1226
  suffixes.push(`${this.options.pluralSeparator}zero`);
926
1227
  }
927
1228
  suffixes.forEach(suffix => {
928
- send([language], key + suffix, opt[`defaultValue${suffix}`] || defaultValue);
1229
+ send([language], key + suffix, options[`defaultValue${suffix}`] || defaultValue);
929
1230
  });
930
1231
  });
931
1232
  } else {
@@ -933,80 +1234,87 @@ class Translator extends EventEmitter {
933
1234
  }
934
1235
  }
935
1236
  }
936
- res = this.extendTranslation(res, keys, opt, resolved, lastKey);
937
- if (usedKey && res === key && this.options.appendNamespaceToMissingKey) {
938
- res = `${namespace}${nsSeparator}${key}`;
939
- }
1237
+ res = this.extendTranslation(res, keys, options, resolved, lastKey);
1238
+ if (usedKey && res === key && this.options.appendNamespaceToMissingKey) res = `${namespace}:${key}`;
940
1239
  if ((usedKey || usedDefault) && this.options.parseMissingKeyHandler) {
941
- res = this.options.parseMissingKeyHandler(this.options.appendNamespaceToMissingKey ? `${namespace}${nsSeparator}${key}` : key, usedDefault ? res : undefined, opt);
1240
+ if (this.options.compatibilityAPI !== 'v1') {
1241
+ res = this.options.parseMissingKeyHandler(this.options.appendNamespaceToMissingKey ? `${namespace}:${key}` : key, usedDefault ? res : undefined);
1242
+ } else {
1243
+ res = this.options.parseMissingKeyHandler(res);
1244
+ }
942
1245
  }
943
1246
  }
944
1247
  if (returnDetails) {
945
1248
  resolved.res = res;
946
- resolved.usedParams = this.getUsedParamsDetails(opt);
1249
+ resolved.usedParams = this.getUsedParamsDetails(options);
947
1250
  return resolved;
948
1251
  }
949
1252
  return res;
950
1253
  }
951
- extendTranslation(res, key, opt, resolved, lastKey) {
952
- if (this.i18nFormat?.parse) {
1254
+ extendTranslation(res, key, options, resolved, lastKey) {
1255
+ var _this = this;
1256
+ if (this.i18nFormat && this.i18nFormat.parse) {
953
1257
  res = this.i18nFormat.parse(res, {
954
1258
  ...this.options.interpolation.defaultVariables,
955
- ...opt
956
- }, opt.lng || this.language || resolved.usedLng, resolved.usedNS, resolved.usedKey, {
1259
+ ...options
1260
+ }, options.lng || this.language || resolved.usedLng, resolved.usedNS, resolved.usedKey, {
957
1261
  resolved
958
1262
  });
959
- } else if (!opt.skipInterpolation) {
960
- if (opt.interpolation) this.interpolator.init({
961
- ...opt,
1263
+ } else if (!options.skipInterpolation) {
1264
+ if (options.interpolation) this.interpolator.init({
1265
+ ...options,
962
1266
  ...{
963
1267
  interpolation: {
964
1268
  ...this.options.interpolation,
965
- ...opt.interpolation
1269
+ ...options.interpolation
966
1270
  }
967
1271
  }
968
1272
  });
969
- const skipOnVariables = isString(res) && (opt?.interpolation?.skipOnVariables !== undefined ? opt.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables);
1273
+ const skipOnVariables = isString(res) && (options && options.interpolation && options.interpolation.skipOnVariables !== undefined ? options.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables);
970
1274
  let nestBef;
971
1275
  if (skipOnVariables) {
972
1276
  const nb = res.match(this.interpolator.nestingRegexp);
973
1277
  nestBef = nb && nb.length;
974
1278
  }
975
- let data = opt.replace && !isString(opt.replace) ? opt.replace : opt;
1279
+ let data = options.replace && !isString(options.replace) ? options.replace : options;
976
1280
  if (this.options.interpolation.defaultVariables) data = {
977
1281
  ...this.options.interpolation.defaultVariables,
978
1282
  ...data
979
1283
  };
980
- res = this.interpolator.interpolate(res, data, opt.lng || this.language || resolved.usedLng, opt);
1284
+ res = this.interpolator.interpolate(res, data, options.lng || this.language || resolved.usedLng, options);
981
1285
  if (skipOnVariables) {
982
1286
  const na = res.match(this.interpolator.nestingRegexp);
983
1287
  const nestAft = na && na.length;
984
- if (nestBef < nestAft) opt.nest = false;
1288
+ if (nestBef < nestAft) options.nest = false;
985
1289
  }
986
- if (!opt.lng && resolved && resolved.res) opt.lng = this.language || resolved.usedLng;
987
- if (opt.nest !== false) res = this.interpolator.nest(res, (...args) => {
988
- if (lastKey?.[0] === args[0] && !opt.context) {
989
- this.logger.warn(`It seems you are nesting recursively key: ${args[0]} in key: ${key[0]}`);
1290
+ if (!options.lng && this.options.compatibilityAPI !== 'v1' && resolved && resolved.res) options.lng = this.language || resolved.usedLng;
1291
+ if (options.nest !== false) res = this.interpolator.nest(res, function () {
1292
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
1293
+ args[_key] = arguments[_key];
1294
+ }
1295
+ if (lastKey && lastKey[0] === args[0] && !options.context) {
1296
+ _this.logger.warn(`It seems you are nesting recursively key: ${args[0]} in key: ${key[0]}`);
990
1297
  return null;
991
1298
  }
992
- return this.translate(...args, key);
993
- }, opt);
994
- if (opt.interpolation) this.interpolator.reset();
1299
+ return _this.translate(...args, key);
1300
+ }, options);
1301
+ if (options.interpolation) this.interpolator.reset();
995
1302
  }
996
- const postProcess = opt.postProcess || this.options.postProcess;
1303
+ const postProcess = options.postProcess || this.options.postProcess;
997
1304
  const postProcessorNames = isString(postProcess) ? [postProcess] : postProcess;
998
- if (res != null && postProcessorNames?.length && opt.applyPostProcessor !== false) {
1305
+ if (res !== undefined && res !== null && postProcessorNames && postProcessorNames.length && options.applyPostProcessor !== false) {
999
1306
  res = postProcessor.handle(postProcessorNames, res, key, this.options && this.options.postProcessPassResolved ? {
1000
1307
  i18nResolved: {
1001
1308
  ...resolved,
1002
- usedParams: this.getUsedParamsDetails(opt)
1309
+ usedParams: this.getUsedParamsDetails(options)
1003
1310
  },
1004
- ...opt
1005
- } : opt, this);
1311
+ ...options
1312
+ } : options, this);
1006
1313
  }
1007
1314
  return res;
1008
1315
  }
1009
- resolve(keys, opt = {}) {
1316
+ resolve(keys) {
1317
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1010
1318
  let found;
1011
1319
  let usedKey;
1012
1320
  let exactUsedKey;
@@ -1015,19 +1323,19 @@ class Translator extends EventEmitter {
1015
1323
  if (isString(keys)) keys = [keys];
1016
1324
  keys.forEach(k => {
1017
1325
  if (this.isValidLookup(found)) return;
1018
- const extracted = this.extractFromKey(k, opt);
1326
+ const extracted = this.extractFromKey(k, options);
1019
1327
  const key = extracted.key;
1020
1328
  usedKey = key;
1021
1329
  let namespaces = extracted.namespaces;
1022
1330
  if (this.options.fallbackNS) namespaces = namespaces.concat(this.options.fallbackNS);
1023
- const needsPluralHandling = opt.count !== undefined && !isString(opt.count);
1024
- const needsZeroSuffixLookup = needsPluralHandling && !opt.ordinal && opt.count === 0;
1025
- const needsContextHandling = opt.context !== undefined && (isString(opt.context) || typeof opt.context === 'number') && opt.context !== '';
1026
- const codes = opt.lngs ? opt.lngs : this.languageUtils.toResolveHierarchy(opt.lng || this.language, opt.fallbackLng);
1331
+ const needsPluralHandling = options.count !== undefined && !isString(options.count);
1332
+ const needsZeroSuffixLookup = needsPluralHandling && !options.ordinal && options.count === 0 && this.pluralResolver.shouldUseIntlApi();
1333
+ const needsContextHandling = options.context !== undefined && (isString(options.context) || typeof options.context === 'number') && options.context !== '';
1334
+ const codes = options.lngs ? options.lngs : this.languageUtils.toResolveHierarchy(options.lng || this.language, options.fallbackLng);
1027
1335
  namespaces.forEach(ns => {
1028
1336
  if (this.isValidLookup(found)) return;
1029
1337
  usedNS = ns;
1030
- if (!checkedLoadedFor[`${codes[0]}-${ns}`] && this.utils?.hasLoadedNamespace && !this.utils?.hasLoadedNamespace(usedNS)) {
1338
+ if (!checkedLoadedFor[`${codes[0]}-${ns}`] && this.utils && this.utils.hasLoadedNamespace && !this.utils.hasLoadedNamespace(usedNS)) {
1031
1339
  checkedLoadedFor[`${codes[0]}-${ns}`] = true;
1032
1340
  this.logger.warn(`key "${usedKey}" for languages "${codes.join(', ')}" won't get resolved as namespace "${usedNS}" was not yet loaded`, 'This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!');
1033
1341
  }
@@ -1035,30 +1343,30 @@ class Translator extends EventEmitter {
1035
1343
  if (this.isValidLookup(found)) return;
1036
1344
  usedLng = code;
1037
1345
  const finalKeys = [key];
1038
- if (this.i18nFormat?.addLookupKeys) {
1039
- this.i18nFormat.addLookupKeys(finalKeys, key, code, ns, opt);
1346
+ if (this.i18nFormat && this.i18nFormat.addLookupKeys) {
1347
+ this.i18nFormat.addLookupKeys(finalKeys, key, code, ns, options);
1040
1348
  } else {
1041
1349
  let pluralSuffix;
1042
- if (needsPluralHandling) pluralSuffix = this.pluralResolver.getSuffix(code, opt.count, opt);
1350
+ if (needsPluralHandling) pluralSuffix = this.pluralResolver.getSuffix(code, options.count, options);
1043
1351
  const zeroSuffix = `${this.options.pluralSeparator}zero`;
1044
1352
  const ordinalPrefix = `${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`;
1045
1353
  if (needsPluralHandling) {
1046
- if (opt.ordinal && pluralSuffix.indexOf(ordinalPrefix) === 0) {
1354
+ finalKeys.push(key + pluralSuffix);
1355
+ if (options.ordinal && pluralSuffix.indexOf(ordinalPrefix) === 0) {
1047
1356
  finalKeys.push(key + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator));
1048
1357
  }
1049
- finalKeys.push(key + pluralSuffix);
1050
1358
  if (needsZeroSuffixLookup) {
1051
1359
  finalKeys.push(key + zeroSuffix);
1052
1360
  }
1053
1361
  }
1054
1362
  if (needsContextHandling) {
1055
- const contextKey = `${key}${this.options.contextSeparator || '_'}${opt.context}`;
1363
+ const contextKey = `${key}${this.options.contextSeparator}${options.context}`;
1056
1364
  finalKeys.push(contextKey);
1057
1365
  if (needsPluralHandling) {
1058
- if (opt.ordinal && pluralSuffix.indexOf(ordinalPrefix) === 0) {
1366
+ finalKeys.push(contextKey + pluralSuffix);
1367
+ if (options.ordinal && pluralSuffix.indexOf(ordinalPrefix) === 0) {
1059
1368
  finalKeys.push(contextKey + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator));
1060
1369
  }
1061
- finalKeys.push(contextKey + pluralSuffix);
1062
1370
  if (needsZeroSuffixLookup) {
1063
1371
  finalKeys.push(contextKey + zeroSuffix);
1064
1372
  }
@@ -1069,7 +1377,7 @@ class Translator extends EventEmitter {
1069
1377
  while (possibleKey = finalKeys.pop()) {
1070
1378
  if (!this.isValidLookup(found)) {
1071
1379
  exactUsedKey = possibleKey;
1072
- found = this.getResource(code, ns, possibleKey, opt);
1380
+ found = this.getResource(code, ns, possibleKey, options);
1073
1381
  }
1074
1382
  }
1075
1383
  });
@@ -1086,11 +1394,13 @@ class Translator extends EventEmitter {
1086
1394
  isValidLookup(res) {
1087
1395
  return res !== undefined && !(!this.options.returnNull && res === null) && !(!this.options.returnEmptyString && res === '');
1088
1396
  }
1089
- getResource(code, ns, key, options = {}) {
1090
- if (this.i18nFormat?.getResource) return this.i18nFormat.getResource(code, ns, key, options);
1397
+ getResource(code, ns, key) {
1398
+ let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1399
+ if (this.i18nFormat && this.i18nFormat.getResource) return this.i18nFormat.getResource(code, ns, key, options);
1091
1400
  return this.resourceStore.getResource(code, ns, key, options);
1092
1401
  }
1093
- getUsedParamsDetails(options = {}) {
1402
+ getUsedParamsDetails() {
1403
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1094
1404
  const optionsKeys = ['defaultValue', 'ordinal', 'context', 'replace', 'lng', 'lngs', 'fallbackLng', 'ns', 'keySeparator', 'nsSeparator', 'returnObjects', 'returnDetails', 'joinArrays', 'postProcess', 'interpolation'];
1095
1405
  const useOptionsReplaceForData = options.replace && !isString(options.replace);
1096
1406
  let data = useOptionsReplaceForData ? options.replace : options;
@@ -1124,6 +1434,7 @@ class Translator extends EventEmitter {
1124
1434
  }
1125
1435
  }
1126
1436
 
1437
+ const capitalize = string => string.charAt(0).toUpperCase() + string.slice(1);
1127
1438
  class LanguageUtil {
1128
1439
  constructor(options) {
1129
1440
  this.options = options;
@@ -1147,18 +1458,31 @@ class LanguageUtil {
1147
1458
  }
1148
1459
  formatLanguageCode(code) {
1149
1460
  if (isString(code) && code.indexOf('-') > -1) {
1150
- let formattedCode;
1151
- try {
1152
- formattedCode = Intl.getCanonicalLocales(code)[0];
1153
- } catch (e) {}
1154
- if (formattedCode && this.options.lowerCaseLng) {
1155
- formattedCode = formattedCode.toLowerCase();
1461
+ if (typeof Intl !== 'undefined' && typeof Intl.getCanonicalLocales !== 'undefined') {
1462
+ try {
1463
+ let formattedCode = Intl.getCanonicalLocales(code)[0];
1464
+ if (formattedCode && this.options.lowerCaseLng) {
1465
+ formattedCode = formattedCode.toLowerCase();
1466
+ }
1467
+ if (formattedCode) return formattedCode;
1468
+ } catch (e) {}
1156
1469
  }
1157
- if (formattedCode) return formattedCode;
1470
+ const specialCases = ['hans', 'hant', 'latn', 'cyrl', 'cans', 'mong', 'arab'];
1471
+ let p = code.split('-');
1158
1472
  if (this.options.lowerCaseLng) {
1159
- return code.toLowerCase();
1473
+ p = p.map(part => part.toLowerCase());
1474
+ } else if (p.length === 2) {
1475
+ p[0] = p[0].toLowerCase();
1476
+ p[1] = p[1].toUpperCase();
1477
+ if (specialCases.indexOf(p[1].toLowerCase()) > -1) p[1] = capitalize(p[1].toLowerCase());
1478
+ } else if (p.length === 3) {
1479
+ p[0] = p[0].toLowerCase();
1480
+ if (p[1].length === 2) p[1] = p[1].toUpperCase();
1481
+ if (p[0] !== 'sgn' && p[2].length === 2) p[2] = p[2].toUpperCase();
1482
+ if (specialCases.indexOf(p[1].toLowerCase()) > -1) p[1] = capitalize(p[1].toLowerCase());
1483
+ if (specialCases.indexOf(p[2].toLowerCase()) > -1) p[2] = capitalize(p[2].toLowerCase());
1160
1484
  }
1161
- return code;
1485
+ return p.join('-');
1162
1486
  }
1163
1487
  return this.options.cleanCode || this.options.lowerCaseLng ? code.toLowerCase() : code;
1164
1488
  }
@@ -1179,8 +1503,6 @@ class LanguageUtil {
1179
1503
  if (!found && this.options.supportedLngs) {
1180
1504
  codes.forEach(code => {
1181
1505
  if (found) return;
1182
- const lngScOnly = this.getScriptPartFromCode(code);
1183
- if (this.isSupportedCode(lngScOnly)) return found = lngScOnly;
1184
1506
  const lngOnly = this.getLanguagePartFromCode(code);
1185
1507
  if (this.isSupportedCode(lngOnly)) return found = lngOnly;
1186
1508
  found = this.options.supportedLngs.find(supportedLng => {
@@ -1208,7 +1530,7 @@ class LanguageUtil {
1208
1530
  return found || [];
1209
1531
  }
1210
1532
  toResolveHierarchy(code, fallbackCode) {
1211
- const fallbackCodes = this.getFallbackCodes((fallbackCode === false ? [] : fallbackCode) || this.options.fallbackLng || [], code);
1533
+ const fallbackCodes = this.getFallbackCodes(fallbackCode || this.options.fallbackLng || [], code);
1212
1534
  const codes = [];
1213
1535
  const addCode = c => {
1214
1536
  if (!c) return;
@@ -1232,6 +1554,125 @@ class LanguageUtil {
1232
1554
  }
1233
1555
  }
1234
1556
 
1557
+ let sets = [{
1558
+ lngs: ['ach', 'ak', 'am', 'arn', 'br', 'fil', 'gun', 'ln', 'mfe', 'mg', 'mi', 'oc', 'pt', 'pt-BR', 'tg', 'tl', 'ti', 'tr', 'uz', 'wa'],
1559
+ nr: [1, 2],
1560
+ fc: 1
1561
+ }, {
1562
+ lngs: ['af', 'an', 'ast', 'az', 'bg', 'bn', 'ca', 'da', 'de', 'dev', 'el', 'en', 'eo', 'es', 'et', 'eu', 'fi', 'fo', 'fur', 'fy', 'gl', 'gu', 'ha', 'hi', 'hu', 'hy', 'ia', 'it', 'kk', 'kn', 'ku', 'lb', 'mai', 'ml', 'mn', 'mr', 'nah', 'nap', 'nb', 'ne', 'nl', 'nn', 'no', 'nso', 'pa', 'pap', 'pms', 'ps', 'pt-PT', 'rm', 'sco', 'se', 'si', 'so', 'son', 'sq', 'sv', 'sw', 'ta', 'te', 'tk', 'ur', 'yo'],
1563
+ nr: [1, 2],
1564
+ fc: 2
1565
+ }, {
1566
+ lngs: ['ay', 'bo', 'cgg', 'fa', 'ht', 'id', 'ja', 'jbo', 'ka', 'km', 'ko', 'ky', 'lo', 'ms', 'sah', 'su', 'th', 'tt', 'ug', 'vi', 'wo', 'zh'],
1567
+ nr: [1],
1568
+ fc: 3
1569
+ }, {
1570
+ lngs: ['be', 'bs', 'cnr', 'dz', 'hr', 'ru', 'sr', 'uk'],
1571
+ nr: [1, 2, 5],
1572
+ fc: 4
1573
+ }, {
1574
+ lngs: ['ar'],
1575
+ nr: [0, 1, 2, 3, 11, 100],
1576
+ fc: 5
1577
+ }, {
1578
+ lngs: ['cs', 'sk'],
1579
+ nr: [1, 2, 5],
1580
+ fc: 6
1581
+ }, {
1582
+ lngs: ['csb', 'pl'],
1583
+ nr: [1, 2, 5],
1584
+ fc: 7
1585
+ }, {
1586
+ lngs: ['cy'],
1587
+ nr: [1, 2, 3, 8],
1588
+ fc: 8
1589
+ }, {
1590
+ lngs: ['fr'],
1591
+ nr: [1, 2],
1592
+ fc: 9
1593
+ }, {
1594
+ lngs: ['ga'],
1595
+ nr: [1, 2, 3, 7, 11],
1596
+ fc: 10
1597
+ }, {
1598
+ lngs: ['gd'],
1599
+ nr: [1, 2, 3, 20],
1600
+ fc: 11
1601
+ }, {
1602
+ lngs: ['is'],
1603
+ nr: [1, 2],
1604
+ fc: 12
1605
+ }, {
1606
+ lngs: ['jv'],
1607
+ nr: [0, 1],
1608
+ fc: 13
1609
+ }, {
1610
+ lngs: ['kw'],
1611
+ nr: [1, 2, 3, 4],
1612
+ fc: 14
1613
+ }, {
1614
+ lngs: ['lt'],
1615
+ nr: [1, 2, 10],
1616
+ fc: 15
1617
+ }, {
1618
+ lngs: ['lv'],
1619
+ nr: [1, 2, 0],
1620
+ fc: 16
1621
+ }, {
1622
+ lngs: ['mk'],
1623
+ nr: [1, 2],
1624
+ fc: 17
1625
+ }, {
1626
+ lngs: ['mnk'],
1627
+ nr: [0, 1, 2],
1628
+ fc: 18
1629
+ }, {
1630
+ lngs: ['mt'],
1631
+ nr: [1, 2, 11, 20],
1632
+ fc: 19
1633
+ }, {
1634
+ lngs: ['or'],
1635
+ nr: [2, 1],
1636
+ fc: 2
1637
+ }, {
1638
+ lngs: ['ro'],
1639
+ nr: [1, 2, 20],
1640
+ fc: 20
1641
+ }, {
1642
+ lngs: ['sl'],
1643
+ nr: [5, 1, 2, 3],
1644
+ fc: 21
1645
+ }, {
1646
+ lngs: ['he', 'iw'],
1647
+ nr: [1, 2, 20, 21],
1648
+ fc: 22
1649
+ }];
1650
+ let _rulesPluralsTypes = {
1651
+ 1: n => Number(n > 1),
1652
+ 2: n => Number(n != 1),
1653
+ 3: n => 0,
1654
+ 4: n => Number(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2),
1655
+ 5: n => Number(n == 0 ? 0 : n == 1 ? 1 : n == 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5),
1656
+ 6: n => Number(n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2),
1657
+ 7: n => Number(n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2),
1658
+ 8: n => Number(n == 1 ? 0 : n == 2 ? 1 : n != 8 && n != 11 ? 2 : 3),
1659
+ 9: n => Number(n >= 2),
1660
+ 10: n => Number(n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4),
1661
+ 11: n => Number(n == 1 || n == 11 ? 0 : n == 2 || n == 12 ? 1 : n > 2 && n < 20 ? 2 : 3),
1662
+ 12: n => Number(n % 10 != 1 || n % 100 == 11),
1663
+ 13: n => Number(n !== 0),
1664
+ 14: n => Number(n == 1 ? 0 : n == 2 ? 1 : n == 3 ? 2 : 3),
1665
+ 15: n => Number(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2),
1666
+ 16: n => Number(n % 10 == 1 && n % 100 != 11 ? 0 : n !== 0 ? 1 : 2),
1667
+ 17: n => Number(n == 1 || n % 10 == 1 && n % 100 != 11 ? 0 : 1),
1668
+ 18: n => Number(n == 0 ? 0 : n == 1 ? 1 : 2),
1669
+ 19: n => Number(n == 1 ? 0 : n == 0 || n % 100 > 1 && n % 100 < 11 ? 1 : n % 100 > 10 && n % 100 < 20 ? 2 : 3),
1670
+ 20: n => Number(n == 1 ? 0 : n == 0 || n % 100 > 0 && n % 100 < 20 ? 1 : 2),
1671
+ 21: n => Number(n % 100 == 1 ? 1 : n % 100 == 2 ? 2 : n % 100 == 3 || n % 100 == 4 ? 3 : 0),
1672
+ 22: n => Number(n == 1 ? 0 : n == 2 ? 1 : (n < 0 || n > 10) && n % 10 == 0 ? 2 : 3)
1673
+ };
1674
+ const nonIntlVersions = ['v1', 'v2', 'v3'];
1675
+ const intlVersions = ['v4'];
1235
1676
  const suffixesOrder = {
1236
1677
  zero: 0,
1237
1678
  one: 1,
@@ -1240,74 +1681,129 @@ const suffixesOrder = {
1240
1681
  many: 4,
1241
1682
  other: 5
1242
1683
  };
1243
- const dummyRule = {
1244
- select: count => count === 1 ? 'one' : 'other',
1245
- resolvedOptions: () => ({
1246
- pluralCategories: ['one', 'other']
1247
- })
1684
+ const createRules = () => {
1685
+ const rules = {};
1686
+ sets.forEach(set => {
1687
+ set.lngs.forEach(l => {
1688
+ rules[l] = {
1689
+ numbers: set.nr,
1690
+ plurals: _rulesPluralsTypes[set.fc]
1691
+ };
1692
+ });
1693
+ });
1694
+ return rules;
1248
1695
  };
1249
1696
  class PluralResolver {
1250
- constructor(languageUtils, options = {}) {
1697
+ constructor(languageUtils) {
1698
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1251
1699
  this.languageUtils = languageUtils;
1252
1700
  this.options = options;
1253
1701
  this.logger = baseLogger.create('pluralResolver');
1702
+ if ((!this.options.compatibilityJSON || intlVersions.includes(this.options.compatibilityJSON)) && (typeof Intl === 'undefined' || !Intl.PluralRules)) {
1703
+ this.options.compatibilityJSON = 'v3';
1704
+ this.logger.error('Your environment seems not to be Intl API compatible, use an Intl.PluralRules polyfill. Will fallback to the compatibilityJSON v3 format handling.');
1705
+ }
1706
+ this.rules = createRules();
1254
1707
  this.pluralRulesCache = {};
1255
1708
  }
1709
+ addRule(lng, obj) {
1710
+ this.rules[lng] = obj;
1711
+ }
1256
1712
  clearCache() {
1257
1713
  this.pluralRulesCache = {};
1258
1714
  }
1259
- getRule(code, options = {}) {
1260
- const cleanedCode = getCleanedCode(code === 'dev' ? 'en' : code);
1261
- const type = options.ordinal ? 'ordinal' : 'cardinal';
1262
- const cacheKey = JSON.stringify({
1263
- cleanedCode,
1264
- type
1265
- });
1266
- if (cacheKey in this.pluralRulesCache) {
1267
- return this.pluralRulesCache[cacheKey];
1268
- }
1269
- let rule;
1270
- try {
1271
- rule = new Intl.PluralRules(cleanedCode, {
1715
+ getRule(code) {
1716
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1717
+ if (this.shouldUseIntlApi()) {
1718
+ const cleanedCode = getCleanedCode(code === 'dev' ? 'en' : code);
1719
+ const type = options.ordinal ? 'ordinal' : 'cardinal';
1720
+ const cacheKey = JSON.stringify({
1721
+ cleanedCode,
1272
1722
  type
1273
1723
  });
1274
- } catch (err) {
1275
- if (typeof Intl === 'undefined') {
1276
- this.logger.error('No Intl support, please use an Intl polyfill!');
1277
- return dummyRule;
1724
+ if (cacheKey in this.pluralRulesCache) {
1725
+ return this.pluralRulesCache[cacheKey];
1726
+ }
1727
+ let rule;
1728
+ try {
1729
+ rule = new Intl.PluralRules(cleanedCode, {
1730
+ type
1731
+ });
1732
+ } catch (err) {
1733
+ if (!code.match(/-|_/)) return;
1734
+ const lngPart = this.languageUtils.getLanguagePartFromCode(code);
1735
+ rule = this.getRule(lngPart, options);
1278
1736
  }
1279
- if (!code.match(/-|_/)) return dummyRule;
1280
- const lngPart = this.languageUtils.getLanguagePartFromCode(code);
1281
- rule = this.getRule(lngPart, options);
1737
+ this.pluralRulesCache[cacheKey] = rule;
1738
+ return rule;
1282
1739
  }
1283
- this.pluralRulesCache[cacheKey] = rule;
1284
- return rule;
1740
+ return this.rules[code] || this.rules[this.languageUtils.getLanguagePartFromCode(code)];
1285
1741
  }
1286
- needsPlural(code, options = {}) {
1287
- let rule = this.getRule(code, options);
1288
- if (!rule) rule = this.getRule('dev', options);
1289
- return rule?.resolvedOptions().pluralCategories.length > 1;
1742
+ needsPlural(code) {
1743
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1744
+ const rule = this.getRule(code, options);
1745
+ if (this.shouldUseIntlApi()) {
1746
+ return rule && rule.resolvedOptions().pluralCategories.length > 1;
1747
+ }
1748
+ return rule && rule.numbers.length > 1;
1290
1749
  }
1291
- getPluralFormsOfKey(code, key, options = {}) {
1750
+ getPluralFormsOfKey(code, key) {
1751
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1292
1752
  return this.getSuffixes(code, options).map(suffix => `${key}${suffix}`);
1293
1753
  }
1294
- getSuffixes(code, options = {}) {
1295
- let rule = this.getRule(code, options);
1296
- if (!rule) rule = this.getRule('dev', options);
1297
- if (!rule) return [];
1298
- return rule.resolvedOptions().pluralCategories.sort((pluralCategory1, pluralCategory2) => suffixesOrder[pluralCategory1] - suffixesOrder[pluralCategory2]).map(pluralCategory => `${this.options.prepend}${options.ordinal ? `ordinal${this.options.prepend}` : ''}${pluralCategory}`);
1754
+ getSuffixes(code) {
1755
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1756
+ const rule = this.getRule(code, options);
1757
+ if (!rule) {
1758
+ return [];
1759
+ }
1760
+ if (this.shouldUseIntlApi()) {
1761
+ return rule.resolvedOptions().pluralCategories.sort((pluralCategory1, pluralCategory2) => suffixesOrder[pluralCategory1] - suffixesOrder[pluralCategory2]).map(pluralCategory => `${this.options.prepend}${options.ordinal ? `ordinal${this.options.prepend}` : ''}${pluralCategory}`);
1762
+ }
1763
+ return rule.numbers.map(number => this.getSuffix(code, number, options));
1299
1764
  }
1300
- getSuffix(code, count, options = {}) {
1765
+ getSuffix(code, count) {
1766
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1301
1767
  const rule = this.getRule(code, options);
1302
1768
  if (rule) {
1303
- return `${this.options.prepend}${options.ordinal ? `ordinal${this.options.prepend}` : ''}${rule.select(count)}`;
1769
+ if (this.shouldUseIntlApi()) {
1770
+ return `${this.options.prepend}${options.ordinal ? `ordinal${this.options.prepend}` : ''}${rule.select(count)}`;
1771
+ }
1772
+ return this.getSuffixRetroCompatible(rule, count);
1304
1773
  }
1305
1774
  this.logger.warn(`no plural rule found for: ${code}`);
1306
- return this.getSuffix('dev', count, options);
1775
+ return '';
1776
+ }
1777
+ getSuffixRetroCompatible(rule, count) {
1778
+ const idx = rule.noAbs ? rule.plurals(count) : rule.plurals(Math.abs(count));
1779
+ let suffix = rule.numbers[idx];
1780
+ if (this.options.simplifyPluralSuffix && rule.numbers.length === 2 && rule.numbers[0] === 1) {
1781
+ if (suffix === 2) {
1782
+ suffix = 'plural';
1783
+ } else if (suffix === 1) {
1784
+ suffix = '';
1785
+ }
1786
+ }
1787
+ const returnSuffix = () => this.options.prepend && suffix.toString() ? this.options.prepend + suffix.toString() : suffix.toString();
1788
+ if (this.options.compatibilityJSON === 'v1') {
1789
+ if (suffix === 1) return '';
1790
+ if (typeof suffix === 'number') return `_plural_${suffix.toString()}`;
1791
+ return returnSuffix();
1792
+ } else if (this.options.compatibilityJSON === 'v2') {
1793
+ return returnSuffix();
1794
+ } else if (this.options.simplifyPluralSuffix && rule.numbers.length === 2 && rule.numbers[0] === 1) {
1795
+ return returnSuffix();
1796
+ }
1797
+ return this.options.prepend && idx.toString() ? this.options.prepend + idx.toString() : idx.toString();
1798
+ }
1799
+ shouldUseIntlApi() {
1800
+ return !nonIntlVersions.includes(this.options.compatibilityJSON);
1307
1801
  }
1308
1802
  }
1309
1803
 
1310
- const deepFindWithDefaults = (data, defaultData, key, keySeparator = '.', ignoreJSONStructure = true) => {
1804
+ const deepFindWithDefaults = function (data, defaultData, key) {
1805
+ let keySeparator = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '.';
1806
+ let ignoreJSONStructure = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
1311
1807
  let path = getPathWithDefaults(data, defaultData, key);
1312
1808
  if (!path && ignoreJSONStructure && isString(key)) {
1313
1809
  path = deepFind(data, key, keySeparator);
@@ -1317,13 +1813,15 @@ const deepFindWithDefaults = (data, defaultData, key, keySeparator = '.', ignore
1317
1813
  };
1318
1814
  const regexSafe = val => val.replace(/\$/g, '$$$$');
1319
1815
  class Interpolator {
1320
- constructor(options = {}) {
1816
+ constructor() {
1817
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1321
1818
  this.logger = baseLogger.create('interpolator');
1322
1819
  this.options = options;
1323
- this.format = options?.interpolation?.format || (value => value);
1820
+ this.format = options.interpolation && options.interpolation.format || (value => value);
1324
1821
  this.init(options);
1325
1822
  }
1326
- init(options = {}) {
1823
+ init() {
1824
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1327
1825
  if (!options.interpolation) options.interpolation = {
1328
1826
  escapeValue: true
1329
1827
  };
@@ -1366,7 +1864,7 @@ class Interpolator {
1366
1864
  }
1367
1865
  resetRegExp() {
1368
1866
  const getOrResetRegExp = (existingRegExp, pattern) => {
1369
- if (existingRegExp?.source === pattern) {
1867
+ if (existingRegExp && existingRegExp.source === pattern) {
1370
1868
  existingRegExp.lastIndex = 0;
1371
1869
  return existingRegExp;
1372
1870
  }
@@ -1374,7 +1872,7 @@ class Interpolator {
1374
1872
  };
1375
1873
  this.regexp = getOrResetRegExp(this.regexp, `${this.prefix}(.+?)${this.suffix}`);
1376
1874
  this.regexpUnescape = getOrResetRegExp(this.regexpUnescape, `${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`);
1377
- this.nestingRegexp = getOrResetRegExp(this.nestingRegexp, `${this.nestingPrefix}((?:[^()"']+|"[^"]*"|'[^']*'|\\((?:[^()]|"[^"]*"|'[^']*')*\\))*?)${this.nestingSuffix}`);
1875
+ this.nestingRegexp = getOrResetRegExp(this.nestingRegexp, `${this.nestingPrefix}(.+?)${this.nestingSuffix}`);
1378
1876
  }
1379
1877
  interpolate(str, data, lng, options) {
1380
1878
  let match;
@@ -1400,8 +1898,8 @@ class Interpolator {
1400
1898
  });
1401
1899
  };
1402
1900
  this.resetRegExp();
1403
- const missingInterpolationHandler = options?.missingInterpolationHandler || this.options.missingInterpolationHandler;
1404
- const skipOnVariables = options?.interpolation?.skipOnVariables !== undefined ? options.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables;
1901
+ const missingInterpolationHandler = options && options.missingInterpolationHandler || this.options.missingInterpolationHandler;
1902
+ const skipOnVariables = options && options.interpolation && options.interpolation.skipOnVariables !== undefined ? options.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables;
1405
1903
  const todos = [{
1406
1904
  regex: this.regexpUnescape,
1407
1905
  safeValue: val => regexSafe(val)
@@ -1446,20 +1944,21 @@ class Interpolator {
1446
1944
  });
1447
1945
  return str;
1448
1946
  }
1449
- nest(str, fc, options = {}) {
1947
+ nest(str, fc) {
1948
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1450
1949
  let match;
1451
1950
  let value;
1452
1951
  let clonedOptions;
1453
1952
  const handleHasOptions = (key, inheritedOptions) => {
1454
1953
  const sep = this.nestingOptionsSeparator;
1455
1954
  if (key.indexOf(sep) < 0) return key;
1456
- const c = key.split(new RegExp(`${regexEscape(sep)}[ ]*{`));
1955
+ const c = key.split(new RegExp(`${sep}[ ]*{`));
1457
1956
  let optionsString = `{${c[1]}`;
1458
1957
  key = c[0];
1459
1958
  optionsString = this.interpolate(optionsString, clonedOptions);
1460
1959
  const matchedSingleQuotes = optionsString.match(/'/g);
1461
1960
  const matchedDoubleQuotes = optionsString.match(/"/g);
1462
- if ((matchedSingleQuotes?.length ?? 0) % 2 === 0 && !matchedDoubleQuotes || (matchedDoubleQuotes?.length ?? 0) % 2 !== 0) {
1961
+ if (matchedSingleQuotes && matchedSingleQuotes.length % 2 === 0 && !matchedDoubleQuotes || matchedDoubleQuotes.length % 2 !== 0) {
1463
1962
  optionsString = optionsString.replace(/'/g, '"');
1464
1963
  }
1465
1964
  try {
@@ -1483,10 +1982,12 @@ class Interpolator {
1483
1982
  clonedOptions = clonedOptions.replace && !isString(clonedOptions.replace) ? clonedOptions.replace : clonedOptions;
1484
1983
  clonedOptions.applyPostProcessor = false;
1485
1984
  delete clonedOptions.defaultValue;
1486
- const keyEndIndex = /{.*}/.test(match[1]) ? match[1].lastIndexOf('}') + 1 : match[1].indexOf(this.formatSeparator);
1487
- if (keyEndIndex !== -1) {
1488
- formatters = match[1].slice(keyEndIndex).split(this.formatSeparator).map(elem => elem.trim()).filter(Boolean);
1489
- match[1] = match[1].slice(0, keyEndIndex);
1985
+ let doReduce = false;
1986
+ if (match[0].indexOf(this.formatSeparator) !== -1 && !/{.*}/.test(match[1])) {
1987
+ const r = match[1].split(this.formatSeparator).map(elem => elem.trim());
1988
+ match[1] = r.shift();
1989
+ formatters = r;
1990
+ doReduce = true;
1490
1991
  }
1491
1992
  value = fc(handleHasOptions.call(this, match[1].trim(), clonedOptions), clonedOptions);
1492
1993
  if (value && match[0] === str && !isString(value)) return value;
@@ -1495,7 +1996,7 @@ class Interpolator {
1495
1996
  this.logger.warn(`missed to resolve ${match[1]} for nesting ${str}`);
1496
1997
  value = '';
1497
1998
  }
1498
- if (formatters.length) {
1999
+ if (doReduce) {
1499
2000
  value = formatters.reduce((v, f) => this.format(v, f, options.lng, {
1500
2001
  ...options,
1501
2002
  interpolationkey: match[1].trim()
@@ -1541,68 +2042,68 @@ const parseFormatStr = formatStr => {
1541
2042
  };
1542
2043
  const createCachedFormatter = fn => {
1543
2044
  const cache = {};
1544
- return (v, l, o) => {
1545
- let optForCache = o;
1546
- if (o && o.interpolationkey && o.formatParams && o.formatParams[o.interpolationkey] && o[o.interpolationkey]) {
2045
+ return (val, lng, options) => {
2046
+ let optForCache = options;
2047
+ if (options && options.interpolationkey && options.formatParams && options.formatParams[options.interpolationkey] && options[options.interpolationkey]) {
1547
2048
  optForCache = {
1548
2049
  ...optForCache,
1549
- [o.interpolationkey]: undefined
2050
+ [options.interpolationkey]: undefined
1550
2051
  };
1551
2052
  }
1552
- const key = l + JSON.stringify(optForCache);
1553
- let frm = cache[key];
1554
- if (!frm) {
1555
- frm = fn(getCleanedCode(l), o);
1556
- cache[key] = frm;
2053
+ const key = lng + JSON.stringify(optForCache);
2054
+ let formatter = cache[key];
2055
+ if (!formatter) {
2056
+ formatter = fn(getCleanedCode(lng), options);
2057
+ cache[key] = formatter;
1557
2058
  }
1558
- return frm(v);
2059
+ return formatter(val);
1559
2060
  };
1560
2061
  };
1561
- const createNonCachedFormatter = fn => (v, l, o) => fn(getCleanedCode(l), o)(v);
1562
2062
  class Formatter {
1563
- constructor(options = {}) {
2063
+ constructor() {
2064
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1564
2065
  this.logger = baseLogger.create('formatter');
1565
2066
  this.options = options;
1566
- this.init(options);
1567
- }
1568
- init(services, options = {
1569
- interpolation: {}
1570
- }) {
1571
- this.formatSeparator = options.interpolation.formatSeparator || ',';
1572
- const cf = options.cacheInBuiltFormats ? createCachedFormatter : createNonCachedFormatter;
1573
2067
  this.formats = {
1574
- number: cf((lng, opt) => {
2068
+ number: createCachedFormatter((lng, opt) => {
1575
2069
  const formatter = new Intl.NumberFormat(lng, {
1576
2070
  ...opt
1577
2071
  });
1578
2072
  return val => formatter.format(val);
1579
2073
  }),
1580
- currency: cf((lng, opt) => {
2074
+ currency: createCachedFormatter((lng, opt) => {
1581
2075
  const formatter = new Intl.NumberFormat(lng, {
1582
2076
  ...opt,
1583
2077
  style: 'currency'
1584
2078
  });
1585
2079
  return val => formatter.format(val);
1586
2080
  }),
1587
- datetime: cf((lng, opt) => {
2081
+ datetime: createCachedFormatter((lng, opt) => {
1588
2082
  const formatter = new Intl.DateTimeFormat(lng, {
1589
2083
  ...opt
1590
2084
  });
1591
2085
  return val => formatter.format(val);
1592
2086
  }),
1593
- relativetime: cf((lng, opt) => {
2087
+ relativetime: createCachedFormatter((lng, opt) => {
1594
2088
  const formatter = new Intl.RelativeTimeFormat(lng, {
1595
2089
  ...opt
1596
2090
  });
1597
2091
  return val => formatter.format(val, opt.range || 'day');
1598
2092
  }),
1599
- list: cf((lng, opt) => {
2093
+ list: createCachedFormatter((lng, opt) => {
1600
2094
  const formatter = new Intl.ListFormat(lng, {
1601
2095
  ...opt
1602
2096
  });
1603
2097
  return val => formatter.format(val);
1604
2098
  })
1605
2099
  };
2100
+ this.init(options);
2101
+ }
2102
+ init(services) {
2103
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
2104
+ interpolation: {}
2105
+ };
2106
+ this.formatSeparator = options.interpolation.formatSeparator || ',';
1606
2107
  }
1607
2108
  add(name, fc) {
1608
2109
  this.formats[name.toLowerCase().trim()] = fc;
@@ -1610,7 +2111,8 @@ class Formatter {
1610
2111
  addCached(name, fc) {
1611
2112
  this.formats[name.toLowerCase().trim()] = createCachedFormatter(fc);
1612
2113
  }
1613
- format(value, format, lng, options = {}) {
2114
+ format(value, format, lng) {
2115
+ let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1614
2116
  const formats = format.split(this.formatSeparator);
1615
2117
  if (formats.length > 1 && formats[0].indexOf('(') > 1 && formats[0].indexOf(')') < 0 && formats.find(f => f.indexOf(')') > -1)) {
1616
2118
  const lastIndex = formats.findIndex(f => f.indexOf(')') > -1);
@@ -1624,7 +2126,7 @@ class Formatter {
1624
2126
  if (this.formats[formatName]) {
1625
2127
  let formatted = mem;
1626
2128
  try {
1627
- const valOptions = options?.formatParams?.[options.interpolationkey] || {};
2129
+ const valOptions = options && options.formatParams && options.formatParams[options.interpolationkey] || {};
1628
2130
  const l = valOptions.locale || valOptions.lng || options.locale || options.lng || lng;
1629
2131
  formatted = this.formats[formatName](mem, l, {
1630
2132
  ...formatOptions,
@@ -1651,7 +2153,8 @@ const removePending = (q, name) => {
1651
2153
  }
1652
2154
  };
1653
2155
  class Connector extends EventEmitter {
1654
- constructor(backend, store, services, options = {}) {
2156
+ constructor(backend, store, services) {
2157
+ let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1655
2158
  super();
1656
2159
  this.backend = backend;
1657
2160
  this.store = store;
@@ -1666,7 +2169,9 @@ class Connector extends EventEmitter {
1666
2169
  this.retryTimeout = options.retryTimeout >= 1 ? options.retryTimeout : 350;
1667
2170
  this.state = {};
1668
2171
  this.queue = [];
1669
- this.backend?.init?.(services, options.backend, options);
2172
+ if (this.backend && this.backend.init) {
2173
+ this.backend.init(services, options.backend, options);
2174
+ }
1670
2175
  }
1671
2176
  queueLoad(languages, namespaces, options, callback) {
1672
2177
  const toLoad = {};
@@ -1745,7 +2250,10 @@ class Connector extends EventEmitter {
1745
2250
  this.emit('loaded', loaded);
1746
2251
  this.queue = this.queue.filter(q => !q.done);
1747
2252
  }
1748
- read(lng, ns, fcName, tried = 0, wait = this.retryTimeout, callback) {
2253
+ read(lng, ns, fcName) {
2254
+ let tried = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
2255
+ let wait = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : this.retryTimeout;
2256
+ let callback = arguments.length > 5 ? arguments[5] : undefined;
1749
2257
  if (!lng.length) return callback(null, {});
1750
2258
  if (this.readingCalls >= this.maxParallelReads) {
1751
2259
  this.waitingReads.push({
@@ -1789,7 +2297,9 @@ class Connector extends EventEmitter {
1789
2297
  }
1790
2298
  return fc(lng, ns, resolver);
1791
2299
  }
1792
- prepareLoading(languages, namespaces, options = {}, callback) {
2300
+ prepareLoading(languages, namespaces) {
2301
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2302
+ let callback = arguments.length > 3 ? arguments[3] : undefined;
1793
2303
  if (!this.backend) {
1794
2304
  this.logger.warn('No backend was added via i18next.use. Will not load resources.');
1795
2305
  return callback && callback();
@@ -1813,7 +2323,8 @@ class Connector extends EventEmitter {
1813
2323
  reload: true
1814
2324
  }, callback);
1815
2325
  }
1816
- loadOne(name, prefix = '') {
2326
+ loadOne(name) {
2327
+ let prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
1817
2328
  const s = name.split('|');
1818
2329
  const lng = s[0];
1819
2330
  const ns = s[1];
@@ -1823,13 +2334,15 @@ class Connector extends EventEmitter {
1823
2334
  this.loaded(name, err, data);
1824
2335
  });
1825
2336
  }
1826
- saveMissing(languages, namespace, key, fallbackValue, isUpdate, options = {}, clb = () => {}) {
1827
- if (this.services?.utils?.hasLoadedNamespace && !this.services?.utils?.hasLoadedNamespace(namespace)) {
2337
+ saveMissing(languages, namespace, key, fallbackValue, isUpdate) {
2338
+ let options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
2339
+ let clb = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : () => {};
2340
+ if (this.services.utils && this.services.utils.hasLoadedNamespace && !this.services.utils.hasLoadedNamespace(namespace)) {
1828
2341
  this.logger.warn(`did not save key "${key}" as the namespace "${namespace}" was not yet loaded`, 'This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!');
1829
2342
  return;
1830
2343
  }
1831
2344
  if (key === undefined || key === null || key === '') return;
1832
- if (this.backend?.create) {
2345
+ if (this.backend && this.backend.create) {
1833
2346
  const opts = {
1834
2347
  ...options,
1835
2348
  isUpdate
@@ -1862,7 +2375,7 @@ class Connector extends EventEmitter {
1862
2375
 
1863
2376
  const get = () => ({
1864
2377
  debug: false,
1865
- initAsync: true,
2378
+ initImmediate: true,
1866
2379
  ns: ['translation'],
1867
2380
  defaultNS: ['translation'],
1868
2381
  fallbackLng: ['dev'],
@@ -1918,17 +2431,15 @@ const get = () => ({
1918
2431
  nestingOptionsSeparator: ',',
1919
2432
  maxReplaces: 1000,
1920
2433
  skipOnVariables: true
1921
- },
1922
- cacheInBuiltFormats: true
2434
+ }
1923
2435
  });
1924
2436
  const transformOptions = options => {
1925
2437
  if (isString(options.ns)) options.ns = [options.ns];
1926
2438
  if (isString(options.fallbackLng)) options.fallbackLng = [options.fallbackLng];
1927
2439
  if (isString(options.fallbackNS)) options.fallbackNS = [options.fallbackNS];
1928
- if (options.supportedLngs?.indexOf?.('cimode') < 0) {
2440
+ if (options.supportedLngs && options.supportedLngs.indexOf('cimode') < 0) {
1929
2441
  options.supportedLngs = options.supportedLngs.concat(['cimode']);
1930
2442
  }
1931
- if (typeof options.initImmediate === 'boolean') options.initAsync = options.initImmediate;
1932
2443
  return options;
1933
2444
  };
1934
2445
 
@@ -1941,17 +2452,10 @@ const bindMemberFunctions = inst => {
1941
2452
  }
1942
2453
  });
1943
2454
  };
1944
- let supportNoticeShown = false;
1945
- const usesLocize = inst => {
1946
- if (inst?.modules?.backend?.name?.indexOf('Locize') > 0) return true;
1947
- if (inst?.modules?.backend?.constructor?.name?.indexOf('Locize') > 0) return true;
1948
- if (inst?.options?.backend?.backends) {
1949
- if (inst.options.backend.backends.some(b => b?.name?.indexOf('Locize') > 0 || b?.constructor?.name?.indexOf('Locize') > 0)) return true;
1950
- }
1951
- return false;
1952
- };
1953
2455
  class I18n extends EventEmitter {
1954
- constructor(options = {}, callback) {
2456
+ constructor() {
2457
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2458
+ let callback = arguments.length > 1 ? arguments[1] : undefined;
1955
2459
  super();
1956
2460
  this.options = transformOptions(options);
1957
2461
  this.services = {};
@@ -1961,7 +2465,7 @@ class I18n extends EventEmitter {
1961
2465
  };
1962
2466
  bindMemberFunctions(this);
1963
2467
  if (callback && !this.isInitialized && !options.isClone) {
1964
- if (!this.options.initAsync) {
2468
+ if (!this.options.initImmediate) {
1965
2469
  this.init(options, callback);
1966
2470
  return this;
1967
2471
  }
@@ -1970,13 +2474,16 @@ class I18n extends EventEmitter {
1970
2474
  }, 0);
1971
2475
  }
1972
2476
  }
1973
- init(options = {}, callback) {
2477
+ init() {
2478
+ var _this = this;
2479
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2480
+ let callback = arguments.length > 1 ? arguments[1] : undefined;
1974
2481
  this.isInitializing = true;
1975
2482
  if (typeof options === 'function') {
1976
2483
  callback = options;
1977
2484
  options = {};
1978
2485
  }
1979
- if (options.defaultNS == null && options.ns) {
2486
+ if (!options.defaultNS && options.defaultNS !== false && options.ns) {
1980
2487
  if (isString(options.ns)) {
1981
2488
  options.defaultNS = options.ns;
1982
2489
  } else if (options.ns.indexOf('translation') < 0) {
@@ -1989,23 +2496,18 @@ class I18n extends EventEmitter {
1989
2496
  ...this.options,
1990
2497
  ...transformOptions(options)
1991
2498
  };
1992
- this.options.interpolation = {
1993
- ...defOpts.interpolation,
1994
- ...this.options.interpolation
1995
- };
2499
+ if (this.options.compatibilityAPI !== 'v1') {
2500
+ this.options.interpolation = {
2501
+ ...defOpts.interpolation,
2502
+ ...this.options.interpolation
2503
+ };
2504
+ }
1996
2505
  if (options.keySeparator !== undefined) {
1997
2506
  this.options.userDefinedKeySeparator = options.keySeparator;
1998
2507
  }
1999
2508
  if (options.nsSeparator !== undefined) {
2000
2509
  this.options.userDefinedNsSeparator = options.nsSeparator;
2001
2510
  }
2002
- if (typeof this.options.overloadTranslationOptionHandler !== 'function') {
2003
- this.options.overloadTranslationOptionHandler = defOpts.overloadTranslationOptionHandler;
2004
- }
2005
- if (this.options.showSupportNotice !== false && !usesLocize(this) && !supportNoticeShown) {
2006
- if (typeof console !== 'undefined' && typeof console.info !== 'undefined') console.info('🌐 i18next is maintained with support from Locize — consider powering your project with managed localization (AI, CDN, integrations): https://locize.com 💙');
2007
- supportNoticeShown = true;
2008
- }
2009
2511
  const createClassOnDemand = ClassOrObject => {
2010
2512
  if (!ClassOrObject) return null;
2011
2513
  if (typeof ClassOrObject === 'function') return new ClassOrObject();
@@ -2020,7 +2522,7 @@ class I18n extends EventEmitter {
2020
2522
  let formatter;
2021
2523
  if (this.modules.formatter) {
2022
2524
  formatter = this.modules.formatter;
2023
- } else {
2525
+ } else if (typeof Intl !== 'undefined') {
2024
2526
  formatter = Formatter;
2025
2527
  }
2026
2528
  const lu = new LanguageUtil(this.options);
@@ -2031,15 +2533,12 @@ class I18n extends EventEmitter {
2031
2533
  s.languageUtils = lu;
2032
2534
  s.pluralResolver = new PluralResolver(lu, {
2033
2535
  prepend: this.options.pluralSeparator,
2536
+ compatibilityJSON: this.options.compatibilityJSON,
2034
2537
  simplifyPluralSuffix: this.options.simplifyPluralSuffix
2035
2538
  });
2036
- const usingLegacyFormatFunction = this.options.interpolation.format && this.options.interpolation.format !== defOpts.interpolation.format;
2037
- if (usingLegacyFormatFunction) {
2038
- this.logger.deprecate(`init: you are still using the legacy format function, please use the new approach: https://www.i18next.com/translation-function/formatting`);
2039
- }
2040
2539
  if (formatter && (!this.options.interpolation.format || this.options.interpolation.format === defOpts.interpolation.format)) {
2041
2540
  s.formatter = createClassOnDemand(formatter);
2042
- if (s.formatter.init) s.formatter.init(s, this.options);
2541
+ s.formatter.init(s, this.options);
2043
2542
  this.options.interpolation.format = s.formatter.format.bind(s.formatter);
2044
2543
  }
2045
2544
  s.interpolator = new Interpolator(this.options);
@@ -2047,8 +2546,11 @@ class I18n extends EventEmitter {
2047
2546
  hasLoadedNamespace: this.hasLoadedNamespace.bind(this)
2048
2547
  };
2049
2548
  s.backendConnector = new Connector(createClassOnDemand(this.modules.backend), s.resourceStore, s, this.options);
2050
- s.backendConnector.on('*', (event, ...args) => {
2051
- this.emit(event, ...args);
2549
+ s.backendConnector.on('*', function (event) {
2550
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
2551
+ args[_key - 1] = arguments[_key];
2552
+ }
2553
+ _this.emit(event, ...args);
2052
2554
  });
2053
2555
  if (this.modules.languageDetector) {
2054
2556
  s.languageDetector = createClassOnDemand(this.modules.languageDetector);
@@ -2059,8 +2561,11 @@ class I18n extends EventEmitter {
2059
2561
  if (s.i18nFormat.init) s.i18nFormat.init(this);
2060
2562
  }
2061
2563
  this.translator = new Translator(this.services, this.options);
2062
- this.translator.on('*', (event, ...args) => {
2063
- this.emit(event, ...args);
2564
+ this.translator.on('*', function (event) {
2565
+ for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
2566
+ args[_key2 - 1] = arguments[_key2];
2567
+ }
2568
+ _this.emit(event, ...args);
2064
2569
  });
2065
2570
  this.modules.external.forEach(m => {
2066
2571
  if (m.init) m.init(this);
@@ -2077,13 +2582,15 @@ class I18n extends EventEmitter {
2077
2582
  }
2078
2583
  const storeApi = ['getResource', 'hasResourceBundle', 'getResourceBundle', 'getDataByLanguage'];
2079
2584
  storeApi.forEach(fcName => {
2080
- this[fcName] = (...args) => this.store[fcName](...args);
2585
+ this[fcName] = function () {
2586
+ return _this.store[fcName](...arguments);
2587
+ };
2081
2588
  });
2082
2589
  const storeApiChained = ['addResource', 'addResources', 'addResourceBundle', 'removeResourceBundle'];
2083
2590
  storeApiChained.forEach(fcName => {
2084
- this[fcName] = (...args) => {
2085
- this.store[fcName](...args);
2086
- return this;
2591
+ this[fcName] = function () {
2592
+ _this.store[fcName](...arguments);
2593
+ return _this;
2087
2594
  };
2088
2595
  });
2089
2596
  const deferred = defer();
@@ -2097,22 +2604,23 @@ class I18n extends EventEmitter {
2097
2604
  deferred.resolve(t);
2098
2605
  callback(err, t);
2099
2606
  };
2100
- if (this.languages && !this.isInitialized) return finish(null, this.t.bind(this));
2607
+ if (this.languages && this.options.compatibilityAPI !== 'v1' && !this.isInitialized) return finish(null, this.t.bind(this));
2101
2608
  this.changeLanguage(this.options.lng, finish);
2102
2609
  };
2103
- if (this.options.resources || !this.options.initAsync) {
2610
+ if (this.options.resources || !this.options.initImmediate) {
2104
2611
  load();
2105
2612
  } else {
2106
2613
  setTimeout(load, 0);
2107
2614
  }
2108
2615
  return deferred;
2109
2616
  }
2110
- loadResources(language, callback = noop) {
2617
+ loadResources(language) {
2618
+ let callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop;
2111
2619
  let usedCallback = callback;
2112
2620
  const usedLng = isString(language) ? language : this.language;
2113
2621
  if (typeof language === 'function') usedCallback = language;
2114
2622
  if (!this.options.resources || this.options.partialBundledLanguages) {
2115
- if (usedLng?.toLowerCase() === 'cimode' && (!this.options.preload || this.options.preload.length === 0)) return usedCallback();
2623
+ if (usedLng && usedLng.toLowerCase() === 'cimode' && (!this.options.preload || this.options.preload.length === 0)) return usedCallback();
2116
2624
  const toLoad = [];
2117
2625
  const append = lng => {
2118
2626
  if (!lng) return;
@@ -2129,7 +2637,9 @@ class I18n extends EventEmitter {
2129
2637
  } else {
2130
2638
  append(usedLng);
2131
2639
  }
2132
- this.options.preload?.forEach?.(l => append(l));
2640
+ if (this.options.preload) {
2641
+ this.options.preload.forEach(l => append(l));
2642
+ }
2133
2643
  this.services.backendConnector.load(toLoad, this.options.ns, e => {
2134
2644
  if (!e && !this.resolvedLanguage && this.language) this.setResolvedLanguage(this.language);
2135
2645
  usedCallback(e);
@@ -2194,542 +2704,249 @@ class I18n extends EventEmitter {
2194
2704
  break;
2195
2705
  }
2196
2706
  }
2197
- if (!this.resolvedLanguage && this.languages.indexOf(l) < 0 && this.store.hasLanguageSomeTranslations(l)) {
2198
- this.resolvedLanguage = l;
2199
- this.languages.unshift(l);
2200
- }
2201
2707
  }
2202
2708
  changeLanguage(lng, callback) {
2709
+ var _this2 = this;
2203
2710
  this.isLanguageChangingTo = lng;
2204
2711
  const deferred = defer();
2205
2712
  this.emit('languageChanging', lng);
2206
- const setLngProps = l => {
2207
- this.language = l;
2208
- this.languages = this.services.languageUtils.toResolveHierarchy(l);
2209
- this.resolvedLanguage = undefined;
2210
- this.setResolvedLanguage(l);
2211
- };
2212
- const done = (err, l) => {
2213
- if (l) {
2214
- if (this.isLanguageChangingTo === lng) {
2215
- setLngProps(l);
2216
- this.translator.changeLanguage(l);
2217
- this.isLanguageChangingTo = undefined;
2218
- this.emit('languageChanged', l);
2219
- this.logger.log('languageChanged', l);
2220
- }
2221
- } else {
2222
- this.isLanguageChangingTo = undefined;
2223
- }
2224
- deferred.resolve((...args) => this.t(...args));
2225
- if (callback) callback(err, (...args) => this.t(...args));
2226
- };
2227
- const setLng = lngs => {
2228
- if (!lng && !lngs && this.services.languageDetector) lngs = [];
2229
- const fl = isString(lngs) ? lngs : lngs && lngs[0];
2230
- const l = this.store.hasLanguageSomeTranslations(fl) ? fl : this.services.languageUtils.getBestMatchFromCodes(isString(lngs) ? [lngs] : lngs);
2231
- if (l) {
2232
- if (!this.language) {
2233
- setLngProps(l);
2234
- }
2235
- if (!this.translator.language) this.translator.changeLanguage(l);
2236
- this.services.languageDetector?.cacheUserLanguage?.(l);
2237
- }
2238
- this.loadResources(l, err => {
2239
- done(err, l);
2240
- });
2241
- };
2242
- if (!lng && this.services.languageDetector && !this.services.languageDetector.async) {
2243
- setLng(this.services.languageDetector.detect());
2244
- } else if (!lng && this.services.languageDetector && this.services.languageDetector.async) {
2245
- if (this.services.languageDetector.detect.length === 0) {
2246
- this.services.languageDetector.detect().then(setLng);
2247
- } else {
2248
- this.services.languageDetector.detect(setLng);
2249
- }
2250
- } else {
2251
- setLng(lng);
2252
- }
2253
- return deferred;
2254
- }
2255
- getFixedT(lng, ns, keyPrefix) {
2256
- const fixedT = (key, opts, ...rest) => {
2257
- let o;
2258
- if (typeof opts !== 'object') {
2259
- o = this.options.overloadTranslationOptionHandler([key, opts].concat(rest));
2260
- } else {
2261
- o = {
2262
- ...opts
2263
- };
2264
- }
2265
- o.lng = o.lng || fixedT.lng;
2266
- o.lngs = o.lngs || fixedT.lngs;
2267
- o.ns = o.ns || fixedT.ns;
2268
- if (o.keyPrefix !== '') o.keyPrefix = o.keyPrefix || keyPrefix || fixedT.keyPrefix;
2269
- const keySeparator = this.options.keySeparator || '.';
2270
- let resultKey;
2271
- if (o.keyPrefix && Array.isArray(key)) {
2272
- resultKey = key.map(k => {
2273
- if (typeof k === 'function') k = keysFromSelector(k, {
2274
- ...this.options,
2275
- ...opts
2276
- });
2277
- return `${o.keyPrefix}${keySeparator}${k}`;
2278
- });
2279
- } else {
2280
- if (typeof key === 'function') key = keysFromSelector(key, {
2281
- ...this.options,
2282
- ...opts
2283
- });
2284
- resultKey = o.keyPrefix ? `${o.keyPrefix}${keySeparator}${key}` : key;
2285
- }
2286
- return this.t(resultKey, o);
2287
- };
2288
- if (isString(lng)) {
2289
- fixedT.lng = lng;
2290
- } else {
2291
- fixedT.lngs = lng;
2292
- }
2293
- fixedT.ns = ns;
2294
- fixedT.keyPrefix = keyPrefix;
2295
- return fixedT;
2296
- }
2297
- t(...args) {
2298
- return this.translator?.translate(...args);
2299
- }
2300
- exists(...args) {
2301
- return this.translator?.exists(...args);
2302
- }
2303
- setDefaultNamespace(ns) {
2304
- this.options.defaultNS = ns;
2305
- }
2306
- hasLoadedNamespace(ns, options = {}) {
2307
- if (!this.isInitialized) {
2308
- this.logger.warn('hasLoadedNamespace: i18next was not initialized', this.languages);
2309
- return false;
2310
- }
2311
- if (!this.languages || !this.languages.length) {
2312
- this.logger.warn('hasLoadedNamespace: i18n.languages were undefined or empty', this.languages);
2313
- return false;
2314
- }
2315
- const lng = options.lng || this.resolvedLanguage || this.languages[0];
2316
- const fallbackLng = this.options ? this.options.fallbackLng : false;
2317
- const lastLng = this.languages[this.languages.length - 1];
2318
- if (lng.toLowerCase() === 'cimode') return true;
2319
- const loadNotPending = (l, n) => {
2320
- const loadState = this.services.backendConnector.state[`${l}|${n}`];
2321
- return loadState === -1 || loadState === 0 || loadState === 2;
2322
- };
2323
- if (options.precheck) {
2324
- const preResult = options.precheck(this, loadNotPending);
2325
- if (preResult !== undefined) return preResult;
2326
- }
2327
- if (this.hasResourceBundle(lng, ns)) return true;
2328
- if (!this.services.backendConnector.backend || this.options.resources && !this.options.partialBundledLanguages) return true;
2329
- if (loadNotPending(lng, ns) && (!fallbackLng || loadNotPending(lastLng, ns))) return true;
2330
- return false;
2331
- }
2332
- loadNamespaces(ns, callback) {
2333
- const deferred = defer();
2334
- if (!this.options.ns) {
2335
- if (callback) callback();
2336
- return Promise.resolve();
2337
- }
2338
- if (isString(ns)) ns = [ns];
2339
- ns.forEach(n => {
2340
- if (this.options.ns.indexOf(n) < 0) this.options.ns.push(n);
2341
- });
2342
- this.loadResources(err => {
2343
- deferred.resolve();
2344
- if (callback) callback(err);
2345
- });
2346
- return deferred;
2347
- }
2348
- loadLanguages(lngs, callback) {
2349
- const deferred = defer();
2350
- if (isString(lngs)) lngs = [lngs];
2351
- const preloaded = this.options.preload || [];
2352
- const newLngs = lngs.filter(lng => preloaded.indexOf(lng) < 0 && this.services.languageUtils.isSupportedCode(lng));
2353
- if (!newLngs.length) {
2354
- if (callback) callback();
2355
- return Promise.resolve();
2356
- }
2357
- this.options.preload = preloaded.concat(newLngs);
2358
- this.loadResources(err => {
2359
- deferred.resolve();
2360
- if (callback) callback(err);
2361
- });
2362
- return deferred;
2363
- }
2364
- dir(lng) {
2365
- if (!lng) lng = this.resolvedLanguage || (this.languages?.length > 0 ? this.languages[0] : this.language);
2366
- if (!lng) return 'rtl';
2367
- try {
2368
- const l = new Intl.Locale(lng);
2369
- if (l && l.getTextInfo) {
2370
- const ti = l.getTextInfo();
2371
- if (ti && ti.direction) return ti.direction;
2372
- }
2373
- } catch (e) {}
2374
- const rtlLngs = ['ar', 'shu', 'sqr', 'ssh', 'xaa', 'yhd', 'yud', 'aao', 'abh', 'abv', 'acm', 'acq', 'acw', 'acx', 'acy', 'adf', 'ads', 'aeb', 'aec', 'afb', 'ajp', 'apc', 'apd', 'arb', 'arq', 'ars', 'ary', 'arz', 'auz', 'avl', 'ayh', 'ayl', 'ayn', 'ayp', 'bbz', 'pga', 'he', 'iw', 'ps', 'pbt', 'pbu', 'pst', 'prp', 'prd', 'ug', 'ur', 'ydd', 'yds', 'yih', 'ji', 'yi', 'hbo', 'men', 'xmn', 'fa', 'jpr', 'peo', 'pes', 'prs', 'dv', 'sam', 'ckb'];
2375
- const languageUtils = this.services?.languageUtils || new LanguageUtil(get());
2376
- if (lng.toLowerCase().indexOf('-latn') > 1) return 'ltr';
2377
- return rtlLngs.indexOf(languageUtils.getLanguagePartFromCode(lng)) > -1 || lng.toLowerCase().indexOf('-arab') > 1 ? 'rtl' : 'ltr';
2378
- }
2379
- static createInstance(options = {}, callback) {
2380
- const instance = new I18n(options, callback);
2381
- instance.createInstance = I18n.createInstance;
2382
- return instance;
2383
- }
2384
- cloneInstance(options = {}, callback = noop) {
2385
- const forkResourceStore = options.forkResourceStore;
2386
- if (forkResourceStore) delete options.forkResourceStore;
2387
- const mergedOptions = {
2388
- ...this.options,
2389
- ...options,
2390
- ...{
2391
- isClone: true
2392
- }
2713
+ const setLngProps = l => {
2714
+ this.language = l;
2715
+ this.languages = this.services.languageUtils.toResolveHierarchy(l);
2716
+ this.resolvedLanguage = undefined;
2717
+ this.setResolvedLanguage(l);
2393
2718
  };
2394
- const clone = new I18n(mergedOptions);
2395
- if (options.debug !== undefined || options.prefix !== undefined) {
2396
- clone.logger = clone.logger.clone(options);
2397
- }
2398
- const membersToCopy = ['store', 'services', 'language'];
2399
- membersToCopy.forEach(m => {
2400
- clone[m] = this[m];
2401
- });
2402
- clone.services = {
2403
- ...this.services
2719
+ const done = (err, l) => {
2720
+ if (l) {
2721
+ setLngProps(l);
2722
+ this.translator.changeLanguage(l);
2723
+ this.isLanguageChangingTo = undefined;
2724
+ this.emit('languageChanged', l);
2725
+ this.logger.log('languageChanged', l);
2726
+ } else {
2727
+ this.isLanguageChangingTo = undefined;
2728
+ }
2729
+ deferred.resolve(function () {
2730
+ return _this2.t(...arguments);
2731
+ });
2732
+ if (callback) callback(err, function () {
2733
+ return _this2.t(...arguments);
2734
+ });
2404
2735
  };
2405
- clone.services.utils = {
2406
- hasLoadedNamespace: clone.hasLoadedNamespace.bind(clone)
2736
+ const setLng = lngs => {
2737
+ if (!lng && !lngs && this.services.languageDetector) lngs = [];
2738
+ const l = isString(lngs) ? lngs : this.services.languageUtils.getBestMatchFromCodes(lngs);
2739
+ if (l) {
2740
+ if (!this.language) {
2741
+ setLngProps(l);
2742
+ }
2743
+ if (!this.translator.language) this.translator.changeLanguage(l);
2744
+ if (this.services.languageDetector && this.services.languageDetector.cacheUserLanguage) this.services.languageDetector.cacheUserLanguage(l);
2745
+ }
2746
+ this.loadResources(l, err => {
2747
+ done(err, l);
2748
+ });
2407
2749
  };
2408
- if (forkResourceStore) {
2409
- const clonedData = Object.keys(this.store.data).reduce((prev, l) => {
2410
- prev[l] = {
2411
- ...this.store.data[l]
2412
- };
2413
- prev[l] = Object.keys(prev[l]).reduce((acc, n) => {
2414
- acc[n] = {
2415
- ...prev[l][n]
2416
- };
2417
- return acc;
2418
- }, prev[l]);
2419
- return prev;
2420
- }, {});
2421
- clone.store = new ResourceStore(clonedData, mergedOptions);
2422
- clone.services.resourceStore = clone.store;
2423
- }
2424
- if (options.interpolation) {
2425
- const defOpts = get();
2426
- const mergedInterpolation = {
2427
- ...defOpts.interpolation,
2428
- ...this.options.interpolation,
2429
- ...options.interpolation
2430
- };
2431
- const mergedForInterpolator = {
2432
- ...mergedOptions,
2433
- interpolation: mergedInterpolation
2434
- };
2435
- clone.services.interpolator = new Interpolator(mergedForInterpolator);
2750
+ if (!lng && this.services.languageDetector && !this.services.languageDetector.async) {
2751
+ setLng(this.services.languageDetector.detect());
2752
+ } else if (!lng && this.services.languageDetector && this.services.languageDetector.async) {
2753
+ if (this.services.languageDetector.detect.length === 0) {
2754
+ this.services.languageDetector.detect().then(setLng);
2755
+ } else {
2756
+ this.services.languageDetector.detect(setLng);
2757
+ }
2758
+ } else {
2759
+ setLng(lng);
2436
2760
  }
2437
- clone.translator = new Translator(clone.services, mergedOptions);
2438
- clone.translator.on('*', (event, ...args) => {
2439
- clone.emit(event, ...args);
2440
- });
2441
- clone.init(mergedOptions, callback);
2442
- clone.translator.options = mergedOptions;
2443
- clone.translator.backendConnector.services.utils = {
2444
- hasLoadedNamespace: clone.hasLoadedNamespace.bind(clone)
2445
- };
2446
- return clone;
2761
+ return deferred;
2447
2762
  }
2448
- toJSON() {
2449
- return {
2450
- options: this.options,
2451
- store: this.store,
2452
- language: this.language,
2453
- languages: this.languages,
2454
- resolvedLanguage: this.resolvedLanguage
2763
+ getFixedT(lng, ns, keyPrefix) {
2764
+ var _this3 = this;
2765
+ const fixedT = function (key, opts) {
2766
+ let options;
2767
+ if (typeof opts !== 'object') {
2768
+ for (var _len3 = arguments.length, rest = new Array(_len3 > 2 ? _len3 - 2 : 0), _key3 = 2; _key3 < _len3; _key3++) {
2769
+ rest[_key3 - 2] = arguments[_key3];
2770
+ }
2771
+ options = _this3.options.overloadTranslationOptionHandler([key, opts].concat(rest));
2772
+ } else {
2773
+ options = {
2774
+ ...opts
2775
+ };
2776
+ }
2777
+ options.lng = options.lng || fixedT.lng;
2778
+ options.lngs = options.lngs || fixedT.lngs;
2779
+ options.ns = options.ns || fixedT.ns;
2780
+ if (options.keyPrefix !== '') options.keyPrefix = options.keyPrefix || keyPrefix || fixedT.keyPrefix;
2781
+ const keySeparator = _this3.options.keySeparator || '.';
2782
+ let resultKey;
2783
+ if (options.keyPrefix && Array.isArray(key)) {
2784
+ resultKey = key.map(k => `${options.keyPrefix}${keySeparator}${k}`);
2785
+ } else {
2786
+ resultKey = options.keyPrefix ? `${options.keyPrefix}${keySeparator}${key}` : key;
2787
+ }
2788
+ return _this3.t(resultKey, options);
2455
2789
  };
2456
- }
2457
- }
2458
- const instance = I18n.createInstance();
2459
-
2460
- instance.createInstance;
2461
- instance.dir;
2462
- instance.init;
2463
- instance.loadResources;
2464
- instance.reloadResources;
2465
- instance.use;
2466
- instance.changeLanguage;
2467
- instance.getFixedT;
2468
- instance.t;
2469
- instance.exists;
2470
- instance.setDefaultNamespace;
2471
- instance.hasLoadedNamespace;
2472
- instance.loadNamespaces;
2473
- instance.loadLanguages;
2474
-
2475
- function warn() {
2476
- if (console && console.warn) {
2477
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
2478
- args[_key] = arguments[_key];
2790
+ if (isString(lng)) {
2791
+ fixedT.lng = lng;
2792
+ } else {
2793
+ fixedT.lngs = lng;
2479
2794
  }
2480
- if (typeof args[0] === 'string') args[0] = `react-i18next:: ${args[0]}`;
2481
- console.warn(...args);
2482
- }
2483
- }
2484
- const alreadyWarned = {};
2485
- function warnOnce() {
2486
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
2487
- args[_key2] = arguments[_key2];
2795
+ fixedT.ns = ns;
2796
+ fixedT.keyPrefix = keyPrefix;
2797
+ return fixedT;
2488
2798
  }
2489
- if (typeof args[0] === 'string' && alreadyWarned[args[0]]) return;
2490
- if (typeof args[0] === 'string') alreadyWarned[args[0]] = new Date();
2491
- warn(...args);
2492
- }
2493
- const loadedClb = (i18n, cb) => () => {
2494
- if (i18n.isInitialized) {
2495
- cb();
2496
- } else {
2497
- const initialized = () => {
2498
- setTimeout(() => {
2499
- i18n.off('initialized', initialized);
2500
- }, 0);
2501
- cb();
2502
- };
2503
- i18n.on('initialized', initialized);
2799
+ t() {
2800
+ return this.translator && this.translator.translate(...arguments);
2504
2801
  }
2505
- };
2506
- function loadNamespaces(i18n, ns, cb) {
2507
- i18n.loadNamespaces(ns, loadedClb(i18n, cb));
2508
- }
2509
- function loadLanguages(i18n, lng, ns, cb) {
2510
- if (typeof ns === 'string') ns = [ns];
2511
- ns.forEach(n => {
2512
- if (i18n.options.ns.indexOf(n) < 0) i18n.options.ns.push(n);
2513
- });
2514
- i18n.loadLanguages(lng, loadedClb(i18n, cb));
2515
- }
2516
- function oldI18nextHasLoadedNamespace(ns, i18n) {
2517
- let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2518
- const lng = i18n.languages[0];
2519
- const fallbackLng = i18n.options ? i18n.options.fallbackLng : false;
2520
- const lastLng = i18n.languages[i18n.languages.length - 1];
2521
- if (lng.toLowerCase() === 'cimode') return true;
2522
- const loadNotPending = (l, n) => {
2523
- const loadState = i18n.services.backendConnector.state[`${l}|${n}`];
2524
- return loadState === -1 || loadState === 2;
2525
- };
2526
- if (options.bindI18n && options.bindI18n.indexOf('languageChanging') > -1 && i18n.services.backendConnector.backend && i18n.isLanguageChangingTo && !loadNotPending(i18n.isLanguageChangingTo, ns)) return false;
2527
- if (i18n.hasResourceBundle(lng, ns)) return true;
2528
- if (!i18n.services.backendConnector.backend || i18n.options.resources && !i18n.options.partialBundledLanguages) return true;
2529
- if (loadNotPending(lng, ns) && (!fallbackLng || loadNotPending(lastLng, ns))) return true;
2530
- return false;
2531
- }
2532
- function hasLoadedNamespace(ns, i18n) {
2533
- let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2534
- if (!i18n.languages || !i18n.languages.length) {
2535
- warnOnce('i18n.languages were undefined or empty', i18n.languages);
2536
- return true;
2802
+ exists() {
2803
+ return this.translator && this.translator.exists(...arguments);
2537
2804
  }
2538
- const isNewerI18next = i18n.options.ignoreJSONStructure !== undefined;
2539
- if (!isNewerI18next) {
2540
- return oldI18nextHasLoadedNamespace(ns, i18n, options);
2805
+ setDefaultNamespace(ns) {
2806
+ this.options.defaultNS = ns;
2541
2807
  }
2542
- return i18n.hasLoadedNamespace(ns, {
2543
- lng: options.lng,
2544
- precheck: (i18nInstance, loadNotPending) => {
2545
- if (options.bindI18n && options.bindI18n.indexOf('languageChanging') > -1 && i18nInstance.services.backendConnector.backend && i18nInstance.isLanguageChangingTo && !loadNotPending(i18nInstance.isLanguageChangingTo, ns)) return false;
2808
+ hasLoadedNamespace(ns) {
2809
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2810
+ if (!this.isInitialized) {
2811
+ this.logger.warn('hasLoadedNamespace: i18next was not initialized', this.languages);
2812
+ return false;
2546
2813
  }
2547
- });
2548
- }
2549
-
2550
- const matchHtmlEntity = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g;
2551
- const htmlEntities = {
2552
- '&amp;': '&',
2553
- '&#38;': '&',
2554
- '&lt;': '<',
2555
- '&#60;': '<',
2556
- '&gt;': '>',
2557
- '&#62;': '>',
2558
- '&apos;': "'",
2559
- '&#39;': "'",
2560
- '&quot;': '"',
2561
- '&#34;': '"',
2562
- '&nbsp;': ' ',
2563
- '&#160;': ' ',
2564
- '&copy;': '©',
2565
- '&#169;': '©',
2566
- '&reg;': '®',
2567
- '&#174;': '®',
2568
- '&hellip;': '…',
2569
- '&#8230;': '…',
2570
- '&#x2F;': '/',
2571
- '&#47;': '/'
2572
- };
2573
- const unescapeHtmlEntity = m => htmlEntities[m];
2574
- const unescape = text => text.replace(matchHtmlEntity, unescapeHtmlEntity);
2575
-
2576
- let defaultOptions$1 = {
2577
- bindI18n: 'languageChanged',
2578
- bindI18nStore: '',
2579
- transEmptyNodeValue: '',
2580
- transSupportBasicHtmlNodes: true,
2581
- transWrapTextNodes: '',
2582
- transKeepBasicHtmlNodesFor: ['br', 'strong', 'i', 'p'],
2583
- useSuspense: true,
2584
- unescape
2585
- };
2586
- function setDefaults() {
2587
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2588
- defaultOptions$1 = {
2589
- ...defaultOptions$1,
2590
- ...options
2591
- };
2592
- }
2593
- function getDefaults() {
2594
- return defaultOptions$1;
2595
- }
2596
-
2597
- let i18nInstance;
2598
- function setI18n(instance) {
2599
- i18nInstance = instance;
2600
- }
2601
- function getI18n() {
2602
- return i18nInstance;
2603
- }
2604
-
2605
- const initReactI18next = {
2606
- type: '3rdParty',
2607
- init(instance) {
2608
- setDefaults(instance.options.react);
2609
- setI18n(instance);
2610
- }
2611
- };
2612
-
2613
- const I18nContext = React.createContext();
2614
- class ReportNamespaces {
2615
- constructor() {
2616
- this.usedNamespaces = {};
2814
+ if (!this.languages || !this.languages.length) {
2815
+ this.logger.warn('hasLoadedNamespace: i18n.languages were undefined or empty', this.languages);
2816
+ return false;
2817
+ }
2818
+ const lng = options.lng || this.resolvedLanguage || this.languages[0];
2819
+ const fallbackLng = this.options ? this.options.fallbackLng : false;
2820
+ const lastLng = this.languages[this.languages.length - 1];
2821
+ if (lng.toLowerCase() === 'cimode') return true;
2822
+ const loadNotPending = (l, n) => {
2823
+ const loadState = this.services.backendConnector.state[`${l}|${n}`];
2824
+ return loadState === -1 || loadState === 0 || loadState === 2;
2825
+ };
2826
+ if (options.precheck) {
2827
+ const preResult = options.precheck(this, loadNotPending);
2828
+ if (preResult !== undefined) return preResult;
2829
+ }
2830
+ if (this.hasResourceBundle(lng, ns)) return true;
2831
+ if (!this.services.backendConnector.backend || this.options.resources && !this.options.partialBundledLanguages) return true;
2832
+ if (loadNotPending(lng, ns) && (!fallbackLng || loadNotPending(lastLng, ns))) return true;
2833
+ return false;
2617
2834
  }
2618
- addUsedNamespaces(namespaces) {
2619
- namespaces.forEach(ns => {
2620
- if (!this.usedNamespaces[ns]) this.usedNamespaces[ns] = true;
2835
+ loadNamespaces(ns, callback) {
2836
+ const deferred = defer();
2837
+ if (!this.options.ns) {
2838
+ if (callback) callback();
2839
+ return Promise.resolve();
2840
+ }
2841
+ if (isString(ns)) ns = [ns];
2842
+ ns.forEach(n => {
2843
+ if (this.options.ns.indexOf(n) < 0) this.options.ns.push(n);
2621
2844
  });
2845
+ this.loadResources(err => {
2846
+ deferred.resolve();
2847
+ if (callback) callback(err);
2848
+ });
2849
+ return deferred;
2622
2850
  }
2623
- getUsedNamespaces() {
2624
- return Object.keys(this.usedNamespaces);
2851
+ loadLanguages(lngs, callback) {
2852
+ const deferred = defer();
2853
+ if (isString(lngs)) lngs = [lngs];
2854
+ const preloaded = this.options.preload || [];
2855
+ const newLngs = lngs.filter(lng => preloaded.indexOf(lng) < 0 && this.services.languageUtils.isSupportedCode(lng));
2856
+ if (!newLngs.length) {
2857
+ if (callback) callback();
2858
+ return Promise.resolve();
2859
+ }
2860
+ this.options.preload = preloaded.concat(newLngs);
2861
+ this.loadResources(err => {
2862
+ deferred.resolve();
2863
+ if (callback) callback(err);
2864
+ });
2865
+ return deferred;
2625
2866
  }
2626
- }
2627
-
2628
- const usePrevious = (value, ignore) => {
2629
- const ref = React.useRef();
2630
- React.useEffect(() => {
2631
- ref.current = ignore ? ref.current : value;
2632
- }, [value, ignore]);
2633
- return ref.current;
2634
- };
2635
- function useTranslation(ns) {
2636
- let props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2637
- const {
2638
- i18n: i18nFromProps
2639
- } = props;
2640
- const {
2641
- i18n: i18nFromContext,
2642
- defaultNS: defaultNSFromContext
2643
- } = React.useContext(I18nContext) || {};
2644
- const i18n = i18nFromProps || i18nFromContext || getI18n();
2645
- if (i18n && !i18n.reportNamespaces) i18n.reportNamespaces = new ReportNamespaces();
2646
- if (!i18n) {
2647
- warnOnce('You will need to pass in an i18next instance by using initReactI18next');
2648
- const notReadyT = (k, optsOrDefaultValue) => {
2649
- if (typeof optsOrDefaultValue === 'string') return optsOrDefaultValue;
2650
- if (optsOrDefaultValue && typeof optsOrDefaultValue === 'object' && typeof optsOrDefaultValue.defaultValue === 'string') return optsOrDefaultValue.defaultValue;
2651
- return Array.isArray(k) ? k[k.length - 1] : k;
2652
- };
2653
- const retNotReady = [notReadyT, {}, false];
2654
- retNotReady.t = notReadyT;
2655
- retNotReady.i18n = {};
2656
- retNotReady.ready = false;
2657
- return retNotReady;
2867
+ dir(lng) {
2868
+ if (!lng) lng = this.resolvedLanguage || (this.languages && this.languages.length > 0 ? this.languages[0] : this.language);
2869
+ if (!lng) return 'rtl';
2870
+ const rtlLngs = ['ar', 'shu', 'sqr', 'ssh', 'xaa', 'yhd', 'yud', 'aao', 'abh', 'abv', 'acm', 'acq', 'acw', 'acx', 'acy', 'adf', 'ads', 'aeb', 'aec', 'afb', 'ajp', 'apc', 'apd', 'arb', 'arq', 'ars', 'ary', 'arz', 'auz', 'avl', 'ayh', 'ayl', 'ayn', 'ayp', 'bbz', 'pga', 'he', 'iw', 'ps', 'pbt', 'pbu', 'pst', 'prp', 'prd', 'ug', 'ur', 'ydd', 'yds', 'yih', 'ji', 'yi', 'hbo', 'men', 'xmn', 'fa', 'jpr', 'peo', 'pes', 'prs', 'dv', 'sam', 'ckb'];
2871
+ const languageUtils = this.services && this.services.languageUtils || new LanguageUtil(get());
2872
+ return rtlLngs.indexOf(languageUtils.getLanguagePartFromCode(lng)) > -1 || lng.toLowerCase().indexOf('-arab') > 1 ? 'rtl' : 'ltr';
2658
2873
  }
2659
- if (i18n.options.react && i18n.options.react.wait !== undefined) warnOnce('It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.');
2660
- const i18nOptions = {
2661
- ...getDefaults(),
2662
- ...i18n.options.react,
2663
- ...props
2664
- };
2665
- const {
2666
- useSuspense,
2667
- keyPrefix
2668
- } = i18nOptions;
2669
- let namespaces = ns || defaultNSFromContext || i18n.options && i18n.options.defaultNS;
2670
- namespaces = typeof namespaces === 'string' ? [namespaces] : namespaces || ['translation'];
2671
- if (i18n.reportNamespaces.addUsedNamespaces) i18n.reportNamespaces.addUsedNamespaces(namespaces);
2672
- const ready = (i18n.isInitialized || i18n.initializedStoreOnce) && namespaces.every(n => hasLoadedNamespace(n, i18n, i18nOptions));
2673
- function getT() {
2674
- return i18n.getFixedT(props.lng || null, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix);
2874
+ static createInstance() {
2875
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2876
+ let callback = arguments.length > 1 ? arguments[1] : undefined;
2877
+ return new I18n(options, callback);
2675
2878
  }
2676
- const [t, setT] = React.useState(getT);
2677
- let joinedNS = namespaces.join();
2678
- if (props.lng) joinedNS = `${props.lng}${joinedNS}`;
2679
- const previousJoinedNS = usePrevious(joinedNS);
2680
- const isMounted = React.useRef(true);
2681
- React.useEffect(() => {
2682
- const {
2683
- bindI18n,
2684
- bindI18nStore
2685
- } = i18nOptions;
2686
- isMounted.current = true;
2687
- if (!ready && !useSuspense) {
2688
- if (props.lng) {
2689
- loadLanguages(i18n, props.lng, namespaces, () => {
2690
- if (isMounted.current) setT(getT);
2691
- });
2692
- } else {
2693
- loadNamespaces(i18n, namespaces, () => {
2694
- if (isMounted.current) setT(getT);
2695
- });
2879
+ cloneInstance() {
2880
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2881
+ let callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop;
2882
+ const forkResourceStore = options.forkResourceStore;
2883
+ if (forkResourceStore) delete options.forkResourceStore;
2884
+ const mergedOptions = {
2885
+ ...this.options,
2886
+ ...options,
2887
+ ...{
2888
+ isClone: true
2696
2889
  }
2697
- }
2698
- if (ready && previousJoinedNS && previousJoinedNS !== joinedNS && isMounted.current) {
2699
- setT(getT);
2700
- }
2701
- function boundReset() {
2702
- if (isMounted.current) setT(getT);
2703
- }
2704
- if (bindI18n && i18n) i18n.on(bindI18n, boundReset);
2705
- if (bindI18nStore && i18n) i18n.store.on(bindI18nStore, boundReset);
2706
- return () => {
2707
- isMounted.current = false;
2708
- if (bindI18n && i18n) bindI18n.split(' ').forEach(e => i18n.off(e, boundReset));
2709
- if (bindI18nStore && i18n) bindI18nStore.split(' ').forEach(e => i18n.store.off(e, boundReset));
2710
2890
  };
2711
- }, [i18n, joinedNS]);
2712
- const isInitial = React.useRef(true);
2713
- React.useEffect(() => {
2714
- if (isMounted.current && !isInitial.current) {
2715
- setT(getT);
2891
+ const clone = new I18n(mergedOptions);
2892
+ if (options.debug !== undefined || options.prefix !== undefined) {
2893
+ clone.logger = clone.logger.clone(options);
2716
2894
  }
2717
- isInitial.current = false;
2718
- }, [i18n, keyPrefix]);
2719
- const ret = [t, i18n, ready];
2720
- ret.t = t;
2721
- ret.i18n = i18n;
2722
- ret.ready = ready;
2723
- if (ready) return ret;
2724
- if (!ready && !useSuspense) return ret;
2725
- throw new Promise(resolve => {
2726
- if (props.lng) {
2727
- loadLanguages(i18n, props.lng, namespaces, () => resolve());
2728
- } else {
2729
- loadNamespaces(i18n, namespaces, () => resolve());
2895
+ const membersToCopy = ['store', 'services', 'language'];
2896
+ membersToCopy.forEach(m => {
2897
+ clone[m] = this[m];
2898
+ });
2899
+ clone.services = {
2900
+ ...this.services
2901
+ };
2902
+ clone.services.utils = {
2903
+ hasLoadedNamespace: clone.hasLoadedNamespace.bind(clone)
2904
+ };
2905
+ if (forkResourceStore) {
2906
+ clone.store = new ResourceStore(this.store.data, mergedOptions);
2907
+ clone.services.resourceStore = clone.store;
2730
2908
  }
2731
- });
2909
+ clone.translator = new Translator(clone.services, mergedOptions);
2910
+ clone.translator.on('*', function (event) {
2911
+ for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
2912
+ args[_key4 - 1] = arguments[_key4];
2913
+ }
2914
+ clone.emit(event, ...args);
2915
+ });
2916
+ clone.init(mergedOptions, callback);
2917
+ clone.translator.options = mergedOptions;
2918
+ clone.translator.backendConnector.services.utils = {
2919
+ hasLoadedNamespace: clone.hasLoadedNamespace.bind(clone)
2920
+ };
2921
+ return clone;
2922
+ }
2923
+ toJSON() {
2924
+ return {
2925
+ options: this.options,
2926
+ store: this.store,
2927
+ language: this.language,
2928
+ languages: this.languages,
2929
+ resolvedLanguage: this.resolvedLanguage
2930
+ };
2931
+ }
2732
2932
  }
2933
+ const instance = I18n.createInstance();
2934
+ instance.createInstance = I18n.createInstance;
2935
+
2936
+ instance.createInstance;
2937
+ instance.dir;
2938
+ instance.init;
2939
+ instance.loadResources;
2940
+ instance.reloadResources;
2941
+ instance.use;
2942
+ instance.changeLanguage;
2943
+ instance.getFixedT;
2944
+ instance.t;
2945
+ instance.exists;
2946
+ instance.setDefaultNamespace;
2947
+ instance.hasLoadedNamespace;
2948
+ instance.loadNamespaces;
2949
+ instance.loadLanguages;
2733
2950
 
2734
2951
  var locations$1 = {
2735
2952
  label: "Location",
@@ -2871,70 +3088,30 @@ var fiCommon = {
2871
3088
  errors: errors
2872
3089
  };
2873
3090
 
2874
- var urlParams = typeof window !== 'undefined'
2875
- ? new URLSearchParams(window.location.search)
2876
- : null;
2877
- var localeFromUrl = (urlParams === null || urlParams === void 0 ? void 0 : urlParams.get('locale')) || 'fi';
2878
- instance.use(initReactI18next).init({
2879
- resources: {
2880
- en: { filterBar: enFilterBar, common: enCommon },
2881
- fi: { filterBar: fiFilterBar, common: fiCommon },
2882
- },
2883
- lng: localeFromUrl,
2884
- fallbackLng: 'fi',
2885
- interpolation: {
2886
- escapeValue: false,
2887
- },
2888
- });
2889
-
2890
- var useUpdateTranslations = function (_a) {
2891
- var language = _a.language;
2892
- var _b = __read(React.useState(0), 2); _b[0]; var setRerenderKey = _b[1];
2893
- React.useEffect(function () {
2894
- instance.changeLanguage(language);
2895
- setRerenderKey(function (prevKey) { return prevKey + 1; });
2896
- }, [language]);
3091
+ var resources = {
3092
+ en: { filterBar: enFilterBar, common: enCommon },
3093
+ fi: { filterBar: fiFilterBar, common: fiCommon },
2897
3094
  };
2898
-
2899
- // TODO - Refactor and rename this hook
2900
- var useCloseFilterSection = function (_a) {
2901
- var handleSelectedFilter = _a.handleSelectedFilter;
2902
- var filterSectionRef = React.useRef(null);
2903
- React.useEffect(function () {
2904
- var handleClickOutside = function (event) {
2905
- if (filterSectionRef.current &&
2906
- !filterSectionRef.current.contains(event.target)) {
2907
- handleSelectedFilter(false);
2908
- }
2909
- };
2910
- document.addEventListener('mousedown', handleClickOutside);
2911
- return function () {
2912
- document.removeEventListener('mousedown', handleClickOutside);
2913
- };
2914
- }, [filterSectionRef]);
2915
- return { filterSectionRef: filterSectionRef };
3095
+ var readLocaleFromUrl = function () {
3096
+ if (typeof window === 'undefined')
3097
+ return null;
3098
+ return new URLSearchParams(window.location.search).get('locale');
3099
+ };
3100
+ var createI18nInstance = function (language) {
3101
+ var instance$1 = instance.createInstance();
3102
+ instance$1.use(initReactI18next).init({
3103
+ resources: resources,
3104
+ lng: language || readLocaleFromUrl() || 'fi',
3105
+ fallbackLng: 'fi',
3106
+ interpolation: { escapeValue: false },
3107
+ });
3108
+ return instance$1;
2916
3109
  };
2917
3110
 
2918
- var useAutoFocus = function (autoFocus) {
2919
- var ref = React.useRef(null);
2920
- React.useEffect(function () {
2921
- if (!autoFocus || !ref.current)
2922
- return;
2923
- var attemptFocus = function (attempts) {
2924
- if (attempts === void 0) { attempts = 0; }
2925
- if (attempts > 20 || !ref.current)
2926
- return;
2927
- var focusable = ref.current.querySelector('button:not([disabled]), [tabindex]:not([tabindex="-1"])');
2928
- if (focusable) {
2929
- focusable.focus();
2930
- }
2931
- else {
2932
- requestAnimationFrame(function () { return attemptFocus(attempts + 1); });
2933
- }
2934
- };
2935
- requestAnimationFrame(function () { return attemptFocus(); });
2936
- }, [autoFocus]);
2937
- return ref;
3111
+ var I18nProvider = function (_a) {
3112
+ var language = _a.language, children = _a.children;
3113
+ var i18n = React.useMemo(function () { return createI18nInstance(language); }, []);
3114
+ return React.createElement(I18nextProvider, { i18n: i18n }, children);
2938
3115
  };
2939
3116
 
2940
3117
  var css_248z$j = ".will-filter-bar-select-button {\n width: 100%;\n height: auto;\n background-color: transparent;\n border: none;\n padding: 0 20px;\n border-radius: 20px;\n cursor: pointer;\n font-size: 14px;\n text-align: initial;\n user-select: none;\n}\n\n.will-filter-bar-select-button.disabled {\n cursor: not-allowed;\n}\n\n.will-filter-bar-select-button .select-button-wrapper {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 10px;\n}\n\n.will-filter-bar-select-button .select-button-wrapper > div {\n display: grid;\n}\n\n.will-filter-bar-select-button .select-button-label {\n color: var(--will-black);\n font-weight: 600;\n}\n\n.will-filter-bar-select-button .select-button-description {\n color: var(--will-black);\n font-weight: 400;\n opacity: 0.5;\n white-space: nowrap;\n min-height: 19px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.will-filter-bar-select-button .select-button-description span {\n font: inherit;\n}\n\n.will-filter-bar-select-button .select-button-label.active,\n.will-filter-bar-select-button .select-button-description.active {\n font-weight: 700;\n font-size: 15px;\n opacity: 1;\n}\n\n@media (max-width: 960px) {\n .will-filter-bar-select-button {\n padding: 15px 0;\n }\n\n .will-filter-bar-select-button:first-child {\n padding: 0 0 15px 0;\n }\n\n .will-filter-bar-select-button .select-button-wrapper {\n justify-content: center;\n text-align: center;\n }\n\n .will-filter-bar-select-button .select-button-description {\n white-space: wrap;\n }\n\n .will-filter-bar-select-button .select-button-divider {\n display: none;\n }\n}\n";
@@ -12231,7 +12408,7 @@ var FilterControls = function () {
12231
12408
  tabsRef.current = el;
12232
12409
  }
12233
12410
  } },
12234
- ((_a = locations === null || locations === void 0 ? void 0 : locations.data) === null || _a === void 0 ? void 0 : _a.length) && locations.data.length > 1 && (React.createElement(React.Fragment, null,
12411
+ !!((_a = locations === null || locations === void 0 ? void 0 : locations.data) === null || _a === void 0 ? void 0 : _a.length) && locations.data.length > 1 && (React.createElement(React.Fragment, null,
12235
12412
  React.createElement(SelectButton, { ref: function (el) { return (buttonRefs.current[FilterSections.LOCATIONS] = el); }, label: t('locations.label'), description: parsedLocations, onClick: function (e) {
12236
12413
  previouslyFocusedButtonRef.current = e.currentTarget;
12237
12414
  handleSelectedFilter(FilterSections.LOCATIONS);
@@ -12277,12 +12454,12 @@ styleInject(css_248z$2);
12277
12454
  var css_248z$1 = ".will-root {\n z-index: 999;\n width: fit-content;\n min-width: 796px;\n max-height: 100vh;\n position: relative;\n}\n\n.will-root.is-full-width {\n width: 100%;\n}\n\n.will-filter-bar {\n box-sizing: border-box;\n position: relative;\n}\n\n@media (max-width: 960px) {\n .will-root {\n width: 100%;\n min-width: auto;\n }\n}\n\n/* Common */\n\n.will-filter-bar-controls.dark,\n.will-filter-bar-panels.dark {\n box-shadow: var(--will-box-shadow-dark);\n}\n\n.will-filter-bar-controls.light,\n.will-filter-bar-panels.light {\n box-shadow: var(--will-box-shadow-light);\n}\n";
12278
12455
  styleInject(css_248z$1);
12279
12456
 
12280
- var FilterBar = function (_a) {
12457
+ var FilterBar = function (props) { return (React.createElement(I18nProvider, { language: props.language },
12458
+ React.createElement(FilterBarInner, __assign$2({}, props)))); };
12459
+ var FilterBarInner = function (_a) {
12281
12460
  var language = _a.language, ageCategories = _a.ageCategories, _b = _a.redirectUrl, redirectUrl = _b === void 0 ? REDIRECT_URL_FALLBACK : _b, palette = _a.palette, onSubmit = _a.onSubmit, fullWidth = _a.fullWidth, disableCalendarDates = _a.disableCalendarDates, mode = _a.mode, tabs = _a.tabs, outerLoading = _a.outerLoading, locations = _a.locations;
12282
12461
  var themePalette = useTheme({ palette: palette });
12283
- // Translations
12284
12462
  useUpdateTranslations({ language: language });
12285
- // Display component after fully loaded
12286
12463
  useAwaitRender();
12287
12464
  return (React.createElement(FilterBarProvider, { language: language, ageCategories: ageCategories, redirectUrl: redirectUrl, palette: palette, onSubmit: onSubmit, fullWidth: fullWidth, disableCalendarDates: disableCalendarDates, mode: mode, tabs: tabs, outerLoading: outerLoading, locations: locations },
12288
12465
  React.createElement("div", { className: "will-root ".concat(fullWidth ? 'is-full-width' : ''), style: themePalette },
@@ -12449,7 +12626,11 @@ var renderCalendarErrorMessage = function (_a) {
12449
12626
  var css_248z = ".will-root .will-calendar-wrapper {\n box-shadow: var(--will-box-shadow-dark);\n border-radius: 20px;\n background-color: var(--will-white);\n position: absolute;\n top: 0;\n left: 0;\n \n}\n\n.will-root .will-calendar-wrapper .will-calendar-header,\n.will-root .will-calendar-wrapper .will-calendar-main,\n.will-root .will-calendar-wrapper .will-calendar-footer {\n padding: 20px;\n}\n\n/* Header */\n\n.will-root .will-calendar-wrapper .will-calendar-header {\n display: flex;\n justify-content: space-between;\n border-bottom: 1px solid var(--will-grey);\n align-items: center;\n}\n\n/* Footer */\n\n.will-root .will-calendar-wrapper .will-calendar-footer {\n border-top: 1px solid var(--will-grey);\n}\n\n/* Footer actions */\n\n.will-root .will-calendar-wrapper .will-calendar-footer-actions-wrapper {\n display: flex;\n justify-content: space-between;\n}\n\n.will-root .will-calendar-wrapper .will-calendar-footer-dates > div {\n margin-bottom: 5px;\n}\n\n.will-root .will-calendar-wrapper .will-calendar-footer-dates-separator {\n margin: 0 15px;\n}\n\n.will-root .will-calendar-wrapper .will-calendar-footer-dates .will-calendar-footer-booked {\n display: flex;\n min-height: 20.5px;\n margin-top: 10px;\n}\n\n.will-root .will-calendar-wrapper .will-calendar-footer-error {\n display: flex;\n max-width: 80%;\n}\n\n.will-root .will-calendar-wrapper .will-calendar-footer-error span {\n display: inline-block;\n margin-left: 10px;\n}\n\n@media (max-width: 960px) {\n .will-root .will-calendar-wrapper {\n width: -webkit-fill-available;\n margin: 0 -6%;\n }\n\n .will-root .will-calendar-wrapper .will-calendar-header,\n .will-root .will-calendar-wrapper .will-calendar-main,\n .will-root .will-calendar-wrapper .will-calendar-footer {\n padding: 20px 10px;\n }\n\n .will-root .will-calendar-wrapper .will-calendar-footer-actions-wrapper {\n flex-direction: column;\n }\n\n .will-root .will-calendar-wrapper .will-calendar-footer-dates {\n text-align: center;\n }\n\n .will-root .will-calendar-wrapper .will-calendar-footer-dates .will-calendar-footer-booked {\n justify-content: center;\n }\n\n .will-root .will-calendar-wrapper .will-calendar-footer-actions {\n flex-direction: column;\n width: 100%;\n }\n\n .will-root .will-calendar-wrapper .will-calendar-footer-actions button{\n width: 100%;\n margin-top: 10px;\n }\n\n .will-root .will-calendar-wrapper .will-calendar-footer-error {\n max-width: 100%;\n }\n\n .will-root .will-calendar-wrapper .will-calendar-footer-error span {\n text-align: center;\n margin-left: 5px;\n }\n }\n\n.will-root .will-calendar-wrapper .will-calendar-header .will-filter-bar-close-button {\n position: initial;\n}";
12450
12627
  styleInject(css_248z);
12451
12628
 
12452
- function FilterCalendar(_a) {
12629
+ function FilterCalendar(props) {
12630
+ return (React.createElement(I18nProvider, { language: props.language },
12631
+ React.createElement(FilterCalendarInner, __assign$2({}, props))));
12632
+ }
12633
+ function FilterCalendarInner(_a) {
12453
12634
  var calendarOffset = _a.calendarOffset, language = _a.language, palette = _a.palette, onSubmit = _a.onSubmit, outerDisableCalendarDates = _a.disableCalendarDates, toggleCalendar = _a.toggleCalendar, loadingData = _a.loadingData, setToggleCalendar = _a.setToggleCalendar, requestDates = _a.requestDates, showFeedback = _a.showFeedback, noActiveSelection = _a.noActiveSelection, outerRangeContext = _a.rangeContext;
12454
12635
  var themePalette = useTheme({ palette: palette });
12455
12636
  // Translations