feat(i18n): mount the provider and surface the language switcher (#159) - #360
Open
devrim-1283 wants to merge 1 commit into
Open
feat(i18n): mount the provider and surface the language switcher (#159)#360devrim-1283 wants to merge 1 commit into
devrim-1283 wants to merge 1 commit into
Conversation
Closes AudioBitsStellar#159. The i18n work was all present and none of it reachable. I18nContext, the en/es locale tables and LanguageSwitcher existed — LanguageSwitcher even carried a "closes AudioBitsStellar#159" comment — but: $ grep -rn "I18nProvider" src/ --include=*.tsx | grep -v context/I18nContext (no matches) $ grep -rn "LanguageSwitcher" src/ --include=*.tsx | grep -v components/LanguageSwitcher (no matches) Nothing mounted the provider and nothing rendered the switcher, so no user could change language and useI18n() would have thrown anywhere it was tried. - I18nProvider now wraps the tree in context/provider.tsx, inside QueryClientProvider and around StellarNetworkProvider. - LanguageSwitcher renders in TopHeader, next to the role badge. Two defects fixed while wiring it up: readPersistedLocale used `stored in locales`, and `in` walks the prototype chain. A stored value of "constructor", "toString", "valueOf" or "hasOwnProperty" therefore passed the check and indexed `locales` to a function instead of a translation table, so every label in the UI rendered undefined. Now Object.hasOwn. setLocale gained the same validation, so an unsupported locale cannot be written in the first place. Both localStorage calls are wrapped: Safari private mode and blocked site data throw on access, which would have taken the whole provider down on mount. useOptionalI18n() was added for components that are i18n-aware rather than i18n-dependent. LanguageSwitcher uses it and renders null with no provider — it has nothing to switch — which keeps the 23 existing TopHeader tests that render without one working. useI18n() still throws, so a component that truly needs translations fails loudly. Tests: 15 new cases — default locale, persistence and restore, an unsupported locale ignored, the four inherited-property values rejected, a localStorage that throws on read and on write, useI18n outside a provider, the switcher listing and changing locales, and a parity check that en and es define exactly the same keys with no empty strings. Verified the tests catch the prototype bug: restoring `in` turns 4 of them red. No regressions: 26 failing tests before and after (381 -> 396 passing, the 15 new ones). `tsc --noEmit` reports the same 181 pre-existing errors. The one eslint error in I18nContext.tsx (react-hooks/set-state-in-effect) is also pre-existing — it is the SSR-safe mount effect, unchanged by this PR.
|
Someone is attempting to deploy a commit to the akatenvictor's projects Team on Vercel. A member of the Team first needs to authorize it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #159.
The i18n work was all present and none of it reachable.
I18nContext, theen/eslocale tables andLanguageSwitcherexisted —LanguageSwitchereven carries acloses #159comment — but:Nothing mounted the provider and nothing rendered the switcher. No user could change language, and
useI18n()would have thrown anywhere it was tried.Wiring
I18nProviderwraps the tree incontext/provider.tsx, insideQueryClientProviderand aroundStellarNetworkProvider.LanguageSwitcherrenders inTopHeader, next to the role badge.Two defects found while wiring it
1. Prototype-chain lookup.
readPersistedLocaleusedstored in locales, andinwalks the prototype chain:So
tbecame a function instead of a translation table and every label in the UI renderedundefined. NowObject.hasOwn.setLocalegained the same validation, so an unsupported value cannot be written in the first place.2. Unguarded storage access. Safari private mode and blocked site data both throw on
localStorage, which would have taken the whole provider down on mount. Both calls are now wrapped.Keeping existing tests working
23 existing tests render
TopHeaderwithout a provider. Rather than rewrite them,useOptionalI18n()was added for components that are i18n-aware rather than i18n-dependent.LanguageSwitcheruses it and rendersnullwhen there is no provider — it has nothing to switch.useI18n()still throws, so a component that genuinely needs translations fails loudly.Tests
15 new cases: default locale, persistence and restore, an unsupported locale ignored, the four inherited-property values rejected, a
localStoragethat throws on read and on write,useI18noutside a provider, the switcher listing and changing locales, and a parity check thatenandesdefine exactly the same keys with no empty strings.Verified the tests catch the bug: restoring
inturns 4 of them red.No regressions
Same 26 failures, and the delta is the 15 new tests.
tsc --noEmitreports the same 181 pre-existing errors. The one eslint error inI18nContext.tsx(react-hooks/set-state-in-effect) is pre-existing too — it is the SSR-safe mount effect, unchanged here.Reproducing locally needs
npm install --legacy-peer-deps.