locizify 9.0.8 → 9.0.10

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.
@@ -175,7 +175,7 @@
175
175
  };
176
176
  var makeString = object => {
177
177
  if (object == null) return '';
178
- return '' + object;
178
+ return String(object);
179
179
  };
180
180
  var copy = (a, s, t) => {
181
181
  a.forEach(m => {
@@ -183,7 +183,7 @@
183
183
  });
184
184
  };
185
185
  var lastOfPathSeparatorRegExp = /###/g;
186
- var cleanKey = key => key && key.indexOf('###') > -1 ? key.replace(lastOfPathSeparatorRegExp, '.') : key;
186
+ var cleanKey = key => key && key.includes('###') ? key.replace(lastOfPathSeparatorRegExp, '.') : key;
187
187
  var canNotTraverseDeeper = object => !object || isString(object);
188
188
  var getLastOfPath = (object, path, Empty) => {
189
189
  var stack = !isString(path) ? path : path.split('.');
@@ -308,7 +308,7 @@
308
308
  var looksLikeObjectPath = (key, nsSeparator, keySeparator) => {
309
309
  nsSeparator = nsSeparator || '';
310
310
  keySeparator = keySeparator || '';
311
- var possibleChars = chars.filter(c => nsSeparator.indexOf(c) < 0 && keySeparator.indexOf(c) < 0);
311
+ var possibleChars = chars.filter(c => !nsSeparator.includes(c) && !keySeparator.includes(c));
312
312
  if (possibleChars.length === 0) return true;
313
313
  var r = looksLikeObjectPathRegExpCache.getRegExp("(".concat(possibleChars.map(c => c === '?' ? '\\?' : c).join('|'), ")"));
314
314
  var matched = !r.test(key);
@@ -342,7 +342,7 @@
342
342
  nextPath += tokens[j];
343
343
  next = current[nextPath];
344
344
  if (next !== undefined) {
345
- if (['string', 'number', 'boolean'].indexOf(typeof next) > -1 && j < tokens.length - 1) {
345
+ if (['string', 'number', 'boolean'].includes(typeof next) && j < tokens.length - 1) {
346
346
  continue;
347
347
  }
348
348
  i += j - i + 1;
@@ -353,7 +353,7 @@
353
353
  }
354
354
  return current;
355
355
  };
356
- var getCleanedCode = code => code === null || code === void 0 ? void 0 : code.replace('_', '-');
356
+ var getCleanedCode = code => code === null || code === void 0 ? void 0 : code.replace(/_/g, '-');
357
357
  var consoleLogger = {
358
358
  type: 'logger',
359
359
  log(args) {
@@ -408,6 +408,7 @@
408
408
  }
409
409
  forward(args, lvl, prefix, debugOnly) {
410
410
  if (debugOnly && !this.debug) return null;
411
+ args = args.map(a => isString(a) ? a.replace(/[\r\n\x00-\x1F\x7F]/g, ' ') : a);
411
412
  if (isString(args[0])) args[0] = "".concat(prefix).concat(this.prefix, " ").concat(args[0]);
412
413
  return this.logger[lvl](args);
413
414
  }
@@ -443,6 +444,15 @@
443
444
  }
444
445
  this.observers[event].delete(listener);
445
446
  }
447
+ once(event, listener) {
448
+ var _this = this;
449
+ var _wrapper = function wrapper() {
450
+ listener(...arguments);
451
+ _this.off(event, _wrapper);
452
+ };
453
+ this.on(event, _wrapper);
454
+ return this;
455
+ }
446
456
  emit(event) {
447
457
  for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
448
458
  args[_key5 - 1] = arguments[_key5];
@@ -461,7 +471,7 @@
461
471
  _cloned.forEach(_ref2 => {
462
472
  var [observer, numTimesAdded] = _ref2;
463
473
  for (var i = 0; i < numTimesAdded; i++) {
464
- observer.apply(observer, [event, ...args]);
474
+ observer(event, ...args);
465
475
  }
466
476
  });
467
477
  }
@@ -484,7 +494,7 @@
484
494
  }
485
495
  }
486
496
  addNamespaces(ns) {
487
- if (this.options.ns.indexOf(ns) < 0) {
497
+ if (!this.options.ns.includes(ns)) {
488
498
  this.options.ns.push(ns);
489
499
  }
490
500
  }
@@ -500,7 +510,7 @@
500
510
  var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
501
511
  var ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure;
502
512
  var path;
503
- if (lng.indexOf('.') > -1) {
513
+ if (lng.includes('.')) {
504
514
  path = lng.split('.');
505
515
  } else {
506
516
  path = [lng, ns];
@@ -515,7 +525,7 @@
515
525
  }
516
526
  }
517
527
  var result = getPath(this.data, path);
518
- if (!result && !ns && !key && lng.indexOf('.') > -1) {
528
+ if (!result && !ns && !key && lng.includes('.')) {
519
529
  lng = path[0];
520
530
  ns = path[1];
521
531
  key = path.slice(2).join('.');
@@ -530,7 +540,7 @@
530
540
  var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
531
541
  var path = [lng, ns];
532
542
  if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key);
533
- if (lng.indexOf('.') > -1) {
543
+ if (lng.includes('.')) {
534
544
  path = lng.split('.');
535
545
  value = ns;
536
546
  ns = path[1];
@@ -556,7 +566,7 @@
556
566
  skipCopy: false
557
567
  };
558
568
  var path = [lng, ns];
559
- if (lng.indexOf('.') > -1) {
569
+ if (lng.includes('.')) {
560
570
  path = lng.split('.');
561
571
  deep = resources;
562
572
  resources = ns;
@@ -628,13 +638,21 @@
628
638
  return Proxy.revocable(Object.create(null), handler).proxy;
629
639
  }
630
640
  function keysFromSelector(selector, opts) {
631
- var _opts$keySeparator;
641
+ var _opts$keySeparator, _opts$nsSeparator;
632
642
  var {
633
643
  [PATH_KEY]: path
634
644
  } = selector(createProxy());
635
- return path.join((_opts$keySeparator = opts === null || opts === void 0 ? void 0 : opts.keySeparator) !== null && _opts$keySeparator !== void 0 ? _opts$keySeparator : '.');
645
+ var keySeparator = (_opts$keySeparator = opts === null || opts === void 0 ? void 0 : opts.keySeparator) !== null && _opts$keySeparator !== void 0 ? _opts$keySeparator : '.';
646
+ var nsSeparator = (_opts$nsSeparator = opts === null || opts === void 0 ? void 0 : opts.nsSeparator) !== null && _opts$nsSeparator !== void 0 ? _opts$nsSeparator : ':';
647
+ if (path.length > 1 && nsSeparator) {
648
+ var ns = opts === null || opts === void 0 ? void 0 : opts.ns;
649
+ var nsArray = Array.isArray(ns) ? ns : null;
650
+ if (nsArray && nsArray.length > 1 && nsArray.slice(1).includes(path[0])) {
651
+ return "".concat(path[0]).concat(nsSeparator).concat(path.slice(1).join(keySeparator));
652
+ }
653
+ }
654
+ return path.join(keySeparator);
636
655
  }
637
- var checkedLoadedFor = {};
638
656
  var shouldHandleAsObject = res => !isString(res) && typeof res !== 'boolean' && typeof res !== 'number';
639
657
  class Translator extends EventEmitter {
640
658
  constructor(services) {
@@ -646,6 +664,7 @@
646
664
  this.options.keySeparator = '.';
647
665
  }
648
666
  this.logger = baseLogger.create('translator');
667
+ this.checkedLoadedFor = {};
649
668
  }
650
669
  changeLanguage(lng) {
651
670
  if (lng) this.language = lng;
@@ -669,7 +688,7 @@
669
688
  if (nsSeparator === undefined) nsSeparator = ':';
670
689
  var keySeparator = opt.keySeparator !== undefined ? opt.keySeparator : this.options.keySeparator;
671
690
  var namespaces = opt.ns || this.options.defaultNS || [];
672
- var wouldCheckForNsInKey = nsSeparator && key.indexOf(nsSeparator) > -1;
691
+ var wouldCheckForNsInKey = nsSeparator && key.includes(nsSeparator);
673
692
  var seemsNaturalLanguage = !this.options.userDefinedKeySeparator && !opt.keySeparator && !this.options.userDefinedNsSeparator && !opt.nsSeparator && !looksLikeObjectPath(key, nsSeparator, keySeparator);
674
693
  if (wouldCheckForNsInKey && !seemsNaturalLanguage) {
675
694
  var m = key.match(this.interpolator.nestingRegexp);
@@ -680,7 +699,7 @@
680
699
  };
681
700
  }
682
701
  var parts = key.split(nsSeparator);
683
- if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.indexOf(parts[0]) > -1) namespaces = parts.shift();
702
+ if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.includes(parts[0])) namespaces = parts.shift();
684
703
  key = parts.join(keySeparator);
685
704
  }
686
705
  return {
@@ -698,6 +717,7 @@
698
717
  if (keys == null) return '';
699
718
  if (typeof keys === 'function') keys = keysFromSelector(keys, _objectSpread2(_objectSpread2({}, this.options), opt));
700
719
  if (!Array.isArray(keys)) keys = [String(keys)];
720
+ keys = keys.map(k => typeof k === 'function' ? keysFromSelector(k, _objectSpread2(_objectSpread2({}, this.options), opt)) : String(k));
701
721
  var returnDetails = opt.returnDetails !== undefined ? opt.returnDetails : this.options.returnDetails;
702
722
  var keySeparator = opt.keySeparator !== undefined ? opt.keySeparator : this.options.keySeparator;
703
723
  var {
@@ -756,7 +776,7 @@
756
776
  }
757
777
  var handleAsObject = shouldHandleAsObject(resForObjHndl);
758
778
  var resType = Object.prototype.toString.apply(resForObjHndl);
759
- if (handleAsObjectInI18nFormat && resForObjHndl && handleAsObject && noObject.indexOf(resType) < 0 && !(isString(joinArrays) && Array.isArray(resForObjHndl))) {
779
+ if (handleAsObjectInI18nFormat && resForObjHndl && handleAsObject && !noObject.includes(resType) && !(isString(joinArrays) && Array.isArray(resForObjHndl))) {
760
780
  if (!opt.returnObjects && !this.options.returnObjects) {
761
781
  if (!this.options.returnedObjectHandler) {
762
782
  this.logger.warn('accessing an object - but returnObjects options is not enabled!');
@@ -846,7 +866,7 @@
846
866
  if (this.options.saveMissingPlurals && needsPluralHandling) {
847
867
  lngs.forEach(language => {
848
868
  var suffixes = this.pluralResolver.getSuffixes(language, opt);
849
- if (needsZeroSuffixLookup && opt["defaultValue".concat(this.options.pluralSeparator, "zero")] && suffixes.indexOf("".concat(this.options.pluralSeparator, "zero")) < 0) {
869
+ if (needsZeroSuffixLookup && opt["defaultValue".concat(this.options.pluralSeparator, "zero")] && !suffixes.includes("".concat(this.options.pluralSeparator, "zero"))) {
850
870
  suffixes.push("".concat(this.options.pluralSeparator, "zero"));
851
871
  }
852
872
  suffixes.forEach(suffix => {
@@ -875,7 +895,7 @@
875
895
  }
876
896
  extendTranslation(res, key, opt, resolved, lastKey) {
877
897
  var _this$i18nFormat,
878
- _this = this;
898
+ _this2 = this;
879
899
  if ((_this$i18nFormat = this.i18nFormat) !== null && _this$i18nFormat !== void 0 && _this$i18nFormat.parse) {
880
900
  res = this.i18nFormat.parse(res, _objectSpread2(_objectSpread2({}, this.options.interpolation.defaultVariables), opt), opt.lng || this.language || resolved.usedLng, resolved.usedNS, resolved.usedKey, {
881
901
  resolved
@@ -905,10 +925,10 @@
905
925
  args[_key6] = arguments[_key6];
906
926
  }
907
927
  if ((lastKey === null || lastKey === void 0 ? void 0 : lastKey[0]) === args[0] && !opt.context) {
908
- _this.logger.warn("It seems you are nesting recursively key: ".concat(args[0], " in key: ").concat(key[0]));
928
+ _this2.logger.warn("It seems you are nesting recursively key: ".concat(args[0], " in key: ").concat(key[0]));
909
929
  return null;
910
930
  }
911
- return _this.translate(...args, key);
931
+ return _this2.translate(...args, key);
912
932
  }, opt);
913
933
  if (opt.interpolation) this.interpolator.reset();
914
934
  }
@@ -931,6 +951,7 @@
931
951
  var usedLng;
932
952
  var usedNS;
933
953
  if (isString(keys)) keys = [keys];
954
+ if (Array.isArray(keys)) keys = keys.map(k => typeof k === 'function' ? keysFromSelector(k, _objectSpread2(_objectSpread2({}, this.options), opt)) : k);
934
955
  keys.forEach(k => {
935
956
  if (this.isValidLookup(found)) return;
936
957
  var extracted = this.extractFromKey(k, opt);
@@ -946,8 +967,8 @@
946
967
  var _this$utils, _this$utils2;
947
968
  if (this.isValidLookup(found)) return;
948
969
  usedNS = ns;
949
- if (!checkedLoadedFor["".concat(codes[0], "-").concat(ns)] && (_this$utils = this.utils) !== null && _this$utils !== void 0 && _this$utils.hasLoadedNamespace && !((_this$utils2 = this.utils) !== null && _this$utils2 !== void 0 && _this$utils2.hasLoadedNamespace(usedNS))) {
950
- checkedLoadedFor["".concat(codes[0], "-").concat(ns)] = true;
970
+ if (!this.checkedLoadedFor["".concat(codes[0], "-").concat(ns)] && (_this$utils = this.utils) !== null && _this$utils !== void 0 && _this$utils.hasLoadedNamespace && !((_this$utils2 = this.utils) !== null && _this$utils2 !== void 0 && _this$utils2.hasLoadedNamespace(usedNS))) {
971
+ this.checkedLoadedFor["".concat(codes[0], "-").concat(ns)] = true;
951
972
  this.logger.warn("key \"".concat(usedKey, "\" for languages \"").concat(codes.join(', '), "\" won't get resolved as namespace \"").concat(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!!!');
952
973
  }
953
974
  codes.forEach(code => {
@@ -963,7 +984,7 @@
963
984
  var zeroSuffix = "".concat(this.options.pluralSeparator, "zero");
964
985
  var ordinalPrefix = "".concat(this.options.pluralSeparator, "ordinal").concat(this.options.pluralSeparator);
965
986
  if (needsPluralHandling) {
966
- if (opt.ordinal && pluralSuffix.indexOf(ordinalPrefix) === 0) {
987
+ if (opt.ordinal && pluralSuffix.startsWith(ordinalPrefix)) {
967
988
  finalKeys.push(key + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator));
968
989
  }
969
990
  finalKeys.push(key + pluralSuffix);
@@ -975,7 +996,7 @@
975
996
  var contextKey = "".concat(key).concat(this.options.contextSeparator || '_').concat(opt.context);
976
997
  finalKeys.push(contextKey);
977
998
  if (needsPluralHandling) {
978
- if (opt.ordinal && pluralSuffix.indexOf(ordinalPrefix) === 0) {
999
+ if (opt.ordinal && pluralSuffix.startsWith(ordinalPrefix)) {
979
1000
  finalKeys.push(contextKey + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator));
980
1001
  }
981
1002
  finalKeys.push(contextKey + pluralSuffix);
@@ -1034,7 +1055,7 @@
1034
1055
  static hasDefaultValue(options) {
1035
1056
  var prefix = 'defaultValue';
1036
1057
  for (var option in options) {
1037
- if (Object.prototype.hasOwnProperty.call(options, option) && prefix === option.substring(0, prefix.length) && undefined !== options[option]) {
1058
+ if (Object.prototype.hasOwnProperty.call(options, option) && option.startsWith(prefix) && undefined !== options[option]) {
1038
1059
  return true;
1039
1060
  }
1040
1061
  }
@@ -1049,7 +1070,7 @@
1049
1070
  }
1050
1071
  getScriptPartFromCode(code) {
1051
1072
  code = getCleanedCode(code);
1052
- if (!code || code.indexOf('-') < 0) return null;
1073
+ if (!code || !code.includes('-')) return null;
1053
1074
  var p = code.split('-');
1054
1075
  if (p.length === 2) return null;
1055
1076
  p.pop();
@@ -1058,12 +1079,12 @@
1058
1079
  }
1059
1080
  getLanguagePartFromCode(code) {
1060
1081
  code = getCleanedCode(code);
1061
- if (!code || code.indexOf('-') < 0) return code;
1082
+ if (!code || !code.includes('-')) return code;
1062
1083
  var p = code.split('-');
1063
1084
  return this.formatLanguageCode(p[0]);
1064
1085
  }
1065
1086
  formatLanguageCode(code) {
1066
- if (isString(code) && code.indexOf('-') > -1) {
1087
+ if (isString(code) && code.includes('-')) {
1067
1088
  var formattedCode;
1068
1089
  try {
1069
1090
  formattedCode = Intl.getCanonicalLocales(code)[0];
@@ -1083,7 +1104,7 @@
1083
1104
  if (this.options.load === 'languageOnly' || this.options.nonExplicitSupportedLngs) {
1084
1105
  code = this.getLanguagePartFromCode(code);
1085
1106
  }
1086
- return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.indexOf(code) > -1;
1107
+ return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.includes(code);
1087
1108
  }
1088
1109
  getBestMatchFromCodes(codes) {
1089
1110
  if (!codes) return null;
@@ -1101,10 +1122,11 @@
1101
1122
  var lngOnly = this.getLanguagePartFromCode(code);
1102
1123
  if (this.isSupportedCode(lngOnly)) return found = lngOnly;
1103
1124
  found = this.options.supportedLngs.find(supportedLng => {
1104
- if (supportedLng === lngOnly) return supportedLng;
1105
- if (supportedLng.indexOf('-') < 0 && lngOnly.indexOf('-') < 0) return;
1106
- if (supportedLng.indexOf('-') > 0 && lngOnly.indexOf('-') < 0 && supportedLng.substring(0, supportedLng.indexOf('-')) === lngOnly) return supportedLng;
1107
- if (supportedLng.indexOf(lngOnly) === 0 && lngOnly.length > 1) return supportedLng;
1125
+ if (supportedLng === lngOnly) return true;
1126
+ if (!supportedLng.includes('-') && !lngOnly.includes('-')) return false;
1127
+ if (supportedLng.includes('-') && !lngOnly.includes('-') && supportedLng.slice(0, supportedLng.indexOf('-')) === lngOnly) return true;
1128
+ if (supportedLng.startsWith(lngOnly) && lngOnly.length > 1) return true;
1129
+ return false;
1108
1130
  });
1109
1131
  });
1110
1132
  }
@@ -1135,7 +1157,7 @@
1135
1157
  this.logger.warn("rejecting language code not found in supportedLngs: ".concat(c));
1136
1158
  }
1137
1159
  };
1138
- if (isString(code) && (code.indexOf('-') > -1 || code.indexOf('_') > -1)) {
1160
+ if (isString(code) && (code.includes('-') || code.includes('_'))) {
1139
1161
  if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code));
1140
1162
  if (this.options.load !== 'languageOnly' && this.options.load !== 'currentOnly') addCode(this.getScriptPartFromCode(code));
1141
1163
  if (this.options.load !== 'currentOnly') addCode(this.getLanguagePartFromCode(code));
@@ -1143,7 +1165,7 @@
1143
1165
  addCode(this.formatLanguageCode(code));
1144
1166
  }
1145
1167
  fallbackCodes.forEach(fc => {
1146
- if (codes.indexOf(fc) < 0) addCode(this.formatLanguageCode(fc));
1168
+ if (!codes.includes(fc)) addCode(this.formatLanguageCode(fc));
1147
1169
  });
1148
1170
  return codes;
1149
1171
  }
@@ -1279,8 +1301,8 @@
1279
1301
  this.prefix = prefix ? regexEscape(prefix) : prefixEscaped || '{{';
1280
1302
  this.suffix = suffix ? regexEscape(suffix) : suffixEscaped || '}}';
1281
1303
  this.formatSeparator = formatSeparator || ',';
1282
- this.unescapePrefix = unescapeSuffix ? '' : unescapePrefix || '-';
1283
- this.unescapeSuffix = this.unescapePrefix ? '' : unescapeSuffix || '';
1304
+ this.unescapePrefix = unescapeSuffix ? '' : unescapePrefix ? regexEscape(unescapePrefix) : '-';
1305
+ this.unescapeSuffix = this.unescapePrefix ? '' : unescapeSuffix ? regexEscape(unescapeSuffix) : '';
1284
1306
  this.nestingPrefix = nestingPrefix ? regexEscape(nestingPrefix) : nestingPrefixEscaped || regexEscape('$t(');
1285
1307
  this.nestingSuffix = nestingSuffix ? regexEscape(nestingSuffix) : nestingSuffixEscaped || regexEscape(')');
1286
1308
  this.nestingOptionsSeparator = nestingOptionsSeparator || ',';
@@ -1310,7 +1332,7 @@
1310
1332
  var replaces;
1311
1333
  var defaultData = this.options && this.options.interpolation && this.options.interpolation.defaultVariables || {};
1312
1334
  var handleFormat = key => {
1313
- if (key.indexOf(this.formatSeparator) < 0) {
1335
+ if (!key.includes(this.formatSeparator)) {
1314
1336
  var path = deepFindWithDefaults(data, defaultData, key, this.options.keySeparator, this.options.ignoreJSONStructure);
1315
1337
  return this.alwaysFormat ? this.format(path, undefined, lng, _objectSpread2(_objectSpread2(_objectSpread2({}, options), data), {}, {
1316
1338
  interpolationkey: key
@@ -1324,6 +1346,9 @@
1324
1346
  }));
1325
1347
  };
1326
1348
  this.resetRegExp();
1349
+ if (!this.escapeValue && typeof str === 'string' && /\$t\([^)]*\{[^}]*\{\{/.test(str)) {
1350
+ this.logger.warn('nesting options string contains interpolated variables with escapeValue: false — ' + 'if any of those values are attacker-controlled they can inject additional ' + 'nesting options (e.g. redirect lng/ns). Sanitise untrusted input before passing ' + 'it to t(), or keep escapeValue: true.');
1351
+ }
1327
1352
  var missingInterpolationHandler = (options === null || options === void 0 ? void 0 : options.missingInterpolationHandler) || this.options.missingInterpolationHandler;
1328
1353
  var skipOnVariables = (options === null || options === void 0 || (_options$interpolatio2 = options.interpolation) === null || _options$interpolatio2 === void 0 ? void 0 : _options$interpolatio2.skipOnVariables) !== undefined ? options.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables;
1329
1354
  var todos = [{
@@ -1378,7 +1403,7 @@
1378
1403
  var handleHasOptions = (key, inheritedOptions) => {
1379
1404
  var _matchedSingleQuotes$, _matchedDoubleQuotes$;
1380
1405
  var sep = this.nestingOptionsSeparator;
1381
- if (key.indexOf(sep) < 0) return key;
1406
+ if (!key.includes(sep)) return key;
1382
1407
  var c = key.split(new RegExp("".concat(regexEscape(sep), "[ ]*{")));
1383
1408
  var optionsString = "{".concat(c[1]);
1384
1409
  key = c[0];
@@ -1395,7 +1420,7 @@
1395
1420
  this.logger.warn("failed parsing options string in nesting for key ".concat(key), e);
1396
1421
  return "".concat(key).concat(sep).concat(optionsString);
1397
1422
  }
1398
- if (clonedOptions.defaultValue && clonedOptions.defaultValue.indexOf(this.prefix) > -1) delete clonedOptions.defaultValue;
1423
+ if (clonedOptions.defaultValue && clonedOptions.defaultValue.includes(this.prefix)) delete clonedOptions.defaultValue;
1399
1424
  return key;
1400
1425
  };
1401
1426
  while (match = this.nestingRegexp.exec(str)) {
@@ -1430,13 +1455,13 @@
1430
1455
  var parseFormatStr = formatStr => {
1431
1456
  var formatName = formatStr.toLowerCase().trim();
1432
1457
  var formatOptions = {};
1433
- if (formatStr.indexOf('(') > -1) {
1458
+ if (formatStr.includes('(')) {
1434
1459
  var p = formatStr.split('(');
1435
1460
  formatName = p[0].toLowerCase().trim();
1436
- var optStr = p[1].substring(0, p[1].length - 1);
1437
- if (formatName === 'currency' && optStr.indexOf(':') < 0) {
1461
+ var optStr = p[1].slice(0, -1);
1462
+ if (formatName === 'currency' && !optStr.includes(':')) {
1438
1463
  if (!formatOptions.currency) formatOptions.currency = optStr.trim();
1439
- } else if (formatName === 'relativetime' && optStr.indexOf(':') < 0) {
1464
+ } else if (formatName === 'relativetime' && !optStr.includes(':')) {
1440
1465
  if (!formatOptions.range) formatOptions.range = optStr.trim();
1441
1466
  } else {
1442
1467
  var opts = optStr.split(';');
@@ -1523,9 +1548,11 @@
1523
1548
  }
1524
1549
  format(value, format, lng) {
1525
1550
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1551
+ if (!format) return value;
1552
+ if (value == null) return value;
1526
1553
  var formats = format.split(this.formatSeparator);
1527
- if (formats.length > 1 && formats[0].indexOf('(') > 1 && formats[0].indexOf(')') < 0 && formats.find(f => f.indexOf(')') > -1)) {
1528
- var lastIndex = formats.findIndex(f => f.indexOf(')') > -1);
1554
+ if (formats.length > 1 && formats[0].indexOf('(') > 1 && !formats[0].includes(')') && formats.find(f => f.includes(')'))) {
1555
+ var lastIndex = formats.findIndex(f => f.includes(')'));
1529
1556
  formats[0] = [formats[0], ...formats.splice(1, lastIndex)].join(this.formatSeparator);
1530
1557
  }
1531
1558
  var result = formats.reduce((mem, f) => {
@@ -1680,7 +1707,7 @@
1680
1707
  }
1681
1708
  if (err && data && tried < this.maxRetries) {
1682
1709
  setTimeout(() => {
1683
- this.read.call(this, lng, ns, fcName, tried + 1, wait * 2, callback);
1710
+ this.read(lng, ns, fcName, tried + 1, wait * 2, callback);
1684
1711
  }, wait);
1685
1712
  return;
1686
1713
  }
@@ -1788,7 +1815,6 @@
1788
1815
  nonExplicitSupportedLngs: false,
1789
1816
  load: 'all',
1790
1817
  preload: false,
1791
- simplifyPluralSuffix: true,
1792
1818
  keySeparator: '.',
1793
1819
  nsSeparator: ':',
1794
1820
  pluralSeparator: '_',
@@ -1825,7 +1851,6 @@
1825
1851
  },
1826
1852
  interpolation: {
1827
1853
  escapeValue: true,
1828
- format: value => value,
1829
1854
  prefix: '{{',
1830
1855
  suffix: '}}',
1831
1856
  formatSeparator: ',',
@@ -1839,14 +1864,12 @@
1839
1864
  cacheInBuiltFormats: true
1840
1865
  });
1841
1866
  var transformOptions = options => {
1842
- var _options$supportedLng, _options$supportedLng2;
1843
1867
  if (isString(options.ns)) options.ns = [options.ns];
1844
1868
  if (isString(options.fallbackLng)) options.fallbackLng = [options.fallbackLng];
1845
1869
  if (isString(options.fallbackNS)) options.fallbackNS = [options.fallbackNS];
1846
- if (((_options$supportedLng = options.supportedLngs) === null || _options$supportedLng === void 0 || (_options$supportedLng2 = _options$supportedLng.indexOf) === null || _options$supportedLng2 === void 0 ? void 0 : _options$supportedLng2.call(_options$supportedLng, 'cimode')) < 0) {
1870
+ if (options.supportedLngs && !options.supportedLngs.includes('cimode')) {
1847
1871
  options.supportedLngs = options.supportedLngs.concat(['cimode']);
1848
1872
  }
1849
- if (typeof options.initImmediate === 'boolean') options.initAsync = options.initImmediate;
1850
1873
  return options;
1851
1874
  };
1852
1875
  var noop = () => {};
@@ -1858,27 +1881,6 @@
1858
1881
  }
1859
1882
  });
1860
1883
  };
1861
- var SUPPORT_NOTICE_KEY = '__i18next_supportNoticeShown';
1862
- var getSupportNoticeShown = () => typeof globalThis !== 'undefined' && !!globalThis[SUPPORT_NOTICE_KEY];
1863
- var setSupportNoticeShown = () => {
1864
- if (typeof globalThis !== 'undefined') globalThis[SUPPORT_NOTICE_KEY] = true;
1865
- };
1866
- var usesLocize = inst => {
1867
- var _inst$modules, _inst$modules2, _inst$options, _inst$options2, _inst$options3;
1868
- if ((inst === null || inst === void 0 || (_inst$modules = inst.modules) === null || _inst$modules === void 0 || (_inst$modules = _inst$modules.backend) === null || _inst$modules === void 0 || (_inst$modules = _inst$modules.name) === null || _inst$modules === void 0 ? void 0 : _inst$modules.indexOf('Locize')) > 0) return true;
1869
- if ((inst === null || inst === void 0 || (_inst$modules2 = inst.modules) === null || _inst$modules2 === void 0 || (_inst$modules2 = _inst$modules2.backend) === null || _inst$modules2 === void 0 || (_inst$modules2 = _inst$modules2.constructor) === null || _inst$modules2 === void 0 || (_inst$modules2 = _inst$modules2.name) === null || _inst$modules2 === void 0 ? void 0 : _inst$modules2.indexOf('Locize')) > 0) return true;
1870
- if (inst !== null && inst !== void 0 && (_inst$options = inst.options) !== null && _inst$options !== void 0 && (_inst$options = _inst$options.backend) !== null && _inst$options !== void 0 && _inst$options.backends) {
1871
- if (inst.options.backend.backends.some(b => {
1872
- var _b$name, _b$constructor;
1873
- return (b === null || b === void 0 || (_b$name = b.name) === null || _b$name === void 0 ? void 0 : _b$name.indexOf('Locize')) > 0 || (b === null || b === void 0 || (_b$constructor = b.constructor) === null || _b$constructor === void 0 || (_b$constructor = _b$constructor.name) === null || _b$constructor === void 0 ? void 0 : _b$constructor.indexOf('Locize')) > 0;
1874
- })) return true;
1875
- }
1876
- if (inst !== null && inst !== void 0 && (_inst$options2 = inst.options) !== null && _inst$options2 !== void 0 && (_inst$options2 = _inst$options2.backend) !== null && _inst$options2 !== void 0 && _inst$options2.projectId) return true;
1877
- if (inst !== null && inst !== void 0 && (_inst$options3 = inst.options) !== null && _inst$options3 !== void 0 && (_inst$options3 = _inst$options3.backend) !== null && _inst$options3 !== void 0 && _inst$options3.backendOptions) {
1878
- if (inst.options.backend.backendOptions.some(b => b === null || b === void 0 ? void 0 : b.projectId)) return true;
1879
- }
1880
- return false;
1881
- };
1882
1884
  class I18n extends EventEmitter {
1883
1885
  constructor() {
1884
1886
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -1902,7 +1904,7 @@
1902
1904
  }
1903
1905
  }
1904
1906
  init() {
1905
- var _this2 = this;
1907
+ var _this3 = this;
1906
1908
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1907
1909
  var callback = arguments.length > 1 ? arguments[1] : undefined;
1908
1910
  this.isInitializing = true;
@@ -1913,7 +1915,7 @@
1913
1915
  if (options.defaultNS == null && options.ns) {
1914
1916
  if (isString(options.ns)) {
1915
1917
  options.defaultNS = options.ns;
1916
- } else if (options.ns.indexOf('translation') < 0) {
1918
+ } else if (!options.ns.includes('translation')) {
1917
1919
  options.defaultNS = options.ns[0];
1918
1920
  }
1919
1921
  }
@@ -1929,10 +1931,6 @@
1929
1931
  if (typeof this.options.overloadTranslationOptionHandler !== 'function') {
1930
1932
  this.options.overloadTranslationOptionHandler = defOpts.overloadTranslationOptionHandler;
1931
1933
  }
1932
- if (this.options.showSupportNotice !== false && !usesLocize(this) && !getSupportNoticeShown()) {
1933
- 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 💙');
1934
- setSupportNoticeShown();
1935
- }
1936
1934
  var createClassOnDemand = ClassOrObject => {
1937
1935
  if (!ClassOrObject) return null;
1938
1936
  if (typeof ClassOrObject === 'function') return new ClassOrObject();
@@ -1957,14 +1955,9 @@
1957
1955
  s.resourceStore = this.store;
1958
1956
  s.languageUtils = lu;
1959
1957
  s.pluralResolver = new PluralResolver(lu, {
1960
- prepend: this.options.pluralSeparator,
1961
- simplifyPluralSuffix: this.options.simplifyPluralSuffix
1958
+ prepend: this.options.pluralSeparator
1962
1959
  });
1963
- var usingLegacyFormatFunction = this.options.interpolation.format && this.options.interpolation.format !== defOpts.interpolation.format;
1964
- if (usingLegacyFormatFunction) {
1965
- this.logger.deprecate("init: you are still using the legacy format function, please use the new approach: https://www.i18next.com/translation-function/formatting");
1966
- }
1967
- if (formatter && (!this.options.interpolation.format || this.options.interpolation.format === defOpts.interpolation.format)) {
1960
+ if (formatter) {
1968
1961
  s.formatter = createClassOnDemand(formatter);
1969
1962
  if (s.formatter.init) s.formatter.init(s, this.options);
1970
1963
  this.options.interpolation.format = s.formatter.format.bind(s.formatter);
@@ -1978,7 +1971,7 @@
1978
1971
  for (var _len7 = arguments.length, args = new Array(_len7 > 1 ? _len7 - 1 : 0), _key7 = 1; _key7 < _len7; _key7++) {
1979
1972
  args[_key7 - 1] = arguments[_key7];
1980
1973
  }
1981
- _this2.emit(event, ...args);
1974
+ _this3.emit(event, ...args);
1982
1975
  });
1983
1976
  if (this.modules.languageDetector) {
1984
1977
  s.languageDetector = createClassOnDemand(this.modules.languageDetector);
@@ -1993,7 +1986,7 @@
1993
1986
  for (var _len8 = arguments.length, args = new Array(_len8 > 1 ? _len8 - 1 : 0), _key8 = 1; _key8 < _len8; _key8++) {
1994
1987
  args[_key8 - 1] = arguments[_key8];
1995
1988
  }
1996
- _this2.emit(event, ...args);
1989
+ _this3.emit(event, ...args);
1997
1990
  });
1998
1991
  this.modules.external.forEach(m => {
1999
1992
  if (m.init) m.init(this);
@@ -2011,14 +2004,14 @@
2011
2004
  var storeApi = ['getResource', 'hasResourceBundle', 'getResourceBundle', 'getDataByLanguage'];
2012
2005
  storeApi.forEach(fcName => {
2013
2006
  this[fcName] = function () {
2014
- return _this2.store[fcName](...arguments);
2007
+ return _this3.store[fcName](...arguments);
2015
2008
  };
2016
2009
  });
2017
2010
  var storeApiChained = ['addResource', 'addResources', 'addResourceBundle', 'removeResourceBundle'];
2018
2011
  storeApiChained.forEach(fcName => {
2019
2012
  this[fcName] = function () {
2020
- _this2.store[fcName](...arguments);
2021
- return _this2;
2013
+ _this3.store[fcName](...arguments);
2014
+ return _this3;
2022
2015
  };
2023
2016
  });
2024
2017
  var deferred = defer();
@@ -2032,7 +2025,7 @@
2032
2025
  deferred.resolve(t);
2033
2026
  callback(err, t);
2034
2027
  };
2035
- if (this.languages && !this.isInitialized) return finish(null, this.t.bind(this));
2028
+ if ((this.languages || this.isLanguageChangingTo) && !this.isInitialized) return finish(null, this.t.bind(this));
2036
2029
  this.changeLanguage(this.options.lng, finish);
2037
2030
  };
2038
2031
  if (this.options.resources || !this.options.initAsync) {
@@ -2057,7 +2050,7 @@
2057
2050
  var lngs = this.services.languageUtils.toResolveHierarchy(lng);
2058
2051
  lngs.forEach(l => {
2059
2052
  if (l === 'cimode') return;
2060
- if (toLoad.indexOf(l) < 0) toLoad.push(l);
2053
+ if (!toLoad.includes(l)) toLoad.push(l);
2061
2054
  });
2062
2055
  };
2063
2056
  if (!usedLng) {
@@ -2122,22 +2115,22 @@
2122
2115
  }
2123
2116
  setResolvedLanguage(l) {
2124
2117
  if (!l || !this.languages) return;
2125
- if (['cimode', 'dev'].indexOf(l) > -1) return;
2118
+ if (['cimode', 'dev'].includes(l)) return;
2126
2119
  for (var li = 0; li < this.languages.length; li++) {
2127
2120
  var lngInLngs = this.languages[li];
2128
- if (['cimode', 'dev'].indexOf(lngInLngs) > -1) continue;
2121
+ if (['cimode', 'dev'].includes(lngInLngs)) continue;
2129
2122
  if (this.store.hasLanguageSomeTranslations(lngInLngs)) {
2130
2123
  this.resolvedLanguage = lngInLngs;
2131
2124
  break;
2132
2125
  }
2133
2126
  }
2134
- if (!this.resolvedLanguage && this.languages.indexOf(l) < 0 && this.store.hasLanguageSomeTranslations(l)) {
2127
+ if (!this.resolvedLanguage && !this.languages.includes(l) && this.store.hasLanguageSomeTranslations(l)) {
2135
2128
  this.resolvedLanguage = l;
2136
2129
  this.languages.unshift(l);
2137
2130
  }
2138
2131
  }
2139
2132
  changeLanguage(lng, callback) {
2140
- var _this3 = this;
2133
+ var _this4 = this;
2141
2134
  this.isLanguageChangingTo = lng;
2142
2135
  var deferred = defer();
2143
2136
  this.emit('languageChanging', lng);
@@ -2160,10 +2153,10 @@
2160
2153
  this.isLanguageChangingTo = undefined;
2161
2154
  }
2162
2155
  deferred.resolve(function () {
2163
- return _this3.t(...arguments);
2156
+ return _this4.t(...arguments);
2164
2157
  });
2165
2158
  if (callback) callback(err, function () {
2166
- return _this3.t(...arguments);
2159
+ return _this4.t(...arguments);
2167
2160
  });
2168
2161
  };
2169
2162
  var setLng = lngs => {
@@ -2196,14 +2189,14 @@
2196
2189
  return deferred;
2197
2190
  }
2198
2191
  getFixedT(lng, ns, keyPrefix) {
2199
- var _this4 = this;
2192
+ var _this5 = this;
2200
2193
  var _fixedT = function fixedT(key, opts) {
2201
2194
  var o;
2202
2195
  if (typeof opts !== 'object') {
2203
2196
  for (var _len9 = arguments.length, rest = new Array(_len9 > 2 ? _len9 - 2 : 0), _key9 = 2; _key9 < _len9; _key9++) {
2204
2197
  rest[_key9 - 2] = arguments[_key9];
2205
2198
  }
2206
- o = _this4.options.overloadTranslationOptionHandler([key, opts].concat(rest));
2199
+ o = _this5.options.overloadTranslationOptionHandler([key, opts].concat(rest));
2207
2200
  } else {
2208
2201
  o = _objectSpread2({}, opts);
2209
2202
  }
@@ -2211,18 +2204,20 @@
2211
2204
  o.lngs = o.lngs || _fixedT.lngs;
2212
2205
  o.ns = o.ns || _fixedT.ns;
2213
2206
  if (o.keyPrefix !== '') o.keyPrefix = o.keyPrefix || keyPrefix || _fixedT.keyPrefix;
2214
- var keySeparator = _this4.options.keySeparator || '.';
2207
+ var selectorOpts = _objectSpread2(_objectSpread2({}, _this5.options), o);
2208
+ if (typeof o.keyPrefix === 'function') o.keyPrefix = keysFromSelector(o.keyPrefix, selectorOpts);
2209
+ var keySeparator = _this5.options.keySeparator || '.';
2215
2210
  var resultKey;
2216
2211
  if (o.keyPrefix && Array.isArray(key)) {
2217
2212
  resultKey = key.map(k => {
2218
- if (typeof k === 'function') k = keysFromSelector(k, _objectSpread2(_objectSpread2({}, _this4.options), opts));
2213
+ if (typeof k === 'function') k = keysFromSelector(k, selectorOpts);
2219
2214
  return "".concat(o.keyPrefix).concat(keySeparator).concat(k);
2220
2215
  });
2221
2216
  } else {
2222
- if (typeof key === 'function') key = keysFromSelector(key, _objectSpread2(_objectSpread2({}, _this4.options), opts));
2217
+ if (typeof key === 'function') key = keysFromSelector(key, selectorOpts);
2223
2218
  resultKey = o.keyPrefix ? "".concat(o.keyPrefix).concat(keySeparator).concat(key) : key;
2224
2219
  }
2225
- return _this4.t(resultKey, o);
2220
+ return _this5.t(resultKey, o);
2226
2221
  };
2227
2222
  if (isString(lng)) {
2228
2223
  _fixedT.lng = lng;
@@ -2285,7 +2280,7 @@
2285
2280
  }
2286
2281
  if (isString(ns)) ns = [ns];
2287
2282
  ns.forEach(n => {
2288
- if (this.options.ns.indexOf(n) < 0) this.options.ns.push(n);
2283
+ if (!this.options.ns.includes(n)) this.options.ns.push(n);
2289
2284
  });
2290
2285
  this.loadResources(err => {
2291
2286
  deferred.resolve();
@@ -2297,7 +2292,7 @@
2297
2292
  var deferred = defer();
2298
2293
  if (isString(lngs)) lngs = [lngs];
2299
2294
  var preloaded = this.options.preload || [];
2300
- var newLngs = lngs.filter(lng => preloaded.indexOf(lng) < 0 && this.services.languageUtils.isSupportedCode(lng));
2295
+ var newLngs = lngs.filter(lng => !preloaded.includes(lng) && this.services.languageUtils.isSupportedCode(lng));
2301
2296
  if (!newLngs.length) {
2302
2297
  if (callback) callback();
2303
2298
  return Promise.resolve();
@@ -2323,7 +2318,7 @@
2323
2318
  var 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'];
2324
2319
  var languageUtils = ((_this$services3 = this.services) === null || _this$services3 === void 0 ? void 0 : _this$services3.languageUtils) || new LanguageUtil(get());
2325
2320
  if (lng.toLowerCase().indexOf('-latn') > 1) return 'ltr';
2326
- return rtlLngs.indexOf(languageUtils.getLanguagePartFromCode(lng)) > -1 || lng.toLowerCase().indexOf('-arab') > 1 ? 'rtl' : 'ltr';
2321
+ return rtlLngs.includes(languageUtils.getLanguagePartFromCode(lng)) || lng.toLowerCase().indexOf('-arab') > 1 ? 'rtl' : 'ltr';
2327
2322
  }
2328
2323
  static createInstance() {
2329
2324
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -2412,6 +2407,66 @@
2412
2407
  var loadNamespaces = instance.loadNamespaces;
2413
2408
  var loadLanguages = instance.loadLanguages;
2414
2409
 
2410
+ function _createForOfIteratorHelper(r, e) {
2411
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
2412
+ if (!t) {
2413
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
2414
+ t && (r = t);
2415
+ var _n = 0,
2416
+ F = function F() {};
2417
+ return {
2418
+ s: F,
2419
+ n: function n() {
2420
+ return _n >= r.length ? {
2421
+ done: !0
2422
+ } : {
2423
+ done: !1,
2424
+ value: r[_n++]
2425
+ };
2426
+ },
2427
+ e: function e(r) {
2428
+ throw r;
2429
+ },
2430
+ f: F
2431
+ };
2432
+ }
2433
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
2434
+ }
2435
+ var o,
2436
+ a = !0,
2437
+ u = !1;
2438
+ return {
2439
+ s: function s() {
2440
+ t = t.call(r);
2441
+ },
2442
+ n: function n() {
2443
+ var r = t.next();
2444
+ return a = r.done, r;
2445
+ },
2446
+ e: function e(r) {
2447
+ u = !0, o = r;
2448
+ },
2449
+ f: function f() {
2450
+ try {
2451
+ a || null == t.return || t.return();
2452
+ } finally {
2453
+ if (u) throw o;
2454
+ }
2455
+ }
2456
+ };
2457
+ }
2458
+ function _unsupportedIterableToArray(r, a) {
2459
+ if (r) {
2460
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
2461
+ var t = {}.toString.call(r).slice(8, -1);
2462
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
2463
+ }
2464
+ }
2465
+ function _arrayLikeToArray(r, a) {
2466
+ (null == a || a > r.length) && (a = r.length);
2467
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
2468
+ return n;
2469
+ }
2415
2470
  function _typeof(o) {
2416
2471
  "@babel/helpers - typeof";
2417
2472
 
@@ -2421,6 +2476,35 @@
2421
2476
  return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
2422
2477
  }, _typeof(o);
2423
2478
  }
2479
+ var UNSAFE_KEYS = ['__proto__', 'constructor', 'prototype'];
2480
+ function isSafeUrlSegment(v) {
2481
+ if (typeof v !== 'string') return false;
2482
+ if (v.length === 0 || v.length > 128) return false;
2483
+ if (UNSAFE_KEYS.indexOf(v) > -1) return false;
2484
+ if (v.indexOf('..') > -1) return false;
2485
+ if (v.indexOf('/') > -1 || v.indexOf('\\') > -1) return false;
2486
+ if (/[?#%\s@]/.test(v)) return false;
2487
+ if (/[\x00-\x1F\x7F]/.test(v)) return false;
2488
+ return true;
2489
+ }
2490
+ function sanitizeLogValue(v) {
2491
+ if (typeof v !== 'string') return v;
2492
+ return v.replace(/[\r\n\x00-\x1F\x7F]/g, ' ');
2493
+ }
2494
+ function redactUrlCredentials(u) {
2495
+ if (typeof u !== 'string' || u.length === 0) return u;
2496
+ try {
2497
+ var parsed = new URL(u);
2498
+ if (parsed.username || parsed.password) {
2499
+ parsed.username = '';
2500
+ parsed.password = '';
2501
+ return parsed.toString();
2502
+ }
2503
+ return u;
2504
+ } catch (e) {
2505
+ return u.replace(/(\/\/)[^/@\s]+@/g, '$1');
2506
+ }
2507
+ }
2424
2508
  function hasXMLHttpRequest() {
2425
2509
  return typeof XMLHttpRequest === 'function' || (typeof XMLHttpRequest === "undefined" ? "undefined" : _typeof(XMLHttpRequest)) === 'object';
2426
2510
  }
@@ -2433,6 +2517,34 @@
2433
2517
  }
2434
2518
  return Promise.resolve(maybePromise);
2435
2519
  }
2520
+ var interpolationRegexp = /\{\{(.+?)\}\}/g;
2521
+ function interpolateUrl(str, data) {
2522
+ var unsafe = false;
2523
+ var result = str.replace(interpolationRegexp, function (match, key) {
2524
+ var k = key.trim();
2525
+ if (UNSAFE_KEYS.indexOf(k) > -1) return match;
2526
+ var value = data[k];
2527
+ if (value == null) return match;
2528
+ var segments = String(value).split('+');
2529
+ var _iterator = _createForOfIteratorHelper(segments),
2530
+ _step;
2531
+ try {
2532
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
2533
+ var seg = _step.value;
2534
+ if (!isSafeUrlSegment(seg)) {
2535
+ unsafe = true;
2536
+ return match;
2537
+ }
2538
+ }
2539
+ } catch (err) {
2540
+ _iterator.e(err);
2541
+ } finally {
2542
+ _iterator.f();
2543
+ }
2544
+ return segments.join('+');
2545
+ });
2546
+ return unsafe ? null : result;
2547
+ }
2436
2548
 
2437
2549
  function ownKeys$1(e, r) {
2438
2550
  var t = Object.keys(e);
@@ -2516,10 +2628,13 @@
2516
2628
  }).catch(function () {});
2517
2629
  } catch (e) {}
2518
2630
  }
2631
+ var UNSAFE_KEYS$1 = ['__proto__', 'constructor', 'prototype'];
2519
2632
  var addQueryString = function addQueryString(url, params) {
2520
2633
  if (params && _typeof$1(params) === 'object') {
2521
2634
  var queryString = '';
2522
- for (var paramName in params) {
2635
+ for (var _i = 0, _Object$keys = Object.keys(params); _i < _Object$keys.length; _i++) {
2636
+ var paramName = _Object$keys[_i];
2637
+ if (UNSAFE_KEYS$1.indexOf(paramName) > -1) continue;
2523
2638
  queryString += '&' + encodeURIComponent(paramName) + '=' + encodeURIComponent(params[paramName]);
2524
2639
  }
2525
2640
  if (!queryString) return url;
@@ -2552,7 +2667,6 @@
2552
2667
  fetchApi(url, fetchOptions).then(resolver).catch(callback);
2553
2668
  }
2554
2669
  };
2555
- var omitFetchOptions = false;
2556
2670
  var requestWithFetch = function requestWithFetch(options, url, payload, callback) {
2557
2671
  if (options.queryStringParams) {
2558
2672
  url = addQueryString(url, options.queryStringParams);
@@ -2567,7 +2681,7 @@
2567
2681
  method: payload ? 'POST' : 'GET',
2568
2682
  body: payload ? options.stringify(payload) : undefined,
2569
2683
  headers: headers
2570
- }, omitFetchOptions ? {} : reqOptions);
2684
+ }, options._omitFetchOptions ? {} : reqOptions);
2571
2685
  var altFetch = typeof options.alternateFetch === 'function' && options.alternateFetch.length >= 1 ? options.alternateFetch : undefined;
2572
2686
  try {
2573
2687
  fetchIt(url, fetchOptions, callback, altFetch);
@@ -2580,7 +2694,7 @@
2580
2694
  delete fetchOptions[opt];
2581
2695
  });
2582
2696
  fetchIt(url, fetchOptions, callback, altFetch);
2583
- omitFetchOptions = true;
2697
+ options._omitFetchOptions = true;
2584
2698
  } catch (err) {
2585
2699
  callback(err);
2586
2700
  }
@@ -2609,7 +2723,9 @@
2609
2723
  var h = options.customHeaders;
2610
2724
  h = typeof h === 'function' ? h() : h;
2611
2725
  if (h) {
2612
- for (var i in h) {
2726
+ for (var _i2 = 0, _Object$keys2 = Object.keys(h); _i2 < _Object$keys2.length; _i2++) {
2727
+ var i = _Object$keys2[_i2];
2728
+ if (UNSAFE_KEYS$1.indexOf(i) > -1) continue;
2613
2729
  x.setRequestHeader(i, h[i]);
2614
2730
  }
2615
2731
  }
@@ -2781,10 +2897,15 @@
2781
2897
  loadPath = makePromise(loadPath);
2782
2898
  loadPath.then(function (resolvedLoadPath) {
2783
2899
  if (!resolvedLoadPath) return callback(null, {});
2784
- var url = _this2.services.interpolator.interpolate(resolvedLoadPath, {
2900
+ var url = interpolateUrl(resolvedLoadPath, {
2785
2901
  lng: languages.join('+'),
2786
2902
  ns: namespaces.join('+')
2787
2903
  });
2904
+ if (url == null) {
2905
+ var safeLngs = languages.map(sanitizeLogValue).join(', ');
2906
+ var safeNss = namespaces.map(sanitizeLogValue).join(', ');
2907
+ return callback(new Error('i18next-http-backend: unsafe lng/ns value — refusing to build request URL for languages=[' + safeLngs + '] namespaces=[' + safeNss + ']'), false);
2908
+ }
2788
2909
  _this2.loadUrl(url, callback, loadUrlLanguages, loadUrlNamespaces);
2789
2910
  });
2790
2911
  }
@@ -2795,16 +2916,17 @@
2795
2916
  var lng = typeof languages === 'string' ? [languages] : languages;
2796
2917
  var ns = typeof namespaces === 'string' ? [namespaces] : namespaces;
2797
2918
  var payload = this.options.parseLoadPayload(lng, ns);
2919
+ var safeUrl = sanitizeLogValue(redactUrlCredentials(url));
2798
2920
  this.options.request(this.options, url, payload, function (err, res) {
2799
- if (res && (res.status >= 500 && res.status < 600 || !res.status)) return callback('failed loading ' + url + '; status code: ' + res.status, true);
2800
- if (res && res.status >= 400 && res.status < 500) return callback('failed loading ' + url + '; status code: ' + res.status, false);
2921
+ if (res && (res.status >= 500 && res.status < 600 || !res.status)) return callback('failed loading ' + safeUrl + '; status code: ' + res.status, true);
2922
+ if (res && res.status >= 400 && res.status < 500) return callback('failed loading ' + safeUrl + '; status code: ' + res.status, false);
2801
2923
  if (!res && err && err.message) {
2802
2924
  var errorMessage = err.message.toLowerCase();
2803
2925
  var isNetworkError = ['failed', 'fetch', 'network', 'load'].find(function (term) {
2804
2926
  return errorMessage.indexOf(term) > -1;
2805
2927
  });
2806
2928
  if (isNetworkError) {
2807
- return callback('failed loading ' + url + ': ' + err.message, true);
2929
+ return callback('failed loading ' + safeUrl + ': ' + sanitizeLogValue(err.message), true);
2808
2930
  }
2809
2931
  }
2810
2932
  if (err) return callback(err, false);
@@ -2816,7 +2938,7 @@
2816
2938
  ret = res.data;
2817
2939
  }
2818
2940
  } catch (e) {
2819
- parseErr = 'failed parsing ' + url + ' to json';
2941
+ parseErr = 'failed parsing ' + safeUrl + ' to json';
2820
2942
  }
2821
2943
  if (parseErr) return callback(parseErr, false);
2822
2944
  callback(null, ret);
@@ -2837,10 +2959,15 @@
2837
2959
  if (typeof _this4.options.addPath === 'function') {
2838
2960
  addPath = _this4.options.addPath(lng, namespace);
2839
2961
  }
2840
- var url = _this4.services.interpolator.interpolate(addPath, {
2962
+ var url = interpolateUrl(addPath, {
2841
2963
  lng: lng,
2842
2964
  ns: namespace
2843
2965
  });
2966
+ if (url == null) {
2967
+ finished += 1;
2968
+ if (callback && finished === languages.length) callback(dataArray, resArray);
2969
+ return;
2970
+ }
2844
2971
  _this4.options.request(_this4.options, url, payload, function (data, res) {
2845
2972
  finished += 1;
2846
2973
  dataArray.push(data);
@@ -4658,8 +4785,12 @@
4658
4785
  return value;
4659
4786
  };
4660
4787
  DOMElement.prototype.removeAttributeNS = function _Element_removeAttributeNS(namespace, name) {
4788
+ // Prevent prototype pollution by checking if namespace is a direct property
4789
+ if (!Object.prototype.hasOwnProperty.call(this._attributes, namespace)) {
4790
+ return;
4791
+ }
4661
4792
  var attributes = this._attributes[namespace];
4662
- if (attributes) {
4793
+ if (attributes && Object.prototype.hasOwnProperty.call(attributes, name)) {
4663
4794
  delete attributes[name];
4664
4795
  }
4665
4796
  };
@@ -6784,6 +6915,16 @@
6784
6915
  }
6785
6916
  var replaceInside = ['src', 'href'];
6786
6917
  var REGEXP = new RegExp('%7B%7B(.+?)%7D%7D', 'g'); // urlEncoded {{}}
6918
+
6919
+ // Reject URL schemes that execute script when used in href/src — regardless
6920
+ // of whether the attacker-controlled value reaches the attribute via a
6921
+ // compromised translation backend, a compromised translation file, or a
6922
+ // local override. The list covers the concrete known-exploitable schemes;
6923
+ // legitimate translation use cases never need them.
6924
+ var DANGEROUS_URL_SCHEMES = /^\s*(javascript|data|vbscript|file)\s*:/i;
6925
+ function isDangerousUrl(value) {
6926
+ return typeof value === 'string' && DANGEROUS_URL_SCHEMES.test(value);
6927
+ }
6787
6928
  function translateProps(node, props) {
6788
6929
  var tOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
6789
6930
  var overrideKey = arguments.length > 3 ? arguments[3] : undefined;
@@ -6833,7 +6974,13 @@
6833
6974
  mem.splice(index - 1, 1);
6834
6975
  }
6835
6976
  }
6836
- mem.push(tr);
6977
+ // Drop dangerous URL schemes (javascript:/data:/vbscript:/file:)
6978
+ // no legitimate translation needs them in src/href.
6979
+ if (isDangerousUrl(tr)) {
6980
+ mem.push('');
6981
+ } else {
6982
+ mem.push(tr);
6983
+ }
6837
6984
  }
6838
6985
  return mem;
6839
6986
  }, arr);
@@ -6912,7 +7059,20 @@
6912
7059
  }
6913
7060
 
6914
7061
  // translate that's children and surround it again with a dummy node to parse to vdom
6915
- var translation = "<i18nextifydummy>".concat(translate(key, tOptions, overrideKey), "</i18nextifydummy>");
7062
+ var translated = translate(key, tOptions, overrideKey);
7063
+ // Optional sanitize hook — if the application has configured
7064
+ // `i18next.options.sanitize` (e.g. wired to DOMPurify), run the raw
7065
+ // translation through it before parsing into the virtual DOM.
7066
+ // Default is pass-through because i18nextify's whole purpose is to
7067
+ // render HTML from translations; sanitisation is only safe for apps
7068
+ // where translation content may not be fully trusted.
7069
+ if (typeof instance.options.sanitize === 'function') {
7070
+ translated = instance.options.sanitize(translated, {
7071
+ key: key,
7072
+ attribute: null
7073
+ });
7074
+ }
7075
+ var translation = "<i18nextifydummy>".concat(translated, "</i18nextifydummy>");
6916
7076
  var newNode = vdomParser((translation || '').trim());
6917
7077
 
6918
7078
  // replace children on passed in node
@@ -7090,8 +7250,24 @@
7090
7250
  cleanWhitespace: true,
7091
7251
  nsSeparator: '#||#',
7092
7252
  keySeparator: '#|#',
7093
- debug: window.location.search && window.location.search.indexOf('debug=true') > -1,
7094
- saveMissing: window.location.search && window.location.search.indexOf('saveMissing=true') > -1,
7253
+ // Use URLSearchParams for exact parameter lookup — a previous substring
7254
+ // match (`indexOf('debug=true')`) activated these modes for any URL that
7255
+ // happened to contain the substring (`?nosaveMissing=true` enabled
7256
+ // saveMissing; `?track_debug=true` enabled debug).
7257
+ debug: function () {
7258
+ try {
7259
+ return new URLSearchParams(window.location.search).get('debug') === 'true';
7260
+ } catch (e) {
7261
+ return false;
7262
+ }
7263
+ }(),
7264
+ saveMissing: function () {
7265
+ try {
7266
+ return new URLSearchParams(window.location.search).get('saveMissing') === 'true';
7267
+ } catch (e) {
7268
+ return false;
7269
+ }
7270
+ }(),
7095
7271
  namespace: scriptEle && scriptEle.getAttribute('namespace') || false,
7096
7272
  namespaceFromPath: scriptEle && (scriptEle.getAttribute('namespacefrompath') || scriptEle.getAttribute('namespaceFromPath')) || false,
7097
7273
  missingKeyHandler: missingHandler,
@@ -7228,19 +7404,96 @@
7228
7404
  forceRerender: forceRerender
7229
7405
  };
7230
7406
 
7407
+ function _createForOfIteratorHelper$1(r, e) {
7408
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
7409
+ if (!t) {
7410
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray$1(r)) || e && r && "number" == typeof r.length) {
7411
+ t && (r = t);
7412
+ var _n = 0,
7413
+ F = function F() {};
7414
+ return {
7415
+ s: F,
7416
+ n: function n() {
7417
+ return _n >= r.length ? {
7418
+ done: !0
7419
+ } : {
7420
+ done: !1,
7421
+ value: r[_n++]
7422
+ };
7423
+ },
7424
+ e: function e(r) {
7425
+ throw r;
7426
+ },
7427
+ f: F
7428
+ };
7429
+ }
7430
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
7431
+ }
7432
+ var o,
7433
+ a = !0,
7434
+ u = !1;
7435
+ return {
7436
+ s: function s() {
7437
+ t = t.call(r);
7438
+ },
7439
+ n: function n() {
7440
+ var r = t.next();
7441
+ return a = r.done, r;
7442
+ },
7443
+ e: function e(r) {
7444
+ u = !0, o = r;
7445
+ },
7446
+ f: function f() {
7447
+ try {
7448
+ a || null == t.return || t.return();
7449
+ } finally {
7450
+ if (u) throw o;
7451
+ }
7452
+ }
7453
+ };
7454
+ }
7455
+ function _unsupportedIterableToArray$1(r, a) {
7456
+ if (r) {
7457
+ if ("string" == typeof r) return _arrayLikeToArray$1(r, a);
7458
+ var t = {}.toString.call(r).slice(8, -1);
7459
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$1(r, a) : void 0;
7460
+ }
7461
+ }
7462
+ function _arrayLikeToArray$1(r, a) {
7463
+ (null == a || a > r.length) && (a = r.length);
7464
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
7465
+ return n;
7466
+ }
7231
7467
  var arr = [];
7232
7468
  var each = arr.forEach;
7233
7469
  var slice$2 = arr.slice;
7470
+ var UNSAFE_KEYS$2 = ['__proto__', 'constructor', 'prototype'];
7234
7471
  function defaults$1(obj) {
7235
7472
  each.call(slice$2.call(arguments, 1), function (source) {
7236
7473
  if (source) {
7237
- for (var prop in source) {
7474
+ for (var _i = 0, _Object$keys = Object.keys(source); _i < _Object$keys.length; _i++) {
7475
+ var prop = _Object$keys[_i];
7476
+ if (UNSAFE_KEYS$2.indexOf(prop) > -1) continue;
7238
7477
  if (obj[prop] === undefined) obj[prop] = source[prop];
7239
7478
  }
7240
7479
  }
7241
7480
  });
7242
7481
  return obj;
7243
7482
  }
7483
+ function isSafeUrlSegment$1(v) {
7484
+ if (typeof v !== 'string') return false;
7485
+ if (v.length === 0 || v.length > 128) return false;
7486
+ if (UNSAFE_KEYS$2.indexOf(v) > -1) return false;
7487
+ if (v.indexOf('..') > -1) return false;
7488
+ if (v.indexOf('/') > -1 || v.indexOf('\\') > -1) return false;
7489
+ if (/[?#%\s@]/.test(v)) return false;
7490
+ if (/[\x00-\x1F\x7F]/.test(v)) return false;
7491
+ return true;
7492
+ }
7493
+ function sanitizeLogValue$1(v) {
7494
+ if (typeof v !== 'string') return v;
7495
+ return v.replace(/[\r\n\x00-\x1F\x7F]/g, ' ');
7496
+ }
7244
7497
  function debounce$1(func, wait, immediate) {
7245
7498
  var timeout;
7246
7499
  return function () {
@@ -7299,20 +7552,47 @@
7299
7552
  if (object == null) return '';
7300
7553
  return '' + object;
7301
7554
  }
7302
- function interpolate(str, data, lng) {
7303
- var match, value;
7304
- function regexSafe(val) {
7305
- return val.replace(/\$/g, '$$$$');
7306
- }
7555
+ function interpolateUrl$1(str, data) {
7556
+ var match;
7557
+ var unsafe = false;
7307
7558
  while (match = regexp.exec(str)) {
7308
- value = match[1].trim();
7309
- if (typeof value !== 'string') value = makeString$1(value);
7310
- if (!value) value = '';
7311
- value = regexSafe(value);
7312
- str = str.replace(match[0], data[value] || value);
7559
+ var key = match[1].trim();
7560
+ if (UNSAFE_KEYS$2.indexOf(key) > -1) {
7561
+ regexp.lastIndex = 0;
7562
+ continue;
7563
+ }
7564
+ var raw = data[key];
7565
+ if (raw == null) {
7566
+ regexp.lastIndex = 0;
7567
+ continue;
7568
+ }
7569
+ var value = makeString$1(raw);
7570
+ var segments = value.split('+');
7571
+ var segmentsOk = true;
7572
+ var _iterator = _createForOfIteratorHelper$1(segments),
7573
+ _step;
7574
+ try {
7575
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
7576
+ var seg = _step.value;
7577
+ if (!isSafeUrlSegment$1(seg)) {
7578
+ segmentsOk = false;
7579
+ break;
7580
+ }
7581
+ }
7582
+ } catch (err) {
7583
+ _iterator.e(err);
7584
+ } finally {
7585
+ _iterator.f();
7586
+ }
7587
+ if (!segmentsOk) {
7588
+ unsafe = true;
7589
+ break;
7590
+ }
7591
+ str = str.replace(match[0], segments.join('+'));
7313
7592
  regexp.lastIndex = 0;
7314
7593
  }
7315
- return str;
7594
+ regexp.lastIndex = 0;
7595
+ return unsafe ? null : str;
7316
7596
  }
7317
7597
  function isMissingOption(obj, props) {
7318
7598
  return props.reduce(function (mem, p) {
@@ -7795,14 +8075,18 @@
7795
8075
  callback(new Error(isMissing));
7796
8076
  return deferred;
7797
8077
  }
7798
- var url = interpolate(this.options.getLanguagesPath, {
8078
+ var url = interpolateUrl$1(this.options.getLanguagesPath, {
7799
8079
  projectId: this.options.projectId
7800
8080
  });
8081
+ if (url == null) {
8082
+ callback(new Error('i18next-locize-backend: unsafe projectId — refusing to build request URL for projectId=' + sanitizeLogValue$1(String(this.options.projectId))));
8083
+ return deferred;
8084
+ }
7801
8085
  if (!this.isProjectNotExisting && this.storage.isProjectNotExisting(this.options.projectId)) {
7802
8086
  this.isProjectNotExisting = true;
7803
8087
  }
7804
8088
  if (this.isProjectNotExisting) {
7805
- callback(new Error(this.isProjectNotExistingErrorMessage || "locize project ".concat(this.options.projectId, " does not exist!")));
8089
+ callback(new Error(this.isProjectNotExistingErrorMessage || "Locize project ".concat(this.options.projectId, " does not exist!")));
7806
8090
  return deferred;
7807
8091
  }
7808
8092
  this.getLanguagesCalls = this.getLanguagesCalls || [];
@@ -7811,16 +8095,17 @@
7811
8095
  this.loadUrl({}, url, function (err, ret, info) {
7812
8096
  if (!_this3.somethingLoaded && info && info.resourceNotExisting) {
7813
8097
  _this3.isProjectNotExisting = true;
7814
- var errMsg = "locize project ".concat(_this3.options.projectId, " does not exist!");
8098
+ var errMsg = "Locize project ".concat(_this3.options.projectId, " does not exist!");
7815
8099
  _this3.isProjectNotExistingErrorMessage = errMsg;
7816
8100
  var cdnTypeAlt = _this3.options.cdnType === 'standard' ? 'pro' : 'standard';
7817
8101
  var otherEndpointApiPaths = getApiPaths(cdnTypeAlt);
7818
- var urlAlt = interpolate(otherEndpointApiPaths.getLanguagesPath, {
8102
+ var urlAlt = interpolateUrl$1(otherEndpointApiPaths.getLanguagesPath, {
7819
8103
  projectId: _this3.options.projectId
7820
8104
  });
8105
+ if (urlAlt == null) return;
7821
8106
  _this3.loadUrl({}, urlAlt, function (errAlt, retAlt, infoAlt) {
7822
8107
  if (!errAlt && retAlt && (!infoAlt || !infoAlt.resourceNotExisting)) {
7823
- errMsg += " It seems you're using the wrong cdnType. Your locize project is configured to use \"".concat(cdnTypeAlt, "\" but here you've configured \"").concat(_this3.options.cdnType, "\".");
8108
+ errMsg += " It seems you're using the wrong cdnType. Your Locize project is configured to use \"".concat(cdnTypeAlt, "\" but here you've configured \"").concat(_this3.options.cdnType, "\".");
7824
8109
  _this3.isProjectNotExistingErrorMessage = errMsg;
7825
8110
  } else if (!_this3.somethingLoaded && infoAlt && infoAlt.resourceNotExisting) {
7826
8111
  _this3.isProjectNotExisting = true;
@@ -7950,7 +8235,7 @@
7950
8235
  if (this.options.private) {
7951
8236
  var isMissing = isMissingOption(this.options, ['projectId', 'version', 'apiKey']);
7952
8237
  if (isMissing) return callback(new Error(isMissing), false);
7953
- url = interpolate(this.options.privatePath, {
8238
+ url = interpolateUrl$1(this.options.privatePath, {
7954
8239
  lng: language,
7955
8240
  ns: namespace,
7956
8241
  projectId: this.options.projectId,
@@ -7962,24 +8247,27 @@
7962
8247
  } else {
7963
8248
  var _isMissing = isMissingOption(this.options, ['projectId', 'version']);
7964
8249
  if (_isMissing) return callback(new Error(_isMissing), false);
7965
- url = interpolate(this.options.loadPath, {
8250
+ url = interpolateUrl$1(this.options.loadPath, {
7966
8251
  lng: language,
7967
8252
  ns: namespace,
7968
8253
  projectId: this.options.projectId,
7969
8254
  version: this.options.version
7970
8255
  });
7971
8256
  }
8257
+ if (url == null) {
8258
+ return callback(new Error('i18next-locize-backend: unsafe lng/ns/projectId/version — refusing to build request URL for lng=' + sanitizeLogValue$1(String(language)) + ' ns=' + sanitizeLogValue$1(String(namespace))), false);
8259
+ }
7972
8260
  if (!this.isProjectNotExisting && this.storage.isProjectNotExisting(this.options.projectId)) {
7973
8261
  this.isProjectNotExisting = true;
7974
8262
  }
7975
8263
  if (this.isProjectNotExisting) {
7976
- var err = new Error(this.isProjectNotExistingErrorMessage || "locize project ".concat(this.options.projectId, " does not exist!"));
8264
+ var err = new Error(this.isProjectNotExistingErrorMessage || "Locize project ".concat(this.options.projectId, " does not exist!"));
7977
8265
  if (logger) logger.error(err.message);
7978
8266
  if (callback) callback(err);
7979
8267
  return;
7980
8268
  }
7981
8269
  if (this.warnedLanguages && this.warnedLanguages.indexOf(language) > -1) {
7982
- var _err = new Error("Will not continue to load language \"".concat(language, "\" since it is not available in locize project ").concat(this.options.projectId, "!"));
8270
+ var _err = new Error("Will not continue to load language \"".concat(language, "\" since it is not available in Locize project ").concat(this.options.projectId, "!"));
7983
8271
  if (logger) logger.error(_err.message);
7984
8272
  if (callback) callback(_err);
7985
8273
  return;
@@ -7998,7 +8286,7 @@
7998
8286
  if (_this6.warnedLanguages && _this6.warnedLanguages.indexOf(language) > -1) return;
7999
8287
  _this6.warnedLanguages || (_this6.warnedLanguages = []);
8000
8288
  _this6.warnedLanguages.push(language);
8001
- if (logger) logger.error("Language \"".concat(language, "\" is not available in locize project ").concat(_this6.options.projectId, "!"));
8289
+ if (logger) logger.error("Language \"".concat(language, "\" is not available in Locize project ").concat(_this6.options.projectId, "!"));
8002
8290
  });
8003
8291
  }, randomizeTimeout(_this6.options.checkForProjectTimeout));
8004
8292
  }
@@ -8127,18 +8415,24 @@
8127
8415
  }, {
8128
8416
  key: "writePage",
8129
8417
  value: function writePage(lng, namespace, missings, callback) {
8130
- var missingUrl = interpolate(this.options.addPath, {
8418
+ var missingUrl = interpolateUrl$1(this.options.addPath, {
8131
8419
  lng: lng,
8132
8420
  ns: namespace,
8133
8421
  projectId: this.options.projectId,
8134
8422
  version: this.options.version
8135
8423
  });
8136
- var updatesUrl = interpolate(this.options.updatePath, {
8424
+ var updatesUrl = interpolateUrl$1(this.options.updatePath, {
8137
8425
  lng: lng,
8138
8426
  ns: namespace,
8139
8427
  projectId: this.options.projectId,
8140
8428
  version: this.options.version
8141
8429
  });
8430
+ if (missingUrl == null || updatesUrl == null) {
8431
+ if (typeof callback === 'function') {
8432
+ callback(new Error('i18next-locize-backend: unsafe lng/ns/projectId/version — refusing to persist missing keys for lng=' + sanitizeLogValue$1(String(lng)) + ' ns=' + sanitizeLogValue$1(String(namespace))));
8433
+ }
8434
+ return;
8435
+ }
8142
8436
  var hasMissing = false;
8143
8437
  var hasUpdates = false;
8144
8438
  var payloadMissing = {};
@@ -8591,17 +8885,17 @@
8591
8885
  }
8592
8886
  }
8593
8887
 
8594
- function _arrayLikeToArray(r, a) {
8888
+ function _arrayLikeToArray$2(r, a) {
8595
8889
  (null == a || a > r.length) && (a = r.length);
8596
8890
  for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
8597
8891
  return n;
8598
8892
  }
8599
8893
 
8600
- function _unsupportedIterableToArray(r, a) {
8894
+ function _unsupportedIterableToArray$2(r, a) {
8601
8895
  if (r) {
8602
- if ("string" == typeof r) return _arrayLikeToArray(r, a);
8896
+ if ("string" == typeof r) return _arrayLikeToArray$2(r, a);
8603
8897
  var t = {}.toString.call(r).slice(8, -1);
8604
- return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
8898
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$2(r, a) : void 0;
8605
8899
  }
8606
8900
  }
8607
8901
 
@@ -8610,7 +8904,7 @@
8610
8904
  }
8611
8905
 
8612
8906
  function _slicedToArray$1(r, e) {
8613
- return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
8907
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray$2(r, e) || _nonIterableRest();
8614
8908
  }
8615
8909
 
8616
8910
  function debounce$2(func, wait, immediate) {
@@ -8867,8 +9161,17 @@
8867
9161
  sendMessage('added', msg);
8868
9162
  }
8869
9163
  };
9164
+ var getExpectedIframeOrigin = function getExpectedIframeOrigin() {
9165
+ try {
9166
+ return new URL(getIframeUrl()).origin;
9167
+ } catch (err) {
9168
+ return null;
9169
+ }
9170
+ };
8870
9171
  if (typeof window !== 'undefined') {
8871
9172
  window.addEventListener('message', function (e) {
9173
+ var expectedOrigin = getExpectedIframeOrigin();
9174
+ if (!expectedOrigin || e.origin !== expectedOrigin) return;
8872
9175
  var _e$data = e.data,
8873
9176
  sender = _e$data.sender,
8874
9177
  action = _e$data.action,
@@ -8889,6 +9192,45 @@
8889
9192
  });
8890
9193
  }
8891
9194
 
9195
+ var DANGEROUS_ATTR_NAMES = /^(on\w+|style)$/i;
9196
+ var URL_ATTR_NAMES = /^(href|src|action|formaction|xlink:href)$/i;
9197
+ var DANGEROUS_URL_SCHEMES$1 = /^\s*(javascript|data|vbscript|file)\s*:/i;
9198
+ function isSafeAttributeWrite(attr, value) {
9199
+ if (typeof attr !== 'string') return false;
9200
+ if (DANGEROUS_ATTR_NAMES.test(attr)) return false;
9201
+ if (URL_ATTR_NAMES.test(attr) && typeof value === 'string' && DANGEROUS_URL_SCHEMES$1.test(value)) return false;
9202
+ return true;
9203
+ }
9204
+ function sanitizeTranslationHtml(html) {
9205
+ if (typeof html !== 'string') return html;
9206
+ if (typeof DOMParser === 'undefined') return html;
9207
+ try {
9208
+ var doc = new DOMParser().parseFromString("<body>".concat(html, "</body>"), 'text/html');
9209
+ var disallowedTags = ['SCRIPT', 'IFRAME', 'OBJECT', 'EMBED', 'LINK', 'META', 'BASE', 'STYLE'];
9210
+ disallowedTags.forEach(function (tag) {
9211
+ doc.body.querySelectorAll(tag.toLowerCase()).forEach(function (n) {
9212
+ return n.remove();
9213
+ });
9214
+ });
9215
+ doc.body.querySelectorAll('*').forEach(function (n) {
9216
+ var attrs = Array.from(n.attributes);
9217
+ attrs.forEach(function (a) {
9218
+ var name = a.name;
9219
+ var val = a.value;
9220
+ if (/^on/i.test(name)) {
9221
+ n.removeAttribute(name);
9222
+ return;
9223
+ }
9224
+ if (URL_ATTR_NAMES.test(name) && DANGEROUS_URL_SCHEMES$1.test(val)) {
9225
+ n.removeAttribute(name);
9226
+ }
9227
+ });
9228
+ });
9229
+ return doc.body.innerHTML;
9230
+ } catch (e) {
9231
+ return html;
9232
+ }
9233
+ }
8892
9234
  function setValueOnNode(meta, value) {
8893
9235
  var item = store.get(meta.eleUniqueID);
8894
9236
  if (!item || !item.keys[meta.textType]) return;
@@ -8897,6 +9239,7 @@
8897
9239
  item.node.textContent = txtWithHiddenMeta;
8898
9240
  } else if (meta.textType.indexOf('attr:') === 0) {
8899
9241
  var attr = meta.textType.replace('attr:', '');
9242
+ if (!isSafeAttributeWrite(attr, txtWithHiddenMeta)) return;
8900
9243
  item.node.setAttribute(attr, txtWithHiddenMeta);
8901
9244
  } else if (meta.textType === 'html') {
8902
9245
  var id = "".concat(meta.textType, "-").concat(meta.children);
@@ -8907,13 +9250,14 @@
8907
9250
  });
8908
9251
  item.originalChildNodes = clones;
8909
9252
  }
9253
+ var sanitisedHtml = sanitizeTranslationHtml(txtWithHiddenMeta);
8910
9254
  if (item.children[id].length === item.node.childNodes.length) {
8911
- item.node.innerHTML = txtWithHiddenMeta;
9255
+ item.node.innerHTML = sanitisedHtml;
8912
9256
  } else {
8913
9257
  var children = item.children[id];
8914
9258
  var first = children[0].child;
8915
9259
  var dummy = document.createElement('div');
8916
- dummy.innerHTML = txtWithHiddenMeta;
9260
+ dummy.innerHTML = sanitisedHtml;
8917
9261
  var nodes = [];
8918
9262
  dummy.childNodes.forEach(function (c) {
8919
9263
  nodes.push(c);
@@ -8956,7 +9300,7 @@
8956
9300
  api.addHandler('commitKey', handler$1);
8957
9301
 
8958
9302
  function _arrayWithoutHoles(r) {
8959
- if (Array.isArray(r)) return _arrayLikeToArray(r);
9303
+ if (Array.isArray(r)) return _arrayLikeToArray$2(r);
8960
9304
  }
8961
9305
 
8962
9306
  function _iterableToArray(r) {
@@ -8968,7 +9312,7 @@
8968
9312
  }
8969
9313
 
8970
9314
  function _toConsumableArray(r) {
8971
- return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
9315
+ return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray$2(r) || _nonIterableSpread();
8972
9316
  }
8973
9317
 
8974
9318
  function handler$2(payload) {
@@ -9069,9 +9413,23 @@
9069
9413
  return refEle;
9070
9414
  }
9071
9415
 
9416
+ function isOccluded(node) {
9417
+ var rect = node.getBoundingClientRect();
9418
+ if (!rect.width || !rect.height) return true;
9419
+ var x = rect.left + rect.width / 2;
9420
+ var y = rect.top + rect.height / 2;
9421
+ var topEl = document.elementFromPoint(x, y);
9422
+ if (!topEl) return true;
9423
+ if (topEl.dataset && topEl.dataset.i18nextEditorElement === 'true') return false;
9424
+ return !node.contains(topEl) && !topEl.contains(node);
9425
+ }
9072
9426
  var debouncedUpdateDistance = debounce$2(function (e, observer) {
9073
9427
  Object.values(store.data).forEach(function (item) {
9074
9428
  if (!isInViewport(item.node)) return;
9429
+ if (isOccluded(item.node)) {
9430
+ resetHighlight(item, item.node, item.keys);
9431
+ return;
9432
+ }
9075
9433
  var distance = mouseDistanceFromElement(e, item.node);
9076
9434
  if (distance < 5) {
9077
9435
  highlight(item, item.node, item.keys);
@@ -9082,6 +9440,10 @@
9082
9440
  });
9083
9441
  Object.values(uninstrumentedStore.data).forEach(function (item) {
9084
9442
  if (!isInViewport(item.node)) return;
9443
+ if (isOccluded(item.node)) {
9444
+ resetHighlight(item, item.node, item.keys);
9445
+ return;
9446
+ }
9085
9447
  var distance = mouseDistanceFromElement(e, item.node);
9086
9448
  if (distance < 10) {
9087
9449
  highlightUninstrumented(item, item.node, item.keys);
@@ -9197,6 +9559,10 @@
9197
9559
  return popup;
9198
9560
  }
9199
9561
 
9562
+ var CSS_LENGTH_RE = /^\d+(?:\.\d+)?(?:px|%|em|rem|vh|vw|ch|ex)$/i;
9563
+ function isSafeCssLength(v) {
9564
+ return typeof v === 'string' && CSS_LENGTH_RE.test(v);
9565
+ }
9200
9566
  function handler$4(payload) {
9201
9567
  var containerStyle = payload.containerStyle;
9202
9568
  if (containerStyle) {
@@ -9210,6 +9576,12 @@
9210
9576
  containerStyle.height = storedSize.height + 'px';
9211
9577
  containerStyle.width = storedSize.width + 'px';
9212
9578
  }
9579
+ if (containerStyle.height && !isSafeCssLength(containerStyle.height)) {
9580
+ delete containerStyle.height;
9581
+ }
9582
+ if (containerStyle.width && !isSafeCssLength(containerStyle.width)) {
9583
+ delete containerStyle.width;
9584
+ }
9213
9585
  if (containerStyle.height) {
9214
9586
  var diff = "calc(".concat(containerStyle.height, " - ").concat(popup.style.height, ")");
9215
9587
  popup.style.setProperty('top', "calc(".concat(popup.style.top, " - ").concat(diff, ")"));
@@ -9220,10 +9592,10 @@
9220
9592
  popup.style.setProperty('left', "calc(".concat(popup.style.left, " - ").concat(_diff, ")"));
9221
9593
  popup.style.setProperty('width', containerStyle.width);
9222
9594
  }
9223
- if (storedPos && storedPos.top && storedPos.top < window.innerHeight - containerStyle.height.replace('px', '')) {
9595
+ if (storedPos && storedPos.top && containerStyle.height && storedPos.top < window.innerHeight - containerStyle.height.replace('px', '')) {
9224
9596
  popup.style.setProperty('top', storedPos.top + 'px');
9225
9597
  }
9226
- if (storedPos && storedPos.left && storedPos.left < window.innerWidth - containerStyle.width.replace('px', '')) {
9598
+ if (storedPos && storedPos.left && containerStyle.width && storedPos.left < window.innerWidth - containerStyle.width.replace('px', '')) {
9227
9599
  popup.style.setProperty('left', storedPos.left + 'px');
9228
9600
  }
9229
9601
  }
@@ -9406,10 +9778,6 @@
9406
9778
  bottom: 'top',
9407
9779
  top: 'bottom'
9408
9780
  };
9409
- var oppositeAlignmentMap = {
9410
- start: 'end',
9411
- end: 'start'
9412
- };
9413
9781
  function clamp(start, value, end) {
9414
9782
  return max(start, min(value, end));
9415
9783
  }
@@ -9429,7 +9797,8 @@
9429
9797
  return axis === 'y' ? 'height' : 'width';
9430
9798
  }
9431
9799
  function getSideAxis(placement) {
9432
- return ['top', 'bottom'].includes(getSide(placement)) ? 'y' : 'x';
9800
+ var firstChar = placement[0];
9801
+ return firstChar === 't' || firstChar === 'b' ? 'y' : 'x';
9433
9802
  }
9434
9803
  function getAlignmentAxis(placement) {
9435
9804
  return getOppositeAxis(getSideAxis(placement));
@@ -9452,21 +9821,21 @@
9452
9821
  return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
9453
9822
  }
9454
9823
  function getOppositeAlignmentPlacement(placement) {
9455
- return placement.replace(/start|end/g, alignment => oppositeAlignmentMap[alignment]);
9824
+ return placement.includes('start') ? placement.replace('start', 'end') : placement.replace('end', 'start');
9456
9825
  }
9826
+ var lrPlacement = ['left', 'right'];
9827
+ var rlPlacement = ['right', 'left'];
9828
+ var tbPlacement = ['top', 'bottom'];
9829
+ var btPlacement = ['bottom', 'top'];
9457
9830
  function getSideList(side, isStart, rtl) {
9458
- var lr = ['left', 'right'];
9459
- var rl = ['right', 'left'];
9460
- var tb = ['top', 'bottom'];
9461
- var bt = ['bottom', 'top'];
9462
9831
  switch (side) {
9463
9832
  case 'top':
9464
9833
  case 'bottom':
9465
- if (rtl) return isStart ? rl : lr;
9466
- return isStart ? lr : rl;
9834
+ if (rtl) return isStart ? rlPlacement : lrPlacement;
9835
+ return isStart ? lrPlacement : rlPlacement;
9467
9836
  case 'left':
9468
9837
  case 'right':
9469
- return isStart ? tb : bt;
9838
+ return isStart ? tbPlacement : btPlacement;
9470
9839
  default:
9471
9840
  return [];
9472
9841
  }
@@ -9483,7 +9852,8 @@
9483
9852
  return list;
9484
9853
  }
9485
9854
  function getOppositePlacement(placement) {
9486
- return placement.replace(/left|right|bottom|top/g, side => oppositeSideMap[side]);
9855
+ var side = getSide(placement);
9856
+ return oppositeSideMap[side] + placement.slice(side.length);
9487
9857
  }
9488
9858
  function expandPaddingObject(padding) {
9489
9859
  return _objectSpread2({
@@ -9578,6 +9948,78 @@
9578
9948
  return coords;
9579
9949
  }
9580
9950
 
9951
+ /**
9952
+ * Resolves with an object of overflow side offsets that determine how much the
9953
+ * element is overflowing a given clipping boundary on each side.
9954
+ * - positive = overflowing the boundary by that number of pixels
9955
+ * - negative = how many pixels left before it will overflow
9956
+ * - 0 = lies flush with the boundary
9957
+ * @see https://floating-ui.com/docs/detectOverflow
9958
+ */
9959
+ function detectOverflow(_x, _x2) {
9960
+ return _detectOverflow.apply(this, arguments);
9961
+ } // Maximum number of resets that can occur before bailing to avoid infinite reset loops.
9962
+ function _detectOverflow() {
9963
+ _detectOverflow = _asyncToGenerator(function* (state, options) {
9964
+ var _await$platform$isEle;
9965
+ if (options === void 0) {
9966
+ options = {};
9967
+ }
9968
+ var {
9969
+ x,
9970
+ y,
9971
+ platform,
9972
+ rects,
9973
+ elements,
9974
+ strategy
9975
+ } = state;
9976
+ var {
9977
+ boundary = 'clippingAncestors',
9978
+ rootBoundary = 'viewport',
9979
+ elementContext = 'floating',
9980
+ altBoundary = false,
9981
+ padding = 0
9982
+ } = evaluate(options, state);
9983
+ var paddingObject = getPaddingObject(padding);
9984
+ var altContext = elementContext === 'floating' ? 'reference' : 'floating';
9985
+ var element = elements[altBoundary ? altContext : elementContext];
9986
+ var clippingClientRect = rectToClientRect(yield platform.getClippingRect({
9987
+ element: ((_await$platform$isEle = yield platform.isElement == null ? void 0 : platform.isElement(element)) != null ? _await$platform$isEle : true) ? element : element.contextElement || (yield platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating)),
9988
+ boundary,
9989
+ rootBoundary,
9990
+ strategy
9991
+ }));
9992
+ var rect = elementContext === 'floating' ? {
9993
+ x,
9994
+ y,
9995
+ width: rects.floating.width,
9996
+ height: rects.floating.height
9997
+ } : rects.reference;
9998
+ var offsetParent = yield platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating);
9999
+ var offsetScale = (yield platform.isElement == null ? void 0 : platform.isElement(offsetParent)) ? (yield platform.getScale == null ? void 0 : platform.getScale(offsetParent)) || {
10000
+ x: 1,
10001
+ y: 1
10002
+ } : {
10003
+ x: 1,
10004
+ y: 1
10005
+ };
10006
+ var elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? yield platform.convertOffsetParentRelativeRectToViewportRelativeRect({
10007
+ elements,
10008
+ rect,
10009
+ offsetParent,
10010
+ strategy
10011
+ }) : rect);
10012
+ return {
10013
+ top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
10014
+ bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
10015
+ left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
10016
+ right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
10017
+ };
10018
+ });
10019
+ return _detectOverflow.apply(this, arguments);
10020
+ }
10021
+ var MAX_RESET_COUNT = 50;
10022
+
9581
10023
  /**
9582
10024
  * Computes the `x` and `y` coordinates that will place the floating element
9583
10025
  * next to a given reference element.
@@ -9593,7 +10035,9 @@
9593
10035
  middleware = [],
9594
10036
  platform
9595
10037
  } = config;
9596
- var validMiddleware = middleware.filter(Boolean);
10038
+ var platformWithDetectOverflow = platform.detectOverflow ? platform : _objectSpread2(_objectSpread2({}, platform), {}, {
10039
+ detectOverflow
10040
+ });
9597
10041
  var rtl = yield platform.isRTL == null ? void 0 : platform.isRTL(floating);
9598
10042
  var rects = yield platform.getElementRects({
9599
10043
  reference,
@@ -9605,13 +10049,17 @@
9605
10049
  y
9606
10050
  } = computeCoordsFromPlacement(rects, placement, rtl);
9607
10051
  var statefulPlacement = placement;
9608
- var middlewareData = {};
9609
10052
  var resetCount = 0;
9610
- for (var i = 0; i < validMiddleware.length; i++) {
10053
+ var middlewareData = {};
10054
+ for (var i = 0; i < middleware.length; i++) {
10055
+ var currentMiddleware = middleware[i];
10056
+ if (!currentMiddleware) {
10057
+ continue;
10058
+ }
9611
10059
  var {
9612
10060
  name,
9613
10061
  fn
9614
- } = validMiddleware[i];
10062
+ } = currentMiddleware;
9615
10063
  var {
9616
10064
  x: nextX,
9617
10065
  y: nextY,
@@ -9625,7 +10073,7 @@
9625
10073
  strategy,
9626
10074
  middlewareData,
9627
10075
  rects,
9628
- platform,
10076
+ platform: platformWithDetectOverflow,
9629
10077
  elements: {
9630
10078
  reference,
9631
10079
  floating
@@ -9633,10 +10081,8 @@
9633
10081
  });
9634
10082
  x = nextX != null ? nextX : x;
9635
10083
  y = nextY != null ? nextY : y;
9636
- middlewareData = _objectSpread2(_objectSpread2({}, middlewareData), {}, {
9637
- [name]: _objectSpread2(_objectSpread2({}, middlewareData[name]), data)
9638
- });
9639
- if (reset && resetCount <= 50) {
10084
+ middlewareData[name] = _objectSpread2(_objectSpread2({}, middlewareData[name]), data);
10085
+ if (reset && resetCount < MAX_RESET_COUNT) {
9640
10086
  resetCount++;
9641
10087
  if (typeof reset === 'object') {
9642
10088
  if (reset.placement) {
@@ -9665,86 +10111,16 @@
9665
10111
  middlewareData
9666
10112
  };
9667
10113
  });
9668
- return function computePosition(_x, _x2, _x3) {
10114
+ return function computePosition(_x3, _x4, _x5) {
9669
10115
  return _ref2.apply(this, arguments);
9670
10116
  };
9671
10117
  }();
9672
10118
 
9673
- /**
9674
- * Resolves with an object of overflow side offsets that determine how much the
9675
- * element is overflowing a given clipping boundary on each side.
9676
- * - positive = overflowing the boundary by that number of pixels
9677
- * - negative = how many pixels left before it will overflow
9678
- * - 0 = lies flush with the boundary
9679
- * @see https://floating-ui.com/docs/detectOverflow
9680
- */
9681
- function detectOverflow(_x4, _x5) {
9682
- return _detectOverflow.apply(this, arguments);
9683
- }
9684
10119
  /**
9685
10120
  * Provides data to position an inner element of the floating element so that it
9686
10121
  * appears centered to the reference element.
9687
10122
  * @see https://floating-ui.com/docs/arrow
9688
10123
  */
9689
- function _detectOverflow() {
9690
- _detectOverflow = _asyncToGenerator(function* (state, options) {
9691
- var _await$platform$isEle;
9692
- if (options === void 0) {
9693
- options = {};
9694
- }
9695
- var {
9696
- x,
9697
- y,
9698
- platform,
9699
- rects,
9700
- elements,
9701
- strategy
9702
- } = state;
9703
- var {
9704
- boundary = 'clippingAncestors',
9705
- rootBoundary = 'viewport',
9706
- elementContext = 'floating',
9707
- altBoundary = false,
9708
- padding = 0
9709
- } = evaluate(options, state);
9710
- var paddingObject = getPaddingObject(padding);
9711
- var altContext = elementContext === 'floating' ? 'reference' : 'floating';
9712
- var element = elements[altBoundary ? altContext : elementContext];
9713
- var clippingClientRect = rectToClientRect(yield platform.getClippingRect({
9714
- element: ((_await$platform$isEle = yield platform.isElement == null ? void 0 : platform.isElement(element)) != null ? _await$platform$isEle : true) ? element : element.contextElement || (yield platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating)),
9715
- boundary,
9716
- rootBoundary,
9717
- strategy
9718
- }));
9719
- var rect = elementContext === 'floating' ? {
9720
- x,
9721
- y,
9722
- width: rects.floating.width,
9723
- height: rects.floating.height
9724
- } : rects.reference;
9725
- var offsetParent = yield platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating);
9726
- var offsetScale = (yield platform.isElement == null ? void 0 : platform.isElement(offsetParent)) ? (yield platform.getScale == null ? void 0 : platform.getScale(offsetParent)) || {
9727
- x: 1,
9728
- y: 1
9729
- } : {
9730
- x: 1,
9731
- y: 1
9732
- };
9733
- var elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? yield platform.convertOffsetParentRelativeRectToViewportRelativeRect({
9734
- elements,
9735
- rect,
9736
- offsetParent,
9737
- strategy
9738
- }) : rect);
9739
- return {
9740
- top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
9741
- bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
9742
- left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
9743
- right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
9744
- };
9745
- });
9746
- return _detectOverflow.apply(this, arguments);
9747
- }
9748
10124
  var arrow = options => ({
9749
10125
  name: 'arrow',
9750
10126
  options,
@@ -9875,7 +10251,7 @@
9875
10251
  fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl));
9876
10252
  }
9877
10253
  var placements = [initialPlacement, ...fallbackPlacements];
9878
- var overflow = yield detectOverflow(state, detectOverflowOptions);
10254
+ var overflow = yield platform.detectOverflow(state, detectOverflowOptions);
9879
10255
  var overflows = [];
9880
10256
  var overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
9881
10257
  if (checkMainAxis) {
@@ -9896,16 +10272,22 @@
9896
10272
  var nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
9897
10273
  var nextPlacement = placements[nextIndex];
9898
10274
  if (nextPlacement) {
9899
- // Try next placement and re-run the lifecycle.
9900
- return {
9901
- data: {
9902
- index: nextIndex,
9903
- overflows: overflowsData
9904
- },
9905
- reset: {
9906
- placement: nextPlacement
9907
- }
9908
- };
10275
+ var ignoreCrossAxisOverflow = checkCrossAxis === 'alignment' ? initialSideAxis !== getSideAxis(nextPlacement) : false;
10276
+ if (!ignoreCrossAxisOverflow ||
10277
+ // We leave the current main axis only if every placement on that axis
10278
+ // overflows the main axis.
10279
+ overflowsData.every(d => getSideAxis(d.placement) === initialSideAxis ? d.overflows[0] > 0 : true)) {
10280
+ // Try next placement and re-run the lifecycle.
10281
+ return {
10282
+ data: {
10283
+ index: nextIndex,
10284
+ overflows: overflowsData
10285
+ },
10286
+ reset: {
10287
+ placement: nextPlacement
10288
+ }
10289
+ };
10290
+ }
9909
10291
  }
9910
10292
 
9911
10293
  // First, find the candidates that fit on the mainAxis side of overflow,
@@ -9951,6 +10333,7 @@
9951
10333
  }
9952
10334
  };
9953
10335
  };
10336
+ var originSides = /*#__PURE__*/new Set(['left', 'top']);
9954
10337
 
9955
10338
  // For type backwards-compatibility, the `OffsetOptions` type was also
9956
10339
  // Derivable.
@@ -9975,7 +10358,7 @@
9975
10358
  var side = getSide(placement);
9976
10359
  var alignment = getAlignment(placement);
9977
10360
  var isVertical = getSideAxis(placement) === 'y';
9978
- var mainAxisMulti = ['left', 'top'].includes(side) ? -1 : 1;
10361
+ var mainAxisMulti = originSides.has(side) ? -1 : 1;
9979
10362
  var crossAxisMulti = rtl && isVertical ? -1 : 1;
9980
10363
  var rawValue = evaluate(options, state);
9981
10364
 
@@ -10058,7 +10441,8 @@
10058
10441
  var {
10059
10442
  x,
10060
10443
  y,
10061
- placement
10444
+ placement,
10445
+ platform
10062
10446
  } = state;
10063
10447
  var _evaluate4 = evaluate(options, state),
10064
10448
  {
@@ -10082,7 +10466,7 @@
10082
10466
  x,
10083
10467
  y
10084
10468
  };
10085
- var overflow = yield detectOverflow(state, detectOverflowOptions);
10469
+ var overflow = yield platform.detectOverflow(state, detectOverflowOptions);
10086
10470
  var crossAxis = getSideAxis(getSide(placement));
10087
10471
  var mainAxis = getOppositeAxis(crossAxis);
10088
10472
  var mainAxisCoord = coords[mainAxis];
@@ -10170,28 +10554,36 @@
10170
10554
  overflowX,
10171
10555
  overflowY,
10172
10556
  display
10173
- } = getComputedStyle(element);
10174
- return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && !['inline', 'contents'].includes(display);
10557
+ } = getComputedStyle$1(element);
10558
+ return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== 'inline' && display !== 'contents';
10175
10559
  }
10176
10560
  function isTableElement(element) {
10177
- return ['table', 'td', 'th'].includes(getNodeName(element));
10561
+ return /^(table|td|th)$/.test(getNodeName(element));
10178
10562
  }
10179
10563
  function isTopLayer(element) {
10180
- return [':popover-open', ':modal'].some(selector => {
10181
- try {
10182
- return element.matches(selector);
10183
- } catch (e) {
10184
- return false;
10564
+ try {
10565
+ if (element.matches(':popover-open')) {
10566
+ return true;
10185
10567
  }
10186
- });
10568
+ } catch (_e) {
10569
+ // no-op
10570
+ }
10571
+ try {
10572
+ return element.matches(':modal');
10573
+ } catch (_e) {
10574
+ return false;
10575
+ }
10187
10576
  }
10577
+ var willChangeRe = /transform|translate|scale|rotate|perspective|filter/;
10578
+ var containRe = /paint|layout|strict|content/;
10579
+ var isNotNone = value => !!value && value !== 'none';
10580
+ var isWebKitValue;
10188
10581
  function isContainingBlock(elementOrCss) {
10189
- var webkit = isWebKit();
10190
- var css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;
10582
+ var css = isElement(elementOrCss) ? getComputedStyle$1(elementOrCss) : elementOrCss;
10191
10583
 
10192
10584
  // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
10193
10585
  // https://drafts.csswg.org/css-transforms-2/#individual-transforms
10194
- return ['transform', 'translate', 'scale', 'rotate', 'perspective'].some(value => css[value] ? css[value] !== 'none' : false) || (css.containerType ? css.containerType !== 'normal' : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== 'none' : false) || !webkit && (css.filter ? css.filter !== 'none' : false) || ['transform', 'translate', 'scale', 'rotate', 'perspective', 'filter'].some(value => (css.willChange || '').includes(value)) || ['paint', 'layout', 'strict', 'content'].some(value => (css.contain || '').includes(value));
10586
+ return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || '') || containRe.test(css.contain || '');
10195
10587
  }
10196
10588
  function getContainingBlock(element) {
10197
10589
  var currentNode = getParentNode(element);
@@ -10206,13 +10598,15 @@
10206
10598
  return null;
10207
10599
  }
10208
10600
  function isWebKit() {
10209
- if (typeof CSS === 'undefined' || !CSS.supports) return false;
10210
- return CSS.supports('-webkit-backdrop-filter', 'none');
10601
+ if (isWebKitValue == null) {
10602
+ isWebKitValue = typeof CSS !== 'undefined' && CSS.supports && CSS.supports('-webkit-backdrop-filter', 'none');
10603
+ }
10604
+ return isWebKitValue;
10211
10605
  }
10212
10606
  function isLastTraversableNode(node) {
10213
- return ['html', 'body', '#document'].includes(getNodeName(node));
10607
+ return /^(html|body|#document)$/.test(getNodeName(node));
10214
10608
  }
10215
- function getComputedStyle(element) {
10609
+ function getComputedStyle$1(element) {
10216
10610
  return getWindow(element).getComputedStyle(element);
10217
10611
  }
10218
10612
  function getNodeScroll(element) {
@@ -10266,15 +10660,16 @@
10266
10660
  if (isBody) {
10267
10661
  var frameElement = getFrameElement(win);
10268
10662
  return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
10663
+ } else {
10664
+ return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
10269
10665
  }
10270
- return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
10271
10666
  }
10272
10667
  function getFrameElement(win) {
10273
10668
  return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
10274
10669
  }
10275
10670
 
10276
10671
  function getCssDimensions(element) {
10277
- var css = getComputedStyle(element);
10672
+ var css = getComputedStyle$1(element);
10278
10673
  // In testing environments, the `width` and `height` properties are empty
10279
10674
  // strings for SVG elements, returning NaN. Fallback to `0` in this case.
10280
10675
  var width = parseFloat(css.width) || 0;
@@ -10375,7 +10770,7 @@
10375
10770
  while (currentIFrame && offsetParent && offsetWin !== currentWin) {
10376
10771
  var iframeScale = getScale(currentIFrame);
10377
10772
  var iframeRect = currentIFrame.getBoundingClientRect();
10378
- var css = getComputedStyle(currentIFrame);
10773
+ var css = getComputedStyle$1(currentIFrame);
10379
10774
  var left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x;
10380
10775
  var top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y;
10381
10776
  x *= iframeScale.x;
@@ -10405,14 +10800,9 @@
10405
10800
  }
10406
10801
  return rect.left + leftScroll;
10407
10802
  }
10408
- function getHTMLOffset(documentElement, scroll, ignoreScrollbarX) {
10409
- if (ignoreScrollbarX === void 0) {
10410
- ignoreScrollbarX = false;
10411
- }
10803
+ function getHTMLOffset(documentElement, scroll) {
10412
10804
  var htmlRect = documentElement.getBoundingClientRect();
10413
- var x = htmlRect.left + scroll.scrollLeft - (ignoreScrollbarX ? 0 :
10414
- // RTL <body> scrollbar.
10415
- getWindowScrollBarX(documentElement, htmlRect));
10805
+ var x = htmlRect.left + scroll.scrollLeft - getWindowScrollBarX(documentElement, htmlRect);
10416
10806
  var y = htmlRect.top + scroll.scrollTop;
10417
10807
  return {
10418
10808
  x,
@@ -10443,14 +10833,14 @@
10443
10833
  if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {
10444
10834
  scroll = getNodeScroll(offsetParent);
10445
10835
  }
10446
- if (isHTMLElement(offsetParent)) {
10836
+ if (isOffsetParentAnElement) {
10447
10837
  var offsetRect = getBoundingClientRect(offsetParent);
10448
10838
  scale = getScale(offsetParent);
10449
10839
  offsets.x = offsetRect.x + offsetParent.clientLeft;
10450
10840
  offsets.y = offsetRect.y + offsetParent.clientTop;
10451
10841
  }
10452
10842
  }
10453
- var htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll, true) : createCoords(0);
10843
+ var htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
10454
10844
  return {
10455
10845
  width: rect.width * scale.x,
10456
10846
  height: rect.height * scale.y,
@@ -10472,7 +10862,7 @@
10472
10862
  var height = max(html.scrollHeight, html.clientHeight, body.scrollHeight, body.clientHeight);
10473
10863
  var x = -scroll.scrollLeft + getWindowScrollBarX(element);
10474
10864
  var y = -scroll.scrollTop;
10475
- if (getComputedStyle(body).direction === 'rtl') {
10865
+ if (getComputedStyle$1(body).direction === 'rtl') {
10476
10866
  x += max(html.clientWidth, body.clientWidth) - width;
10477
10867
  }
10478
10868
  return {
@@ -10482,6 +10872,11 @@
10482
10872
  y
10483
10873
  };
10484
10874
  }
10875
+
10876
+ // Safety check: ensure the scrollbar space is reasonable in case this
10877
+ // calculation is affected by unusual styles.
10878
+ // Most scrollbars leave 15-18px of space.
10879
+ var SCROLLBAR_MAX = 25;
10485
10880
  function getViewportRect(element, strategy) {
10486
10881
  var win = getWindow(element);
10487
10882
  var html = getDocumentElement(element);
@@ -10499,6 +10894,24 @@
10499
10894
  y = visualViewport.offsetTop;
10500
10895
  }
10501
10896
  }
10897
+ var windowScrollbarX = getWindowScrollBarX(html);
10898
+ // <html> `overflow: hidden` + `scrollbar-gutter: stable` reduces the
10899
+ // visual width of the <html> but this is not considered in the size
10900
+ // of `html.clientWidth`.
10901
+ if (windowScrollbarX <= 0) {
10902
+ var doc = html.ownerDocument;
10903
+ var body = doc.body;
10904
+ var bodyStyles = getComputedStyle(body);
10905
+ var bodyMarginInline = doc.compatMode === 'CSS1Compat' ? parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight) || 0 : 0;
10906
+ var clippingStableScrollbarWidth = Math.abs(html.clientWidth - body.clientWidth - bodyMarginInline);
10907
+ if (clippingStableScrollbarWidth <= SCROLLBAR_MAX) {
10908
+ width -= clippingStableScrollbarWidth;
10909
+ }
10910
+ } else if (windowScrollbarX <= SCROLLBAR_MAX) {
10911
+ // If the <body> scrollbar is on the left, the width needs to be extended
10912
+ // by the scrollbar amount so there isn't extra space on the right.
10913
+ width += windowScrollbarX;
10914
+ }
10502
10915
  return {
10503
10916
  width,
10504
10917
  height,
@@ -10548,7 +10961,7 @@
10548
10961
  if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) {
10549
10962
  return false;
10550
10963
  }
10551
- return getComputedStyle(parentNode).position === 'fixed' || hasFixedPositionAncestor(parentNode, stopNode);
10964
+ return getComputedStyle$1(parentNode).position === 'fixed' || hasFixedPositionAncestor(parentNode, stopNode);
10552
10965
  }
10553
10966
 
10554
10967
  // A "clipping ancestor" is an `overflow` element with the characteristic of
@@ -10561,17 +10974,17 @@
10561
10974
  }
10562
10975
  var result = getOverflowAncestors(element, [], false).filter(el => isElement(el) && getNodeName(el) !== 'body');
10563
10976
  var currentContainingBlockComputedStyle = null;
10564
- var elementIsFixed = getComputedStyle(element).position === 'fixed';
10977
+ var elementIsFixed = getComputedStyle$1(element).position === 'fixed';
10565
10978
  var currentNode = elementIsFixed ? getParentNode(element) : element;
10566
10979
 
10567
10980
  // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
10568
10981
  while (isElement(currentNode) && !isLastTraversableNode(currentNode)) {
10569
- var computedStyle = getComputedStyle(currentNode);
10982
+ var computedStyle = getComputedStyle$1(currentNode);
10570
10983
  var currentNodeIsContaining = isContainingBlock(currentNode);
10571
10984
  if (!currentNodeIsContaining && computedStyle.position === 'fixed') {
10572
10985
  currentContainingBlockComputedStyle = null;
10573
10986
  }
10574
- var shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === 'static' && !!currentContainingBlockComputedStyle && ['absolute', 'fixed'].includes(currentContainingBlockComputedStyle.position) || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode);
10987
+ var shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === 'static' && !!currentContainingBlockComputedStyle && (currentContainingBlockComputedStyle.position === 'absolute' || currentContainingBlockComputedStyle.position === 'fixed') || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode);
10575
10988
  if (shouldDropCurrentNode) {
10576
10989
  // Drop non-containing blocks.
10577
10990
  result = result.filter(ancestor => ancestor !== currentNode);
@@ -10596,20 +11009,23 @@
10596
11009
  } = _ref;
10597
11010
  var elementClippingAncestors = boundary === 'clippingAncestors' ? isTopLayer(element) ? [] : getClippingElementAncestors(element, this._c) : [].concat(boundary);
10598
11011
  var clippingAncestors = [...elementClippingAncestors, rootBoundary];
10599
- var firstClippingAncestor = clippingAncestors[0];
10600
- var clippingRect = clippingAncestors.reduce((accRect, clippingAncestor) => {
10601
- var rect = getClientRectFromClippingAncestor(element, clippingAncestor, strategy);
10602
- accRect.top = max(rect.top, accRect.top);
10603
- accRect.right = min(rect.right, accRect.right);
10604
- accRect.bottom = min(rect.bottom, accRect.bottom);
10605
- accRect.left = max(rect.left, accRect.left);
10606
- return accRect;
10607
- }, getClientRectFromClippingAncestor(element, firstClippingAncestor, strategy));
11012
+ var firstRect = getClientRectFromClippingAncestor(element, clippingAncestors[0], strategy);
11013
+ var top = firstRect.top;
11014
+ var right = firstRect.right;
11015
+ var bottom = firstRect.bottom;
11016
+ var left = firstRect.left;
11017
+ for (var i = 1; i < clippingAncestors.length; i++) {
11018
+ var rect = getClientRectFromClippingAncestor(element, clippingAncestors[i], strategy);
11019
+ top = max(rect.top, top);
11020
+ right = min(rect.right, right);
11021
+ bottom = min(rect.bottom, bottom);
11022
+ left = max(rect.left, left);
11023
+ }
10608
11024
  return {
10609
- width: clippingRect.right - clippingRect.left,
10610
- height: clippingRect.bottom - clippingRect.top,
10611
- x: clippingRect.left,
10612
- y: clippingRect.top
11025
+ width: right - left,
11026
+ height: bottom - top,
11027
+ x: left,
11028
+ y: top
10613
11029
  };
10614
11030
  }
10615
11031
  function getDimensions(element) {
@@ -10632,6 +11048,12 @@
10632
11048
  scrollTop: 0
10633
11049
  };
10634
11050
  var offsets = createCoords(0);
11051
+
11052
+ // If the <body> scrollbar appears on the left (e.g. RTL systems). Use
11053
+ // Firefox with layout.scrollbar.side = 3 in about:config to test this.
11054
+ function setLeftRTLScrollbarOffset() {
11055
+ offsets.x = getWindowScrollBarX(documentElement);
11056
+ }
10635
11057
  if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
10636
11058
  if (getNodeName(offsetParent) !== 'body' || isOverflowElement(documentElement)) {
10637
11059
  scroll = getNodeScroll(offsetParent);
@@ -10641,11 +11063,12 @@
10641
11063
  offsets.x = offsetRect.x + offsetParent.clientLeft;
10642
11064
  offsets.y = offsetRect.y + offsetParent.clientTop;
10643
11065
  } else if (documentElement) {
10644
- // If the <body> scrollbar appears on the left (e.g. RTL systems). Use
10645
- // Firefox with layout.scrollbar.side = 3 in about:config to test this.
10646
- offsets.x = getWindowScrollBarX(documentElement);
11066
+ setLeftRTLScrollbarOffset();
10647
11067
  }
10648
11068
  }
11069
+ if (isFixed && !isOffsetParentAnElement && documentElement) {
11070
+ setLeftRTLScrollbarOffset();
11071
+ }
10649
11072
  var htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
10650
11073
  var x = rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x;
10651
11074
  var y = rect.top + scroll.scrollTop - offsets.y - htmlOffset.y;
@@ -10657,10 +11080,10 @@
10657
11080
  };
10658
11081
  }
10659
11082
  function isStaticPositioned(element) {
10660
- return getComputedStyle(element).position === 'static';
11083
+ return getComputedStyle$1(element).position === 'static';
10661
11084
  }
10662
11085
  function getTrueOffsetParent(element, polyfill) {
10663
- if (!isHTMLElement(element) || getComputedStyle(element).position === 'fixed') {
11086
+ if (!isHTMLElement(element) || getComputedStyle$1(element).position === 'fixed') {
10664
11087
  return null;
10665
11088
  }
10666
11089
  if (polyfill) {
@@ -10724,7 +11147,7 @@
10724
11147
  };
10725
11148
  }();
10726
11149
  function isRTL(element) {
10727
- return getComputedStyle(element).direction === 'rtl';
11150
+ return getComputedStyle$1(element).direction === 'rtl';
10728
11151
  }
10729
11152
  var platform = {
10730
11153
  convertOffsetParentRelativeRectToViewportRelativeRect,
@@ -11094,11 +11517,12 @@
11094
11517
  if (child.nodeName !== '#text') return;
11095
11518
  var txt = child.textContent;
11096
11519
  if (containsOnlySpaces(txt)) return;
11097
- var hasHiddenMeta = containsHiddenMeta(txt);
11098
- var hasHiddenStartMarker = containsHiddenStartMarker(txt);
11520
+ var trimmedTxt = txt.trim();
11521
+ var hasHiddenMeta = containsHiddenMeta(trimmedTxt);
11522
+ var hasHiddenStartMarker = containsHiddenStartMarker(trimmedTxt);
11099
11523
  if (hasHiddenMeta) usedSubliminalForText = true;
11100
11524
  if (hasHiddenStartMarker && hasHiddenMeta) {
11101
- var meta = unwrap(txt);
11525
+ var meta = unwrap(trimmedTxt);
11102
11526
  uninstrumentedStore.remove(node.uniqueID, node);
11103
11527
  store.save(node.uniqueID, meta.invisibleMeta, 'text', extractHiddenMeta(node.uniqueID, 'text', meta), node);
11104
11528
  } else if (hasHiddenStartMarker) {
@@ -11221,6 +11645,8 @@
11221
11645
  if (mutation.type === 'attributes' && !validAttributes.includes(mutation.attributeName)) {
11222
11646
  return;
11223
11647
  }
11648
+ var target = mutation.target.nodeType === 3 ? mutation.target.parentElement : mutation.target;
11649
+ if (!target) return;
11224
11650
  Object.keys(mutationTriggeringElements).forEach(function (k) {
11225
11651
  var info = mutationTriggeringElements[k];
11226
11652
  if (info.lastTriggerDate + 60000 < Date.now()) {
@@ -11229,7 +11655,7 @@
11229
11655
  });
11230
11656
  if (mutation.type === 'childList') {
11231
11657
  var notOurs = 0;
11232
- if (!ignoreMutation(mutation.target)) {
11658
+ if (!ignoreMutation(target)) {
11233
11659
  mutation.addedNodes.forEach(function (n) {
11234
11660
  if (ignoreMutation(n)) return;
11235
11661
  notOurs = notOurs + 1;
@@ -11242,25 +11668,25 @@
11242
11668
  if (notOurs === 0) return;
11243
11669
  }
11244
11670
  triggerMutation = true;
11245
- if (mutation.target && mutation.target.uniqueID) {
11246
- var info = mutationTriggeringElements[mutation.target.uniqueID] || {
11671
+ if (target.uniqueID) {
11672
+ var info = mutationTriggeringElements[target.uniqueID] || {
11247
11673
  triggered: 0
11248
11674
  };
11249
11675
  info.triggered = info.triggered + 1;
11250
11676
  info.lastTriggerDate = Date.now();
11251
- mutationTriggeringElements[mutation.target.uniqueID] = info;
11677
+ mutationTriggeringElements[target.uniqueID] = info;
11252
11678
  }
11253
11679
  var includedAlready = targetEles.reduce(function (mem, element) {
11254
- if (mem || element.contains(mutation.target) || !mutation.target.parentElement) {
11680
+ if (mem || element.contains(target) || !target.parentElement) {
11255
11681
  return true;
11256
11682
  }
11257
11683
  return false;
11258
11684
  }, false);
11259
11685
  if (!includedAlready) {
11260
11686
  targetEles = targetEles.filter(function (element) {
11261
- return !mutation.target.contains(element);
11687
+ return !target.contains(element);
11262
11688
  });
11263
- targetEles.push(mutation.target);
11689
+ targetEles.push(target);
11264
11690
  }
11265
11691
  });
11266
11692
  if (triggerMutation) debouncedHandler();
@@ -11678,6 +12104,30 @@
11678
12104
  if (!results[2]) return '';
11679
12105
  return decodeURIComponent(results[2].replace(/\+/g, ' '));
11680
12106
  }
12107
+
12108
+ // Reading credentials from the URL query string is convenient for local
12109
+ // development (run `?apikey=...&projectId=...` against a demo page) but is
12110
+ // dangerous on deployed sites: an attacker-crafted link would cause the
12111
+ // victim's page to send translation data (saveMissing) to the attacker's
12112
+ // locize project, or to run against an attacker-chosen backend.
12113
+ // The feature is preserved, but a warning is emitted when the URL
12114
+ // overrides credential values on hosts that don't look like a local dev
12115
+ // environment, so maintainers can notice and decide whether to disable it.
12116
+ function isLocalDevHost() {
12117
+ if (typeof window === 'undefined' || !window.location) return false;
12118
+ var h = window.location.hostname;
12119
+ if (!h) return false;
12120
+ return h === 'localhost' || h === '127.0.0.1' || h === '::1' || h === '0.0.0.0' || h.endsWith('.localhost') || h.endsWith('.local');
12121
+ }
12122
+ var credentialWarningShown = false;
12123
+ function warnIfCredentialFromUrlOnProdHost(attr) {
12124
+ if (isLocalDevHost()) return;
12125
+ if (credentialWarningShown) return; // only once per page
12126
+ credentialWarningShown = true;
12127
+ if (typeof console !== 'undefined' && typeof console.warn === 'function') {
12128
+ console.warn('locizify: reading credential "' + attr + '" from URL query string on a non-local host. ' + 'An attacker-crafted link can replace your locize credentials, redirecting saveMissing writes ' + 'to an attacker-chosen project. Prefer configuring credentials via the ' + '<script id="locizify" apikey="..." projectid="..."> attributes instead.');
12129
+ }
12130
+ }
11681
12131
  var originalInit = i18next$1.init;
11682
12132
  i18next$1.init = function () {
11683
12133
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -11711,11 +12161,20 @@
11711
12161
  if (attr.toLowerCase() === 'autopilot' && value === '') value = true;
11712
12162
  if (value !== undefined && value !== null) backend[attr] = value;
11713
12163
  if (!value) {
11714
- value = getQsParameterByName$1(attr.toLowerCase());
12164
+ var lc = attr.toLowerCase();
12165
+ value = getQsParameterByName$1(lc);
11715
12166
  if (value === 'true') value = true;
11716
12167
  if (value === 'false') value = false;
11717
- if (attr.toLowerCase() === 'autopilot' && value === '') value = true;
11718
- if (value !== undefined && value !== null) backend[attr] = value;
12168
+ if (lc === 'autopilot' && value === '') value = true;
12169
+ if (value !== undefined && value !== null) {
12170
+ backend[attr] = value;
12171
+ // Credential-bearing attributes via URL on a non-local host is
12172
+ // risky — attacker-crafted links can replace your credentials.
12173
+ // Warn once per page load so maintainers notice.
12174
+ if (lc === 'apikey' || lc === 'projectid') {
12175
+ warnIfCredentialFromUrlOnProdHost(lc);
12176
+ }
12177
+ }
11719
12178
  }
11720
12179
  });
11721
12180
  if (backend.allowedAddOrUpdateHost) {
@@ -11731,8 +12190,14 @@
11731
12190
  // call orginal callback
11732
12191
  callback(err, t);
11733
12192
  }
12193
+
12194
+ // Accept `?apikey=` from the URL query string as a fallback. On non-local
12195
+ // hosts this is risky (attacker-crafted links can replace your credentials
12196
+ // and redirect saveMissing writes to an attacker-chosen project), so warn
12197
+ // once when it happens.
11734
12198
  if (!options.backend.apiKey && getQsParameterByName$1('apikey')) {
11735
12199
  options.backend.apiKey = getQsParameterByName$1('apikey');
12200
+ warnIfCredentialFromUrlOnProdHost('apikey');
11736
12201
  }
11737
12202
  if (!options.backend.autoPilot || options.backend.autoPilot === 'false') {
11738
12203
  return originalInit.call(i18next$1, _objectSpread2(_objectSpread2({}, options), enforce), handleI18nextInitialized);