dependabot[bot] opened a new pull request, #70409: URL: https://github.com/apache/airflow/pull/70409
Bumps [i18next](https://github.com/i18next/i18next) from 25.8.16 to 26.3.6. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/i18next/i18next/releases">i18next's releases</a>.</em></p> <blockquote> <h2>v26.3.6</h2> <ul> <li>fix: allow TypeScript 7 in the optional <code>typescript</code> peer dependency range (<code>^5 || ^6 || ^7</code>). With <code>[email protected]</code> in a project, <code>npm install</code> failed with an <code>ERESOLVE</code> peer conflict. The published types are TS7-compatible as-is: every <code>test/typescript</code> suite produces identical results under 6.0 and 7.0.2. Reported in <a href="https://redirect.github.com/i18next/react-i18next/issues/1927">react-i18next#1927</a>, thanks <a href="https://github.com/andikapradanaarif"><code>@andikapradanaarif</code></a>.</li> </ul> <h2>v26.3.5</h2> <ul> <li>fix: <code>$t()</code> nesting options blocks that span multiple lines are now parsed. <code>nest()</code> decided where the nested key ends by testing <code>match[1]</code> with <code>/{.*}/</code>, whose dot does not cross line breaks — so a <code>$t(key, { ... })</code> options object containing a newline was treated as having no options, mis-split as formatters, and the nested lookup ran without its options (placeholders stayed unresolved). The nesting regexp itself already matches newlines inside <code>$t(...)</code>; adding the <code>s</code> (dotAll) flag makes multiline options behave like the single-line form. Thanks <a href="https://github.com/spokodev"><code>@spokodev</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2440">#2440</a>).</li> <li>fix: <code>getUsedParamsDetails</code> (the <code>returnDetails: true</code> path) no longer mutates the passed <code>replace</code> object. It wrote <code>count</code> straight onto <code>options.replace</code> so the returned <code>usedParams</code> would include it — a caller reusing one <code>replace</code> object across <code>t()</code> calls then carried a stale <code>count</code> into later interpolations (e.g. a previous call's <code>count: 5</code> rendered instead of the current call's value). The details are now built from a copy; <code>usedParams</code> still includes <code>count</code>. Thanks <a href="https://github.com/spokodev"><code>@spokodev</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2441">#2441</a>).</li> <li>fix: with the default <code>skipOnVariables: true</code> + <code>escapeValue: true</code>, a <code>{{placeholder}}</code> carried inside an interpolated value now stays literal even when the value contains escapable characters. The skip logic advanced the regex <code>lastIndex</code> by the raw value length, but the escaped text written into the string is longer, so <code>lastIndex</code> landed inside the inserted value and a trailing <code>{{placeholder}}</code> in it got interpolated — leaking another in-scope variable that should have stayed literal (values without escapable characters were already skipped correctly). The advance now uses the escaped length that is actually written, and the regex-safe <code>$</code>-doubling is applied only at the <code>String.replace</code> call so it can't distort the length arithmetic. Thanks <a href="https://github.com/spokodev"><code>@spokodev</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2442">#2442</a>). </li> </ul> <h2>v26.3.4</h2> <ul> <li>fix(security): <code>deepExtend</code> (used by <code>addResourceBundle(..., deep, overwrite)</code>) no longer recurses into inherited properties. It checked key existence with the <code>in</code> operator, which walks the prototype chain, so a source key matching an inherited built-in (e.g. <code>hasOwnProperty</code>, <code>toString</code>) caused recursion into the shared <code>Object.prototype</code> function and, with <code>overwrite: true</code>, could overwrite e.g. <code>Object.prototype.hasOwnProperty.call</code> with a non-callable value — corrupting a shared built-in process-wide (DoS). Existence is now checked with <code>Object.prototype.hasOwnProperty.call</code>, so such keys are copied as plain own data instead. This complements the existing <code>__proto__</code>/<code>constructor</code> guard and is also strictly more correct for an own-property merge. Only affects applications that pass attacker-controlled data with <code>deep: true</code> and <code>overwr ite: true</code>; no standard backend/integration does this. Distinct from CVE-2026-48713 / CVE-2026-48714 (different packages, <code>setPath</code> mechanism). Thanks to zx (Jace) for the responsible disclosure.</li> </ul> <h2>v26.3.3</h2> <ul> <li>fix(types): selector <code>t($ => $.arr, { returnObjects: true, context })</code> on a JSON array of <strong>heterogeneous</strong> objects now preserves each element's full shape (e.g. <code>{ transKey1: string; transKey2: string }[]</code>) instead of collapsing to a union of partial element types. Two type-level causes: (1) <code>FilterKeys</code> evaluated the whole array element type at once, so <code>keyof (A | B)</code> only saw the keys common to every element — it now distributes over the object union and filters each element independently; (2) when TypeScript merges mismatched array element types it injects phantom optional <code>undefined</code> keys (e.g. <code>transKey1_withContext?: undefined</code> on elements that don't define it), which the context-detection helpers mistook for real context variants — they now skip keys typed as <code>undefined</code>. Also adds a dedicated <code>context</code> + <code>returnObjects: true</code> selector overload using <code>const Fn</code> + <code>ReturnType<Fn></code>, so <code>Target</code> is no longer collapsed to <code>unknown</code> via <code>ApplyTarget</code>. Resolves Problem 1 of <a href="https://redirect.github.com/i18next/i18next/issues/2398">#2398</a> (Problem 2 was already fixed on master). Thanks <a href="https://github.com/sauravgupta-dotcom"><code>@sauravgupta-dotcom</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2438">#2438</a>). Fixes <a href="https://redirect.github.com/i18next/i18next/issues/2398">#2398</a>.</li> </ul> <h2>v26.3.2</h2> <ul> <li>fix: chained formatters with a parenthesised option that contains the format separator (e.g. <code>join(separator: ', ')</code>) now work at <strong>any</strong> position in the chain, not just first. Previously the comma-in-parens reassembly only repaired <code>formats[0]</code>, so <code>{{v, uppercase, join(separator: ', ')}}</code> split the <code>join(...)</code> option on the inner comma and never rejoined it, producing corrupt output. Replaced the first-position-only repair with a position-independent pass that re-joins fragments until each open paren closes. Thanks <a href="https://github.com/spokodev"><code>@spokodev</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2437">#2437</a>).</li> </ul> <h2>v26.3.1</h2> <ul> <li>fix(types): <code>t()</code> with a <code>keyPrefix</code> no longer pollutes its return type with sibling keys' values. A regression in 26.3.0 — the <code>[Res] extends [never]</code> guards added to <code>KeysBuilderWithReturnObjects</code> / <code>KeysBuilderWithoutReturnObjects</code> turned the builders into deferred conditional types, so <code>KeyPrefix<Ns></code> stopped resolving to a literal union and <code>keyPrefix</code> inference widened to the whole namespace. Symptom: <code>useTranslation(ns, { keyPrefix: 'a.b' })</code> then <code>t('title')</code> would resolve to <code>'<a.b>.title' | '<other.path>.title' | ...</code> instead of just the scoped value. Affected every <code>react-i18next</code> user using <code>keyPrefix</code>. Restored to the eager 26.2.0 form. The same-namespace conflict handling from <a href="https://redirect.github.com/i18next/i18next/issues/2434">#2434</a> still works via <code>_DropConflictKeys</code> at the merge lay er (in <code>options.d.ts</code>). Thanks <a href="https://github.com/aaronrosenthal"><code>@aaronrosenthal</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2436">#2436</a>).</li> </ul> <h2>v26.3.0</h2> <ul> <li>feat(types): introduce <code>ResourceNamespaceMap</code> — a separate mergeable augmentation surface for namespace resource types, designed for monorepos where multiple packages each want to contribute their own namespaces. Previously, every package had to coordinate on a single <code>CustomTypeOptions.resources</code> declaration (or fall back to typing dependency namespaces as <code>any</code>) because <code>resources</code> is a single property of an interface and TypeScript reports TS2717 when two declarations of the same property disagree. The new interface merges naturally across <code>declare module 'i18next'</code> blocks, so each package can ship its own <code>i18next.d.ts</code> independently. Per-property merge handles same-namespace contributions from multiple packages, and same-key/different-literal conflicts are silently dropped to avoid poisoning <code>t()</code> overload resolution. Fully backwards-compatible — existing <code>CustomTypeOptions.resources</co de> augmentations continue to work, and both surfaces can coexist. Scalar options (<code>defaultNS</code>, <code>returnNull</code>, <code>enableSelector</code>, etc.) still belong on <code>CustomTypeOptions</code>. Thanks <a href="https://github.com/sh3xu"><code>@sh3xu</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2434">#2434</a>). Fixes <a href="https://redirect.github.com/i18next/i18next/issues/2409">#2409</a>.</li> </ul> <h2>v26.2.0</h2> <ul> <li>feat(types): new <code>parseInterpolation</code> TypeOption (default <code>true</code>). When set to <code>false</code> in <code>CustomTypeOptions</code>, the type-level extractor stops parsing translation strings for <code>{{variable}}</code> patterns. Required by <code>i18next-icu</code> users — the default extractor mistakes ICU MessageFormat nested-brace plurals like <code>{count, plural, one {{count} row} other {{count} rows}}</code> for an interpolation block and demands a phantom variable name. The flag is type-only; runtime interpolation is governed by <code>InterpolationOptions</code> and is unaffected. Fixes <a href="https://redirect.github.com/i18next/i18next-icu/issues/85">i18next-icu#85</a>.</li> <li>fix(types): expose <code>enableSelector</code> on <code>InitOptions</code> so <code>i18next.init({ enableSelector: 'strict' })</code> typechecks without a module augmentation. The runtime already reads <code>opts?.enableSelector</code> from init options; this lands the matching type declaration next to the other selector-resolution knobs. Accepts <code>false | true | 'optimize' | 'strict'</code>. Thanks <a href="https://github.com/Faithfinder"><code>@Faithfinder</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2431">#2431</a>)</li> </ul> <h2>v26.1.0</h2> <ul> <li>feat: <code>enableSelector: 'strict'</code> (TypeOptions + runtime option). Opt-in mode that drops the flattened-primary form from <code>NsResource</code> at the type level — every namespace (primary included) is exposed only under its own key on <code>$</code>, uniformly across single- and multi-ns hooks. At runtime, a leading selector path segment matching the scope's namespace list is always rewritten as a namespace prefix, including the primary. Eliminates the silent-miss surface area where <code>t($ => $.primary.foo)</code> typechecks but doesn't resolve under the default mode (see <a href="https://redirect.github.com/i18next/i18next/issues/2429">#2429</a>). Backward-compatible: default <code>enableSelector: false | true | 'optimize'</code> behavior is unchanged. Note: strict mode is incompatible with the <a href="https://redirect.github.com/i18next/i18next/issues/2405">#2405</a> pattern (keys whose names match sibling namespaces) — those users should stay on defau lt mode.</li> </ul> <h2>v26.0.10</h2> <ul> <li>feat: <code>getFixedT</code> accepts a fourth optional <code>fixedOpts</code> argument carrying <code>scopeNs</code> — the full namespace list the bound <code>t</code> was created for. The selector API uses <code>scopeNs</code> to detect when a path's first segment is a namespace prefix, <strong>without</strong> changing resolution scope. Resolution still uses the bound <code>ns</code> (a single primary string in the typical react-i18next setup), so plain <code>t('key')</code> lookups stay isolated to the primary namespace exactly as before — only <code>t($ => $.secondaryNs.foo)</code> selectors now route correctly under <code>useTranslation([nsA, nsB])</code>. Fixes the runtime side of <a href="https://redirect.github.com/i18next/i18next/issues/2429">#2429</a> for the <code>react-i18next</code> default-<code>nsMode</code> case. The 4th argument is opt-in: existing 3-arg <code>getFixedT(lng, ns, keyPrefix)</code> callers see no behavior change.</li> </ul> <h2>v26.0.9</h2> <ul> <li>fix(types): unformatted interpolation values are now typed as <code>string | number</code> (was <code>string</code>). i18next stringifies values at runtime, so requiring callers to wrap numbers in <code>String(...)</code> for plain <code>{{var}}</code> placeholders was unnecessary friction — and could mask the real problem when a non-string value was passed alongside multiple interpolation slots (the <code>t()</code> overload resolution would fall through to the 3-arg form and report a confusing "not assignable to string" error against the options object). Typed format specifiers like <code>{{x, number}}</code>, <code>{{x, currency}}</code>, <code>{{x, datetime}}</code>, etc. keep their precise types; this only relaxes the no-format default. The <code>count</code> variable remains <code>number</code>-only</li> </ul> <h2>v26.0.8</h2> <ul> <li>fix(types): restore the pre-v25.10.4 <code>ExistsFunction</code> shape so plain arrow functions can again be assigned to <code>ExistsFunction</code>-typed variables (TypeScript cannot infer type predicates through multi-overload assignment). Direct <code>i18next.exists(key)</code> calls still narrow <code>key</code> to <code>SelectorKey</code> — the predicate is now declared inline on <code>i18n.exists</code>. Custom wrappers that want the narrowing can type themselves as <code>typeof i18next.exists</code> <a href="https://redirect.github.com/i18next/i18next/issues/2425">2425</a></li> </ul> <h2>v26.0.7</h2> <ul> <li>fix: when a plural lookup misses, the <code>missingKey</code> debug log now shows the actual plural-resolved key (e.g. <code>foo.bar_many</code> for Polish <code>count: 14</code>) instead of the base key — making it obvious which plural category was expected and missing <a href="https://redirect.github.com/i18next/i18next/issues/2423">2423</a></li> <li>chore: drop <code>@babel/runtime</code> runtime dependency. The build no longer generates any <code>@babel/runtime</code> imports, so the package is unused by consumers. Rollup now uses <code>babelHelpers: 'bundled'</code> so any helpers that are ever needed in the future will be inlined rather than imported externally <a href="https://redirect.github.com/i18next/i18next/issues/2424">2424</a></li> <li>chore: stop emitting <code>dist/esm/i18next.bundled.js</code>. It was byte-identical to <code>dist/esm/i18next.js</code> because no helpers were being imported <a href="https://redirect.github.com/i18next/i18next/issues/2424">2424</a></li> </ul> <h2>v26.0.6</h2> <p>Security release — all issues found via an internal audit. GHSA advisory filed after release.</p> <ul> <li>security: warn when a translation string combines <code>escapeValue: false</code> with interpolated variables inside a <code>$t(key, { ... "{{var}}" ... })</code> nesting-options block. In that narrow combination, attacker-controlled string values containing <code>"</code> can break out of the JSON options literal and inject additional nesting options (e.g. redirect <code>lng</code>/<code>ns</code>). The default <code>escapeValue: true</code> configuration is unaffected because HTML-escaping neutralises the quote before <code>JSON.parse</code>. See the security docs for mitigation guidance (GHSA-TBD)</li> <li>security: apply <code>regexEscape</code> to <code>unescapePrefix</code> / <code>unescapeSuffix</code> on par with the other interpolation delimiters. Prevents ReDoS (catastrophic-backtracking) when a misconfigured delimiter contains regex metacharacters, and fixes silent breakage of the <code>{{- var}}</code> syntax when the delimiter contains characters like <code>(</code>, <code>[</code>, <code>.</code></li> <li>security: strip CR/LF/NUL and other C0/C1 control characters from string log arguments to prevent log forging via user-controlled translation keys, language codes, namespaces, or interpolation variable names (CWE-117)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/i18next/i18next/blob/master/CHANGELOG.md">i18next's changelog</a>.</em></p> <blockquote> <h2>26.3.6</h2> <ul> <li>fix: allow TypeScript 7 in the optional <code>typescript</code> peer dependency range (<code>^5 || ^6 || ^7</code>). With <code>[email protected]</code> in a project, <code>npm install</code> failed with an <code>ERESOLVE</code> peer conflict. The published types are TS7-compatible as-is: every <code>test/typescript</code> suite produces identical results under 6.0 and 7.0.2. Reported in <a href="https://redirect.github.com/i18next/react-i18next/issues/1927">react-i18next#1927</a>, thanks <a href="https://github.com/andikapradanaarif"><code>@andikapradanaarif</code></a>.</li> </ul> <h2>26.3.5</h2> <ul> <li>fix: <code>$t()</code> nesting options blocks that span multiple lines are now parsed. <code>nest()</code> decided where the nested key ends by testing <code>match[1]</code> with <code>/{.*}/</code>, whose dot does not cross line breaks — so a <code>$t(key, { ... })</code> options object containing a newline was treated as having no options, mis-split as formatters, and the nested lookup ran without its options (placeholders stayed unresolved). The nesting regexp itself already matches newlines inside <code>$t(...)</code>; adding the <code>s</code> (dotAll) flag makes multiline options behave like the single-line form. Thanks <a href="https://github.com/spokodev"><code>@spokodev</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2440">#2440</a>).</li> <li>fix: <code>getUsedParamsDetails</code> (the <code>returnDetails: true</code> path) no longer mutates the passed <code>replace</code> object. It wrote <code>count</code> straight onto <code>options.replace</code> so the returned <code>usedParams</code> would include it — a caller reusing one <code>replace</code> object across <code>t()</code> calls then carried a stale <code>count</code> into later interpolations (e.g. a previous call's <code>count: 5</code> rendered instead of the current call's value). The details are now built from a copy; <code>usedParams</code> still includes <code>count</code>. Thanks <a href="https://github.com/spokodev"><code>@spokodev</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2441">#2441</a>).</li> <li>fix: with the default <code>skipOnVariables: true</code> + <code>escapeValue: true</code>, a <code>{{placeholder}}</code> carried inside an interpolated value now stays literal even when the value contains escapable characters. The skip logic advanced the regex <code>lastIndex</code> by the raw value length, but the escaped text written into the string is longer, so <code>lastIndex</code> landed inside the inserted value and a trailing <code>{{placeholder}}</code> in it got interpolated — leaking another in-scope variable that should have stayed literal (values without escapable characters were already skipped correctly). The advance now uses the escaped length that is actually written, and the regex-safe <code>$</code>-doubling is applied only at the <code>String.replace</code> call so it can't distort the length arithmetic. Thanks <a href="https://github.com/spokodev"><code>@spokodev</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2442">#2442</a>). </li> </ul> <h2>26.3.4</h2> <ul> <li>fix(security): <code>deepExtend</code> (used by <code>addResourceBundle(..., deep, overwrite)</code>) no longer recurses into inherited properties. It checked key existence with the <code>in</code> operator, which walks the prototype chain, so a source key matching an inherited built-in (e.g. <code>hasOwnProperty</code>, <code>toString</code>) caused recursion into the shared <code>Object.prototype</code> function and, with <code>overwrite: true</code>, could overwrite e.g. <code>Object.prototype.hasOwnProperty.call</code> with a non-callable value — corrupting a shared built-in process-wide (DoS). Existence is now checked with <code>Object.prototype.hasOwnProperty.call</code>, so such keys are copied as plain own data instead. This complements the existing <code>__proto__</code>/<code>constructor</code> guard and is also strictly more correct for an own-property merge. Only affects applications that pass attacker-controlled data with <code>deep: true</code> and <code>overwr ite: true</code>; no standard backend/integration does this. Distinct from CVE-2026-48713 / CVE-2026-48714 (different packages, <code>setPath</code> mechanism). See advisory <a href="https://github.com/i18next/i18next/security/advisories/GHSA-6jcc-5g8w-32mx">GHSA-6jcc-5g8w-32mx</a>, CVSS 5.9 (<code>CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H</code>). Thanks to zx (Jace) <a href="https://github.com/manus-use"><code>@manus-use</code></a> for the responsible disclosure.</li> </ul> <h2>26.3.3</h2> <ul> <li>fix(types): selector <code>t($ => $.arr, { returnObjects: true, context })</code> on a JSON array of <strong>heterogeneous</strong> objects now preserves each element's full shape (e.g. <code>{ transKey1: string; transKey2: string }[]</code>) instead of collapsing to a union of partial element types. Two type-level causes: (1) <code>FilterKeys</code> evaluated the whole array element type at once, so <code>keyof (A | B)</code> only saw the keys common to every element — it now distributes over the object union and filters each element independently; (2) when TypeScript merges mismatched array element types it injects phantom optional <code>undefined</code> keys (e.g. <code>transKey1_withContext?: undefined</code> on elements that don't define it), which the context-detection helpers mistook for real context variants — they now skip keys typed as <code>undefined</code>. Also adds a dedicated <code>context</code> + <code>returnObjects: true</code> selector overload using <code>const Fn</code> + <code>ReturnType<Fn></code>, so <code>Target</code> is no longer collapsed to <code>unknown</code> via <code>ApplyTarget</code>. Resolves Problem 1 of <a href="https://redirect.github.com/i18next/i18next/issues/2398">#2398</a> (Problem 2 was already fixed on master). Thanks <a href="https://github.com/sauravgupta-dotcom"><code>@sauravgupta-dotcom</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2438">#2438</a>). Fixes <a href="https://redirect.github.com/i18next/i18next/issues/2398">#2398</a>.</li> </ul> <h2>26.3.2</h2> <ul> <li>fix: chained formatters with a parenthesised option that contains the format separator (e.g. <code>join(separator: ', ')</code>) now work at <strong>any</strong> position in the chain, not just first. Previously the comma-in-parens reassembly only repaired <code>formats[0]</code>, so <code>{{v, uppercase, join(separator: ', ')}}</code> split the <code>join(...)</code> option on the inner comma and never rejoined it, producing corrupt output. Replaced the first-position-only repair with a position-independent pass that re-joins fragments until each open paren closes. Thanks <a href="https://github.com/spokodev"><code>@spokodev</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2437">#2437</a>).</li> </ul> <h2>26.3.1</h2> <ul> <li>fix(types): <code>t()</code> with a <code>keyPrefix</code> no longer pollutes its return type with sibling keys' values. A regression in 26.3.0 — the <code>[Res] extends [never]</code> guards added to <code>KeysBuilderWithReturnObjects</code> / <code>KeysBuilderWithoutReturnObjects</code> turned the builders into deferred conditional types, so <code>KeyPrefix<Ns></code> stopped resolving to a literal union and <code>keyPrefix</code> inference widened to the whole namespace. Symptom: <code>useTranslation(ns, { keyPrefix: 'a.b' })</code> then <code>t('title')</code> would resolve to <code>'<a.b>.title' | '<other.path>.title' | ...</code> instead of just the scoped value. Affected every <code>react-i18next</code> user using <code>keyPrefix</code>. Restored to the eager 26.2.0 form. The same-namespace conflict handling from <a href="https://redirect.github.com/i18next/i18next/issues/2434">#2434</a> still works via <code>_DropConflictKeys</code> at the merge lay er (in <code>options.d.ts</code>). Thanks <a href="https://github.com/aaronrosenthal"><code>@aaronrosenthal</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2436">#2436</a>).</li> </ul> <h2>26.3.0</h2> <ul> <li>feat(types): introduce <code>ResourceNamespaceMap</code> — a separate mergeable augmentation surface for namespace resource types, designed for monorepos where multiple packages each want to contribute their own namespaces. Previously, every package had to coordinate on a single <code>CustomTypeOptions.resources</code> declaration (or fall back to typing dependency namespaces as <code>any</code>) because <code>resources</code> is a single property of an interface and TypeScript reports TS2717 when two declarations of the same property disagree. The new interface merges naturally across <code>declare module 'i18next'</code> blocks, so each package can ship its own <code>i18next.d.ts</code> independently. Per-property merge handles same-namespace contributions from multiple packages, and same-key/different-literal conflicts are silently dropped to avoid poisoning <code>t()</code> overload resolution. Fully backwards-compatible — existing <code>CustomTypeOptions.resources</co de> augmentations continue to work, and both surfaces can coexist. Scalar options (<code>defaultNS</code>, <code>returnNull</code>, <code>enableSelector</code>, etc.) still belong on <code>CustomTypeOptions</code>. Thanks <a href="https://github.com/sh3xu"><code>@sh3xu</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2434">#2434</a>). Fixes <a href="https://redirect.github.com/i18next/i18next/issues/2409">#2409</a>.</li> </ul> <h2>26.2.0</h2> <ul> <li>feat(types): new <code>parseInterpolation</code> TypeOption (default <code>true</code>). When set to <code>false</code> in <code>CustomTypeOptions</code>, the type-level extractor stops parsing translation strings for <code>{{variable}}</code> patterns. Required by <code>i18next-icu</code> users — the default extractor mistakes ICU MessageFormat nested-brace plurals like <code>{count, plural, one {{count} row} other {{count} rows}}</code> for an interpolation block and demands a phantom variable name. The flag is type-only; runtime interpolation is governed by <code>InterpolationOptions</code> and is unaffected. Fixes <a href="https://redirect.github.com/i18next/i18next-icu/issues/85">i18next-icu#85</a>.</li> <li>fix(types): expose <code>enableSelector</code> on <code>InitOptions</code> so <code>i18next.init({ enableSelector: 'strict' })</code> typechecks without a module augmentation. The runtime already reads <code>opts?.enableSelector</code> from init options; this lands the matching type declaration next to the other selector-resolution knobs. Accepts <code>false | true | 'optimize' | 'strict'</code>. Thanks <a href="https://github.com/Faithfinder"><code>@Faithfinder</code></a> (<a href="https://redirect.github.com/i18next/i18next/pull/2431">#2431</a>)</li> </ul> <h2>26.1.0</h2> <ul> <li>feat: <code>enableSelector: 'strict'</code> (TypeOptions + runtime option). Opt-in mode that drops the flattened-primary form from <code>NsResource</code> at the type level — every namespace (primary included) is exposed only under its own key on <code>$</code>, uniformly across single- and multi-ns hooks. At runtime, a leading selector path segment matching the scope's namespace list is always rewritten as a namespace prefix, including the primary. Eliminates the silent-miss surface area where <code>t($ => $.primary.foo)</code> typechecks but doesn't resolve under the default mode (see <a href="https://redirect.github.com/i18next/i18next/issues/2429">#2429</a>). Backward-compatible: default <code>enableSelector: false | true | 'optimize'</code> behavior is unchanged. Note: strict mode is incompatible with the <a href="https://redirect.github.com/i18next/i18next/issues/2405">#2405</a> pattern (keys whose names match sibling namespaces) — those users should stay on defau lt mode.</li> </ul> <h2>26.0.10</h2> <ul> <li>feat: <code>getFixedT</code> accepts a fourth optional <code>fixedOpts</code> argument carrying <code>scopeNs</code> — the full namespace list the bound <code>t</code> was created for. The selector API uses <code>scopeNs</code> to detect when a path's first segment is a namespace prefix, <strong>without</strong> changing resolution scope. Resolution still uses the bound <code>ns</code> (a single primary string in the typical react-i18next setup), so plain <code>t('key')</code> lookups stay isolated to the primary namespace exactly as before — only <code>t($ => $.secondaryNs.foo)</code> selectors now route correctly under <code>useTranslation([nsA, nsB])</code>. Fixes the runtime side of <a href="https://redirect.github.com/i18next/i18next/issues/2429">#2429</a> for the <code>react-i18next</code> default-<code>nsMode</code> case. The 4th argument is opt-in: existing 3-arg <code>getFixedT(lng, ns, keyPrefix)</code> callers see no behavior change.</li> </ul> <h2>26.0.9</h2> <ul> <li>fix(types): unformatted interpolation values are now typed as <code>string | number</code> (was <code>string</code>). i18next stringifies values at runtime, so requiring callers to wrap numbers in <code>String(...)</code> for plain <code>{{var}}</code> placeholders was unnecessary friction — and could mask the real problem when a non-string value was passed alongside multiple interpolation slots (the <code>t()</code> overload resolution would fall through to the 3-arg form and report a confusing "not assignable to string" error against the options object). Typed format specifiers like <code>{{x, number}}</code>, <code>{{x, currency}}</code>, <code>{{x, datetime}}</code>, etc. keep their precise types; this only relaxes the no-format default. The <code>count</code> variable remains <code>number</code>-only</li> </ul> <h2>26.0.8</h2> <ul> <li>fix(types): restore the pre-v25.10.4 <code>ExistsFunction</code> shape so plain arrow functions can again be assigned to <code>ExistsFunction</code>-typed variables (TypeScript cannot infer type predicates through multi-overload assignment). Direct <code>i18next.exists(key)</code> calls still narrow <code>key</code> to <code>SelectorKey</code> — the predicate is now declared inline on <code>i18n.exists</code>. Custom wrappers that want the narrowing can type themselves as <code>typeof i18next.exists</code> <a href="https://redirect.github.com/i18next/i18next/issues/2425">2425</a></li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/i18next/i18next/commit/e1c60d4dd28a16f91be7f55b3685ffcf9760619b"><code>e1c60d4</code></a> 26.3.6</li> <li><a href="https://github.com/i18next/i18next/commit/04da43e08cb799f2e6f9a5578f3674fe2ef49595"><code>04da43e</code></a> fix: allow typescript 7 in optional peerDependencies range (react-i18next#1927)</li> <li><a href="https://github.com/i18next/i18next/commit/8eed4accc6c69398e9e25f79b617249fd3f7b1ec"><code>8eed4ac</code></a> build</li> <li><a href="https://github.com/i18next/i18next/commit/573ae735682a082ad5a581dea3f2d5f517c53772"><code>573ae73</code></a> 26.3.5</li> <li><a href="https://github.com/i18next/i18next/commit/cc54b05b5cab9bf76cf66557c222c978bbb3c082"><code>cc54b05</code></a> docs(changelog): 26.3.5 — multiline $t() options, replace mutation, escaped-l...</li> <li><a href="https://github.com/i18next/i18next/commit/3180d67291a8fff10950f79660420c106c047f94"><code>3180d67</code></a> fix: skip interpolation of placeholders inside escaped values (<a href="https://redirect.github.com/i18next/i18next/issues/2442">#2442</a>)</li> <li><a href="https://github.com/i18next/i18next/commit/d16f5a2da748082155007ba0677d32b877b1102e"><code>d16f5a2</code></a> fix: stop mutating the passed replace object when returning details (<a href="https://redirect.github.com/i18next/i18next/issues/2441">#2441</a>)</li> <li><a href="https://github.com/i18next/i18next/commit/bed56c115979de52bd85c46d9b7a7b13361bf736"><code>bed56c1</code></a> fix: parse $t() nesting options block that spans multiple lines (<a href="https://redirect.github.com/i18next/i18next/issues/2440">#2440</a>)</li> <li><a href="https://github.com/i18next/i18next/commit/c19e45864f3abbbe90e30be44cc131f2248394bf"><code>c19e458</code></a> docs(changelog): link GHSA advisory for deepExtend fix</li> <li><a href="https://github.com/i18next/i18next/commit/7bb87d09f907b4395ed0825638d7d2c4356f7a89"><code>7bb87d0</code></a> docs(changelog): reference security advisory for deepExtend fix</li> <li>Additional commits viewable in <a href="https://github.com/i18next/i18next/compare/v25.8.16...v26.3.6">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
