react-i18next 17.0.10 → 17.0.12

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.
package/react-i18next.js CHANGED
@@ -917,6 +917,10 @@
917
917
  this.options = options;
918
918
  this.supportedLngs = this.options.supportedLngs || false;
919
919
  this.logger = baseLogger.create('languageUtils');
920
+ this.resolveHierarchyCache = {};
921
+ }
922
+ clearCache() {
923
+ this.resolveHierarchyCache = {};
920
924
  }
921
925
  getScriptPartFromCode(code) {
922
926
  code = getCleanedCode(code);
@@ -997,6 +1001,25 @@
997
1001
  return found || [];
998
1002
  }
999
1003
  toResolveHierarchy(code, fallbackCode) {
1004
+ const fallbackLng = this.options.fallbackLng;
1005
+ const fallbackLngKey = Array.isArray(fallbackLng) ? fallbackLng.join('|') : fallbackLng;
1006
+ if (fallbackLngKey !== this._cachedFallbackLng) {
1007
+ this.resolveHierarchyCache = {};
1008
+ this._cachedFallbackLng = fallbackLngKey;
1009
+ }
1010
+ const hasCacheableFallback = fallbackCode === undefined || fallbackCode === false || isString$1(fallbackCode);
1011
+ const usesUncacheableOptionsFallback = fallbackCode === undefined && typeof this.options.fallbackLng === 'function';
1012
+ const cacheable = isString$1(code) && hasCacheableFallback && !usesUncacheableOptionsFallback;
1013
+ let cacheKey = null;
1014
+ if (cacheable) {
1015
+ let fallbackCacheKey;
1016
+ if (fallbackCode === undefined) fallbackCacheKey = 'undefined';else if (fallbackCode === false) fallbackCacheKey = 'boolean:false';else fallbackCacheKey = `string:${fallbackCode}`;
1017
+ cacheKey = `${code.length}:${code}|${fallbackCacheKey}`;
1018
+ }
1019
+ if (cacheKey !== null) {
1020
+ const cached = this.resolveHierarchyCache[cacheKey];
1021
+ if (cached !== undefined) return cached.slice();
1022
+ }
1000
1023
  const fallbackCodes = this.getFallbackCodes((fallbackCode === false ? [] : fallbackCode) || this.options.fallbackLng || [], code);
1001
1024
  const codes = [];
1002
1025
  const addCode = c => {
@@ -1017,6 +1040,10 @@
1017
1040
  fallbackCodes.forEach(fc => {
1018
1041
  if (!codes.includes(fc)) addCode(this.formatLanguageCode(fc));
1019
1042
  });
1043
+ if (cacheKey !== null) {
1044
+ this.resolveHierarchyCache[cacheKey] = codes;
1045
+ return codes.slice();
1046
+ }
1020
1047
  return codes;
1021
1048
  }
1022
1049
  }
@@ -2245,127 +2272,318 @@
2245
2272
  instance.loadNamespaces;
2246
2273
  instance.loadLanguages;
2247
2274
 
2248
- function getDefaultExportFromCjs (x) {
2249
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
2275
+ const voidElements = {
2276
+ area: true,
2277
+ base: true,
2278
+ br: true,
2279
+ col: true,
2280
+ embed: true,
2281
+ hr: true,
2282
+ img: true,
2283
+ input: true,
2284
+ link: true,
2285
+ meta: true,
2286
+ param: true,
2287
+ source: true,
2288
+ track: true,
2289
+ wbr: true,
2290
+ '!doctype': true,
2291
+ '!DOCTYPE': true
2292
+ };
2293
+ const attrRE = /\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?("[^"]*"|'[^']*')/g;
2294
+ function parseTag(tag) {
2295
+ const res = {
2296
+ type: 'tag',
2297
+ name: '',
2298
+ voidElement: false,
2299
+ attrs: {},
2300
+ children: []
2301
+ };
2302
+ const tagMatch = tag.match(/<\/?([^\s]+?)[/\s>]/);
2303
+ if (tagMatch) {
2304
+ res.name = tagMatch[1];
2305
+ if (voidElements[tagMatch[1]] || tag.charAt(tag.length - 2) === '/') {
2306
+ res.voidElement = true;
2307
+ }
2308
+ if (res.name.startsWith('!--')) {
2309
+ const endIndex = tag.indexOf('-->');
2310
+ return {
2311
+ type: 'comment',
2312
+ comment: endIndex !== -1 ? tag.slice(4, endIndex) : ''
2313
+ };
2314
+ }
2315
+ }
2316
+ const reg = new RegExp(attrRE);
2317
+ let result = null;
2318
+ for (;;) {
2319
+ result = reg.exec(tag);
2320
+ if (result === null) {
2321
+ break;
2322
+ }
2323
+ if (!result[0].trim()) {
2324
+ continue;
2325
+ }
2326
+ if (result[1]) {
2327
+ const attr = result[1].trim();
2328
+ let arr = [attr, null];
2329
+ const eq = attr.indexOf('=');
2330
+ if (eq > -1) {
2331
+ arr = [attr.slice(0, eq), attr.slice(eq + 1)];
2332
+ }
2333
+ res.attrs[arr[0]] = arr[1];
2334
+ reg.lastIndex--;
2335
+ } else if (result[2]) {
2336
+ res.attrs[result[2]] = result[3].trim().substring(1, result[3].length - 1);
2337
+ }
2338
+ }
2339
+ return res;
2250
2340
  }
2251
-
2252
- var voidElements;
2253
- var hasRequiredVoidElements;
2254
-
2255
- function requireVoidElements () {
2256
- if (hasRequiredVoidElements) return voidElements;
2257
- hasRequiredVoidElements = 1;
2258
- voidElements = {
2259
- "area": true,
2260
- "base": true,
2261
- "br": true,
2262
- "col": true,
2263
- "embed": true,
2264
- "hr": true,
2265
- "img": true,
2266
- "input": true,
2267
- "link": true,
2268
- "meta": true,
2269
- "param": true,
2270
- "source": true,
2271
- "track": true,
2272
- "wbr": true
2273
- };
2274
- return voidElements;
2341
+ const tagRE = /<!--[\s\S]*?-->|<[a-zA-Z0-9\-!/](?:"[^"]*"|'[^']*'|[^'">])*>/g;
2342
+ const tagNameRE = /<\/?([^\s]+?)[/\s>]/;
2343
+ const whitespaceRE = /^\s*$/;
2344
+ const rawTextRE = /^(script|style)$/i;
2345
+ const sentinel = '\u0000';
2346
+ const empty = Object.create(null);
2347
+ function restoreSentinels(nodes) {
2348
+ nodes.forEach(function (node) {
2349
+ if (node.type === 'text') {
2350
+ node.content = node.content.split(sentinel).join('<');
2351
+ return;
2352
+ }
2353
+ if (node.type === 'comment') {
2354
+ node.comment = node.comment.split(sentinel).join('<');
2355
+ return;
2356
+ }
2357
+ for (const key in node.attrs) {
2358
+ const value = node.attrs[key];
2359
+ if (typeof value === 'string' && value.indexOf(sentinel) > -1) {
2360
+ node.attrs[key] = value.split(sentinel).join('<');
2361
+ }
2362
+ }
2363
+ if (node.children.length) {
2364
+ restoreSentinels(node.children);
2365
+ }
2366
+ });
2275
2367
  }
2276
-
2277
- var voidElementsExports = requireVoidElements();
2278
- var e = /*@__PURE__*/getDefaultExportFromCjs(voidElementsExports);
2279
-
2280
- var t = /\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;
2281
- function n(n) {
2282
- var r = {
2283
- type: "tag",
2284
- name: "",
2285
- voidElement: false,
2286
- attrs: {},
2287
- children: []
2288
- },
2289
- i = n.match(/<\/?([^\s]+?)[/\s>]/);
2290
- if (i && (r.name = i[1], (e[i[1]] || "/" === n.charAt(n.length - 2)) && (r.voidElement = true), r.name.startsWith("!--"))) {
2291
- var s = n.indexOf("--\x3e");
2292
- return {
2293
- type: "comment",
2294
- comment: -1 !== s ? n.slice(4, s) : ""
2368
+ function parse(html, options) {
2369
+ const components = options && options.components || empty;
2370
+ const allowedTags = options && options.allowedTags;
2371
+ let restoreNeeded = false;
2372
+ if (allowedTags) {
2373
+ const isAllowed = typeof allowedTags === 'function' ? allowedTags : function (name) {
2374
+ return allowedTags.indexOf(name) > -1;
2295
2375
  };
2376
+ let out = '';
2377
+ let pos = 0;
2378
+ tagRE.lastIndex = 0;
2379
+ let am;
2380
+ while (am = tagRE.exec(html)) {
2381
+ const tag = am[0];
2382
+ out += html.slice(pos, am.index);
2383
+ const nameMatch = tag.match(tagNameRE);
2384
+ if (tag.startsWith('<!--') || nameMatch && isAllowed(nameMatch[1])) {
2385
+ out += tag;
2386
+ pos = am.index + tag.length;
2387
+ } else {
2388
+ restoreNeeded = true;
2389
+ out += sentinel;
2390
+ pos = am.index + 1;
2391
+ tagRE.lastIndex = pos;
2392
+ }
2393
+ }
2394
+ html = out + html.slice(pos);
2296
2395
  }
2297
- for (var a = new RegExp(t), c = null; null !== (c = a.exec(n));) if (c[0].trim()) if (c[1]) {
2298
- var o = c[1].trim(),
2299
- l = [o, ""];
2300
- o.indexOf("=") > -1 && (l = o.split("=")), r.attrs[l[0]] = l[1], a.lastIndex--;
2301
- } else c[2] && (r.attrs[c[2]] = c[3].trim().substring(1, c[3].length - 1));
2302
- return r;
2303
- }
2304
- var r = /<[a-zA-Z0-9\-\!\/](?:"[^"]*"|'[^']*'|[^'">])*>/g,
2305
- i = /^\s*$/,
2306
- s = Object.create(null);
2307
- function a(e, t) {
2308
- switch (t.type) {
2309
- case "text":
2310
- return e + t.content;
2311
- case "tag":
2312
- return e += "<" + t.name + (t.attrs ? function (e) {
2313
- var t = [];
2314
- for (var n in e) t.push(n + '="' + e[n] + '"');
2315
- return t.length ? " " + t.join(" ") : "";
2316
- }(t.attrs) : "") + (t.voidElement ? "/>" : ">"), t.voidElement ? e : e + t.children.reduce(a, "") + "</" + t.name + ">";
2317
- case "comment":
2318
- return e + "\x3c!--" + t.comment + "--\x3e";
2396
+ const result = [];
2397
+ const arr = [];
2398
+ let current;
2399
+ let level = -1;
2400
+ let inComponent = false;
2401
+ let rawUntil = 0;
2402
+ let htmlLower;
2403
+ if (html.indexOf('<') !== 0) {
2404
+ const end = html.indexOf('<');
2405
+ result.push({
2406
+ type: 'text',
2407
+ content: end === -1 ? html : html.substring(0, end)
2408
+ });
2319
2409
  }
2320
- }
2321
- var c = {
2322
- parse: function (e, t) {
2323
- t || (t = {}), t.components || (t.components = s);
2324
- var a,
2325
- c = [],
2326
- o = [],
2327
- l = -1,
2328
- m = false;
2329
- if (0 !== e.indexOf("<")) {
2330
- var u = e.indexOf("<");
2331
- c.push({
2332
- type: "text",
2333
- content: -1 === u ? e : e.substring(0, u)
2334
- });
2410
+ const matches = [];
2411
+ let m;
2412
+ while (m = tagRE.exec(html)) {
2413
+ matches.push(m);
2414
+ }
2415
+ matches.forEach(function (match, i) {
2416
+ const tag = match[0];
2417
+ if (!tag) return;
2418
+ if (tag.startsWith('<!--')) return;
2419
+ let lts = 0;
2420
+ let gts = 0;
2421
+ let secondLt = -1;
2422
+ let quote = null;
2423
+ for (let j = 0; j < tag.length; j++) {
2424
+ const c = tag.charAt(j);
2425
+ if (quote) {
2426
+ if (c === quote) quote = null;
2427
+ } else if (c === '"' || c === "'") {
2428
+ quote = c;
2429
+ } else if (c === '<') {
2430
+ lts++;
2431
+ if (lts === 2) secondLt = j;
2432
+ } else if (c === '>') {
2433
+ gts++;
2434
+ }
2435
+ }
2436
+ const validSplit = secondLt > -1 && /[a-zA-Z0-9\-!/]/.test(tag.charAt(secondLt + 1));
2437
+ if (lts > gts && validSplit) {
2438
+ const firstPart = tag.substring(0, secondLt);
2439
+ const secondPart = tag.substring(firstPart.length);
2440
+ matches[i][0] = secondPart;
2441
+ matches[i].index += firstPart.length;
2335
2442
  }
2336
- return e.replace(r, function (r, s) {
2337
- if (m) {
2338
- if (r !== "</" + a.name + ">") return;
2339
- m = false;
2340
- }
2341
- var u,
2342
- f = "/" !== r.charAt(1),
2343
- h = r.startsWith("\x3c!--"),
2344
- p = s + r.length,
2345
- d = e.charAt(p);
2346
- if (h) {
2347
- var v = n(r);
2348
- return l < 0 ? (c.push(v), c) : ((u = o[l]).children.push(v), c);
2349
- }
2350
- if (f && (l++, "tag" === (a = n(r)).type && t.components[a.name] && (a.type = "component", m = true), a.voidElement || m || !d || "<" === d || a.children.push({
2351
- type: "text",
2352
- content: e.slice(p, e.indexOf("<", p))
2353
- }), 0 === l && c.push(a), (u = o[l - 1]) && u.children.push(a), o[l] = a), (!f || a.voidElement) && (l > -1 && (a.voidElement || a.name === r.slice(2, -1)) && (l--, a = -1 === l ? c : o[l]), !m && "<" !== d && d)) {
2354
- u = -1 === l ? c : o[l].children;
2355
- var x = e.indexOf("<", p),
2356
- g = e.slice(p, -1 === x ? void 0 : x);
2357
- i.test(g) && (g = " "), (x > -1 && l + u.length >= 0 || " " !== g) && u.push({
2358
- type: "text",
2359
- content: g
2443
+ });
2444
+ matches.forEach(function (match, i) {
2445
+ const tag = match[0];
2446
+ if (!tag) return;
2447
+ const index = match.index;
2448
+ if (index < rawUntil) return;
2449
+ if (inComponent) {
2450
+ if (tag !== '</' + current.name + '>') {
2451
+ return;
2452
+ } else {
2453
+ inComponent = false;
2454
+ }
2455
+ }
2456
+ const isOpen = tag.charAt(1) !== '/';
2457
+ const isComment = tag.startsWith('<!--');
2458
+ const start = index + tag.length;
2459
+ const nextChar = html.charAt(start);
2460
+ const nextMatch = matches[i + 1];
2461
+ let isText;
2462
+ if (nextChar === '<' && nextMatch) {
2463
+ const nextTag = html.substring(start, nextMatch.index);
2464
+ isText = nextTag.split('<').length > nextTag.split('>').length;
2465
+ }
2466
+ let parent;
2467
+ if (isComment) {
2468
+ const comment = parseTag(tag);
2469
+ if (level < 0) {
2470
+ result.push(comment);
2471
+ return result;
2472
+ }
2473
+ parent = arr[level];
2474
+ parent.children.push(comment);
2475
+ const text = html.slice(start, nextMatch ? nextMatch.index : undefined);
2476
+ if (text.length > 0) {
2477
+ parent.children.push({
2478
+ type: 'text',
2479
+ content: text
2360
2480
  });
2361
2481
  }
2362
- }), c;
2363
- },
2364
- stringify: function (e) {
2365
- return e.reduce(function (e, t) {
2366
- return e + a("", t);
2367
- }, "");
2482
+ return result;
2483
+ }
2484
+ if (isOpen) {
2485
+ level++;
2486
+ current = parseTag(tag);
2487
+ if (current.type === 'tag' && components[current.name]) {
2488
+ current.type = 'component';
2489
+ inComponent = true;
2490
+ }
2491
+ let isRawText = false;
2492
+ if (!inComponent && !current.voidElement && rawTextRE.test(current.name)) {
2493
+ isRawText = true;
2494
+ htmlLower || (htmlLower = html.toLowerCase());
2495
+ const closeIndex = htmlLower.indexOf('</' + current.name.toLowerCase() + '>', start);
2496
+ const contentEnd = closeIndex === -1 ? html.length : closeIndex;
2497
+ const content = html.slice(start, contentEnd);
2498
+ if (content) {
2499
+ current.children.push({
2500
+ type: 'text',
2501
+ content
2502
+ });
2503
+ }
2504
+ rawUntil = contentEnd;
2505
+ }
2506
+ if (!current.voidElement && !inComponent && !isRawText && nextChar && nextChar !== '<') {
2507
+ current.children.push({
2508
+ type: 'text',
2509
+ content: html.slice(start, nextMatch ? nextMatch.index : undefined)
2510
+ });
2511
+ }
2512
+ if (level === 0) {
2513
+ result.push(current);
2514
+ }
2515
+ parent = arr[level - 1];
2516
+ if (parent) {
2517
+ parent.children.push(current);
2518
+ }
2519
+ arr[level] = current;
2520
+ }
2521
+ if (!isOpen || current.voidElement) {
2522
+ if (level > -1 && (current.voidElement || current.name === tag.slice(2, -1))) {
2523
+ level--;
2524
+ current = level === -1 ? result : arr[level];
2525
+ }
2526
+ if (!inComponent && (nextChar !== '<' || isText) && nextChar) {
2527
+ parent = level === -1 ? result : arr[level].children;
2528
+ const end = nextMatch ? nextMatch.index : -1;
2529
+ let content = html.slice(start, end === -1 ? undefined : end);
2530
+ if (whitespaceRE.test(content)) {
2531
+ content = ' ';
2532
+ }
2533
+ if (end > -1 && level + parent.length >= 0 || content !== ' ') {
2534
+ parent.push({
2535
+ type: 'text',
2536
+ content
2537
+ });
2538
+ }
2539
+ }
2540
+ }
2541
+ });
2542
+ if (restoreNeeded) {
2543
+ restoreSentinels(result);
2544
+ }
2545
+ return result;
2546
+ }
2547
+ function attrString(attrs) {
2548
+ const buff = [];
2549
+ for (const key in attrs) {
2550
+ if (attrs[key] === null) {
2551
+ buff.push(key);
2552
+ } else {
2553
+ buff.push(key + '="' + String(attrs[key]).replace(/"/g, '&quot;') + '"');
2554
+ }
2368
2555
  }
2556
+ if (!buff.length) {
2557
+ return '';
2558
+ }
2559
+ return ' ' + buff.join(' ');
2560
+ }
2561
+ function stringifyNode(buff, doc) {
2562
+ switch (doc.type) {
2563
+ case 'text':
2564
+ return buff + doc.content;
2565
+ case 'tag':
2566
+ {
2567
+ const tagEnd = doc.voidElement && doc.name.toLowerCase() !== '!doctype' ? '/>' : '>';
2568
+ buff += '<' + doc.name + (doc.attrs ? attrString(doc.attrs) : '') + tagEnd;
2569
+ if (doc.voidElement) {
2570
+ return buff;
2571
+ }
2572
+ return buff + doc.children.reduce(stringifyNode, '') + '</' + doc.name + '>';
2573
+ }
2574
+ case 'comment':
2575
+ buff += '<!--' + doc.comment + '-->';
2576
+ return buff;
2577
+ }
2578
+ }
2579
+ function stringify(doc) {
2580
+ return doc.reduce(function (token, rootEl) {
2581
+ return token + stringifyNode('', rootEl);
2582
+ }, '');
2583
+ }
2584
+ var index = {
2585
+ parse,
2586
+ stringify
2369
2587
  };
2370
2588
 
2371
2589
  const warn = (i18n, code, msg, rest) => {
@@ -2583,46 +2801,6 @@
2583
2801
  });
2584
2802
  return stringNode;
2585
2803
  };
2586
- const escapeLiteralLessThan = (str, keepArray = [], knownComponentsMap = {}) => {
2587
- if (!str) return str;
2588
- const knownNames = Object.keys(knownComponentsMap);
2589
- const allValidNames = [...keepArray, ...knownNames];
2590
- let result = '';
2591
- let i = 0;
2592
- while (i < str.length) {
2593
- if (str[i] === '<') {
2594
- let isValidTag = false;
2595
- const closingMatch = str.slice(i).match(/^<\/(\d+|[a-zA-Z][a-zA-Z0-9_-]*)>/);
2596
- if (closingMatch) {
2597
- const tagName = closingMatch[1];
2598
- if (/^\d+$/.test(tagName) || allValidNames.includes(tagName)) {
2599
- isValidTag = true;
2600
- result += closingMatch[0];
2601
- i += closingMatch[0].length;
2602
- }
2603
- }
2604
- if (!isValidTag) {
2605
- const openingMatch = str.slice(i).match(/^<(\d+|[a-zA-Z][a-zA-Z0-9_-]*)(\s+[\w-]+(?:=(?:"[^"]*"|'[^']*'|[^\s>]+))?)*\s*(\/)?>/);
2606
- if (openingMatch) {
2607
- const tagName = openingMatch[1];
2608
- if (/^\d+$/.test(tagName) || allValidNames.includes(tagName)) {
2609
- isValidTag = true;
2610
- result += openingMatch[0];
2611
- i += openingMatch[0].length;
2612
- }
2613
- }
2614
- }
2615
- if (!isValidTag) {
2616
- result += '&lt;';
2617
- i += 1;
2618
- }
2619
- } else {
2620
- result += str[i];
2621
- i += 1;
2622
- }
2623
- }
2624
- return result;
2625
- };
2626
2804
  const renderNodes = (children, knownComponentsMap, targetString, i18n, i18nOptions, combinedTOpts, shouldUnescape) => {
2627
2805
  if (targetString === '') return [];
2628
2806
  const keepArray = i18nOptions.transKeepBasicHtmlNodesFor || [];
@@ -2637,8 +2815,11 @@
2637
2815
  });
2638
2816
  };
2639
2817
  getData(children);
2640
- const escapedString = escapeLiteralLessThan(targetString, keepArray, data);
2641
- const ast = c.parse(`<0>${escapedString}</0>`);
2818
+ const knownNames = Object.keys(data);
2819
+ const allowedTags = name => /^\d+$/.test(name) || keepArray.indexOf(name) > -1 || knownNames.indexOf(name) > -1;
2820
+ const ast = index.parse(`<0>${targetString}</0>`, {
2821
+ allowedTags
2822
+ });
2642
2823
  const opts = {
2643
2824
  ...data,
2644
2825
  ...combinedTOpts
@@ -3418,7 +3599,7 @@
3418
3599
  ...i18n.options.interpolation.defaultVariables
3419
3600
  };
3420
3601
  }
3421
- const translation = t(i18nKey, {
3602
+ const translation = t(i18nKey || defaultTranslation, {
3422
3603
  defaultValue: defaultTranslation,
3423
3604
  ...mergedValues,
3424
3605
  ns: namespaces