You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Measured while writing the locale tests for #4468 (PR #4512). Observation-class: no user hits this, but it costs a debugging lap and it can make a test look like it is asserting one thing while asserting another.
The mechanism
useObjectTranslation() is provider-safe by design — outside I18nProvider it falls back to react-i18next's global instance:
The catch is that the global instance is shared across the whole test file, and every I18nProvider mounted in that file leaves it on the language it was given. Vitest isolates modules per file, not per test, so the effect persists across cleanup() and across describe boundaries: once any case has mounted a zh provider, every provider-less render later in the same file resolves zh.
Measured twice, in two different shapes
A provider-less assertion that reads as a fallback pin but is really an ordering pin. In PR fix(i18n): every date branch threads the active locale — future-relative and absolute forms localize (#4468) #4512 a case asserting useDisplayLocale()'s 'en' last resort was written after the zh cases and failed with 3天后 — correct behaviour for react-i18next's state, and nothing to do with the fallback under test. Withdrawn, with the pin left in DateCellRenderer.test.tsx, which mounts no provider at all.
An unrelated test in another file broken by adding a provider above it. Adding one I18nProvider case to packages/fields/src/widgets/GridField.test.tsx turned shows an uploaded file as a removable chip red, ~200 lines further down. That test reads FileField.tsx:474's translated aria-label:
Deterministic, and it reproduced on a clean re-run; running the chip test alone passes. The zh case was moved to its own file, and GridField.test.tsx carries a comment saying why.
Why this is worth recording
The failure never names its cause. It surfaces as an assertion about some unrelated label or date in a test that was not touched, several hundred lines from the provider that caused it, and it is invisible when that test is run alone — which is the first thing anyone does to triage it.
Candidate directions (not a recommendation — this needs measuring first)
An afterEach in the shared DOM setup that restores the global i18next instance's language, so provider-less renders always mean the same thing.
Have I18nProvider create an instance that is never installed as react-i18next's global default, so a provider can only affect its own subtree. Needs checking against the deliberate design in provider.tsx — the global fallback is what makes useObjectTranslation() provider-safe in the first place, so this may be a trade rather than a fix.
Leave the mechanism alone and document it where tests are written (AGENTS.md §测试纪律), on the grounds that the two occurrences above were both cheap to diagnose once known.
No suggested severity — filing it plainly for triage.
Measured while writing the locale tests for #4468 (PR #4512). Observation-class: no user hits this, but it costs a debugging lap and it can make a test look like it is asserting one thing while asserting another.
The mechanism
useObjectTranslation()is provider-safe by design — outsideI18nProviderit falls back to react-i18next's global instance:The catch is that the global instance is shared across the whole test file, and every
I18nProvidermounted in that file leaves it on the language it was given. Vitest isolates modules per file, not per test, so the effect persists acrosscleanup()and acrossdescribeboundaries: once any case has mounted azhprovider, every provider-less render later in the same file resolveszh.Measured twice, in two different shapes
A provider-less assertion that reads as a fallback pin but is really an ordering pin. In PR fix(i18n): every date branch threads the active locale — future-relative and absolute forms localize (#4468) #4512 a case asserting
useDisplayLocale()'s'en'last resort was written after thezhcases and failed with3天后— correct behaviour for react-i18next's state, and nothing to do with the fallback under test. Withdrawn, with the pin left inDateCellRenderer.test.tsx, which mounts no provider at all.An unrelated test in another file broken by adding a provider above it. Adding one
I18nProvidercase topackages/fields/src/widgets/GridField.test.tsxturnedshows an uploaded file as a removable chipred, ~200 lines further down. That test readsFileField.tsx:474's translatedaria-label:Deterministic, and it reproduced on a clean re-run; running the chip test alone passes. The zh case was moved to its own file, and
GridField.test.tsxcarries a comment saying why.Why this is worth recording
The failure never names its cause. It surfaces as an assertion about some unrelated label or date in a test that was not touched, several hundred lines from the provider that caused it, and it is invisible when that test is run alone — which is the first thing anyone does to triage it.
Candidate directions (not a recommendation — this needs measuring first)
afterEachin the shared DOM setup that restores the global i18next instance's language, so provider-less renders always mean the same thing.I18nProvidercreate an instance that is never installed as react-i18next's global default, so a provider can only affect its own subtree. Needs checking against the deliberate design inprovider.tsx— the global fallback is what makesuseObjectTranslation()provider-safe in the first place, so this may be a trade rather than a fix.No suggested severity — filing it plainly for triage.