dependabot[bot] 2c28ac3089 Bump i18next from 26.0.3 to 26.3.4 in /frontend (#1769)
Bumps [i18next](https://github.com/i18next/i18next) from 26.0.3 to
26.3.4.
<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.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>overwrite: 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($ =&gt; $.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&lt;Fn&gt;</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&lt;Ns&gt;</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>'&lt;a.b&gt;.title' | '&lt;other.path&gt;.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 layer (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</code>
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($ =&gt; $.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 default 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($ =&gt; $.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 &quot;not assignable to string&quot; 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, { ...
&quot;{{var}}&quot; ... })</code> nesting-options block. In that narrow
combination, attacker-controlled string values containing
<code>&quot;</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>
<li>chore: ignore <code>.env*</code> and
<code>*.pem</code>/<code>*.key</code> files in
<code>.gitignore</code></li>
</ul>
<h2>v26.0.5</h2>
<ul>
<li>fix: <code>cloneInstance().changeLanguage()</code> no longer fails
to update language state when the target language is not yet loaded — a
race between <code>init()</code>'s deferred <code>load()</code> and the
user's <code>changeLanguage()</code> could overwrite
<code>isLanguageChangingTo</code>, causing <code>setLngProps</code> to
be skipped <a
href="https://redirect.github.com/i18next/i18next/issues/2422">2422</a></li>
</ul>
<h2>v26.0.4</h2>
<ul>
<li>fix(types): inline formatting options like <code>{{price,
currency(EUR)}}</code> are now correctly resolved to their base format
type (e.g. <code>number</code> for <code>currency</code>) instead of
falling back to <code>string</code> <a
href="https://redirect.github.com/i18next/i18next/issues/2378">2378</a></li>
</ul>
</blockquote>
</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.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>overwrite: 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($ =&gt; $.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&lt;Fn&gt;</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&lt;Ns&gt;</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>'&lt;a.b&gt;.title' | '&lt;other.path&gt;.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 layer (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</code>
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($ =&gt; $.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 default 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($ =&gt; $.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 &quot;not assignable to string&quot; 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>
<h2>26.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>26.0.6</h2>
<p>Security release — all issues found via an internal audit.</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/i18next/i18next/commit/817ede5146e6d366645982885b0a729861d10a3a"><code>817ede5</code></a>
26.3.4</li>
<li><a
href="https://github.com/i18next/i18next/commit/46d0dd80b505b6b69feccebbe7d9c4fd66c8f85c"><code>46d0dd8</code></a>
build</li>
<li><a
href="https://github.com/i18next/i18next/commit/642137b7786d83661ec3ee53027798dc4b81d30a"><code>642137b</code></a>
fix(security): prevent deepExtend from recursing into inherited
built-ins</li>
<li><a
href="https://github.com/i18next/i18next/commit/cf7080d363c0bc775681215bba6513a3610dee8b"><code>cf7080d</code></a>
26.3.3</li>
<li><a
href="https://github.com/i18next/i18next/commit/05fd7be281a3c2175da16c9e867a91d95e034889"><code>05fd7be</code></a>
build</li>
<li><a
href="https://github.com/i18next/i18next/commit/cc0bd80943eae4f45867abbd78c0ae8dd964bb82"><code>cc0bd80</code></a>
changelog: 26.3.3 entry for <a
href="https://redirect.github.com/i18next/i18next/issues/2438">#2438</a></li>
<li><a
href="https://github.com/i18next/i18next/commit/9cbfa6353b6ab726c42be1e6ed52aab5b0601612"><code>9cbfa63</code></a>
fix(types): preserve selector returnObjects shape with context (<a
href="https://redirect.github.com/i18next/i18next/issues/2438">#2438</a>)</li>
<li><a
href="https://github.com/i18next/i18next/commit/3b047122f5ad5b99a29f9138bb8542de125c8783"><code>3b04712</code></a>
26.3.2</li>
<li><a
href="https://github.com/i18next/i18next/commit/fc20f5dd5ae9744045942e135e93dd787e4bc869"><code>fc20f5d</code></a>
changelog: 26.3.2 entry for <a
href="https://redirect.github.com/i18next/i18next/issues/2437">#2437</a></li>
<li><a
href="https://github.com/i18next/i18next/commit/6901e04f07f0eec1848242d8af26509ab5438920"><code>6901e04</code></a>
fix: reassemble comma-in-parens formatters at any chain position (<a
href="https://redirect.github.com/i18next/i18next/issues/2437">#2437</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/i18next/i18next/compare/v26.0.3...v26.3.4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=i18next&package-manager=npm_and_yarn&previous-version=26.0.3&new-version=26.3.4)](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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 04:12:52 +00:00

Bracket - Tournament System

build status translations last commit release codecov

Demo · Documentation · Quickstart · GitHub · Releases

evroon/bracket | Trendshift

Tournament system meant to be easy to use. Bracket is written in async Python (with FastAPI) and Vite as frontend using the Mantine library.

It has the following features:

  • Supports single elimination, round-robin and swiss formats.
  • Build your tournament structure with multiple stages that can have multiple groups/brackets in them.
  • Drag-and-drop matches to different courts or reschedule them to another start time.
  • Various dashboard pages are available that can be presented to the public, customized with a logo.
  • Create/update teams, and add players to teams.
  • Create multiple clubs, with multiple tournaments per club.
  • Swiss tournaments can be handled dynamically, with automatic scheduling of matches.

Explore the Bracket docs  ▶

Live Demo

A demo is available for free at https://www.bracketapp.nl/demo. The demo lasts for 30 minutes, after which your data will de deleted.

Quickstart

To quickly run bracket to see how it works, clone it and run docker compose up:

git clone git@github.com:evroon/bracket.git
cd bracket
sudo docker compose up -d

This will start the backend and frontend of Bracket, as well as a postgres instance. You should now be able to view bracket at http://localhost:3000. You can log in with the following credentials:

  • Username: test@example.org
  • Password: aeGhoe1ahng2Aezai0Dei6Aih6dieHoo.

To insert dummy rows into the database, run:

docker exec bracket-backend uv run --no-dev ./cli.py create-dev-db

See also the quickstart docs.

Usage

Read the usage guide for how to organize a tournament in Bracket from start to finish.

Configuration

Read the configuration docs for how to configure Bracket.

Bracket's backend is configured using .env files (prod.env for production, dev.env for development etc.). But you can also configure Bracket using environment variables directly, for example by specifying them in the docker-compose.yml.

The frontend doesn't can be configured by environment variables as well, as well as .env files using Vite's way of loading environment variables.

Running Bracket in production

Read the deployment docs for how to deploy Bracket and run it in production.

Bracket can be run in Docker or by itself (using uv and pnpm).

Development setup

Read the development docs for how to run Bracket for development.

Prerequisites are pnpm, postgresql and uv to run the frontend, database and backend.

Translations

Based on your browser settings, your language should be automatically detected and loaded. For now, there's no manual way of choosing a different language.

Supported Languages

To add/refine translations, Crowdin is used. See the docs for more information.

More screenshots

Help

If you're having trouble getting Bracket up and running, or have a question about usage or configuration, feel free to ask. The best place to do this is by creating a Discussion.

Supporting Bracket

If you're using Bracket and would like to help support its development, that would be greatly appreciated!

Several areas that we need a bit of help with at the moment are:

  • Star Bracket on GitHub
  • 🌐 Translating: Help make Bracket available to non-native English speakers by adding your language (via crowdin)
  • 📣 Spread the word by sharing Bracket to help new users discover it
  • 🖥️ Submit a PR to add a new feature, fix a bug, extend/update the docs or something else

See the contribution docs for more information on how to contribute

Contributors

evroon
Erik Vroon
robigan
Null
nvanheuverzwijn
Nicolas Vanheuverzwijn
sevi418
Sevi C
MaxRickettsUy
Max Ricketts-Uy
djpiper28
Danny Piper
ByteAfterlife
Byte
BachErik
BachErik
aminnairi
Amin NAIRI
FelipeGdM
Felipe Gomes De Melo
IzStriker
IzStriker
jmillxyz
Jon Miller
oscartobar
Oscar Tobar Rios
babeuh
Raphael Le Goaller

License

Bracket is licensed under AGPL-v3.0.

Please note that any contributions also fall under this license.

See LICENSE

S
Description
No description provided
Readme AGPL-3.0
56 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 51%
Python 47.7%
CSS 0.8%
Dockerfile 0.2%