feat(ui): let hosts supply locale and Reader Bible language (YPE-4813, YPE-5119) - #345
Conversation
Expo DOM WebViews often report English in navigator, so the Reader could not follow the device language. YouVersionProvider now accepts locale for UI strings and Accept-Language. BibleReader.Root accepts defaultLanguageId/languageId for the version picker. App locale and Bible language stay separate. YPE-4813
🦋 Changeset detectedLatest commit: e88925c The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Let the Vite demo pass YouVersionProvider locale and BibleReader defaultLanguageId from env so hosts can exercise YPE-4813 locally.
Main replaced vi.mock helpers with context probes and hook overrides, which broke CI on the merge. Rewrite the locale tests to match that pattern so lint, typecheck, and unit tests pass. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep a single locale prop instead of a second lng API. Cover Verse of the Day copy and regional tags, apply language before paint, and document that app locale stays separate from Bible language. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 44c51c57ba
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
cameronapak
left a comment
There was a problem hiding this comment.
Spec
The pull request matches YPE-4813 and YPE-5119. App locale and Bible language stay separate. locale does not seed the version picker. No must-fix spec gap.
YouVersionProvider locale
syncSdkLanguage → i18n + Accept-Language
(not BibleVersionPicker language)
BibleReader.Root defaultLanguageId / languageId
context → Toolbar → BibleVersionPicker.Root
suggestion (worth): The PR says language is applied before paint. locale is applied in useLayoutEffect via async changeLanguage. i18n.init still uses navigator. In the Expo case (navigator reports English), first paint can stay English verseOfTheDay. Tests use findByText and pass after the update.
nitpick: Unsupported-tag fallback to English is implemented. New tests do not cover an unsupported locale tag.
nitpick: onLanguageChange is forwarded. It is not tested.
nitpick: Omit-locale still follows navigator. No new provider test for that path.
Standards
No documented-standard violation. Hook stubs use HookOverrideProvider. No new i18n keys. No reverse dependency.
suggestion (worth): packages/ui/AGENTS.md says assert roles and behavior, not localized copy blobs. The provider test asserts es.verseOfTheDay text. Assert i18n.language === 'es' instead.
nitpick: syncBrowserLanguageFromNavigator now only calls syncSdkLanguage. The provider calls syncSdkLanguage directly.
Summary
- Standards: 0 must-fix, 1 worth, 1 nit. Worst: provider test asserts localized copy.
- Spec: 0 must-fix, 1 worth, 3 nits. Worst: first paint can stay English when
localeis set.
Code Reviewer bot, sent on behalf of Cam.
Layout effects never run on the server, so an explicit locale stayed English until hydration. Also drop the header-test type assertion that failed lint. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the provider SSR test on the applied language instead of a translated string. Co-authored-by: Cursor <cursoragent@cursor.com>
cameronapak
left a comment
There was a problem hiding this comment.
Spec
Re-review at 37a59fc (was 44c51c57). YPE-4813 and YPE-5119 still match. locale does not seed the picker. Case-insensitive Accept-Language is a real spec fix.
Prior worth (first paint) — resolved for this SDK. The provider now calls syncSdkLanguage during render when locale is set. This package passes all locales into i18n.init (resources). In that case changeLanguage runs loadResources as a sync no-op and sets translator.language before return. Children then call t() in the host language. The SSR test proves i18n.language === 'es' with no await.
nitpick: Unsupported locale tag, onLanguageChange, and omit-locale → navigator are still untested on the provider.
Standards
No documented-standard violation. Render-time sync matches the existing filter writes. The new SSR test asserts i18n.language.
suggestion (worth): The client test 'uses locale for bundled copy…' still asserts es.verseOfTheDay text. packages/ui/AGENTS.md says assert roles and behavior, not localized copy blobs.
nitpick: syncBrowserLanguageFromNavigator is still a one-line wrapper. The provider calls syncSdkLanguage directly.
Summary
- Standards: 0 must-fix, 1 worth, 1 nit. Worst: client provider test still asserts VOTD copy.
- Spec: 0 must-fix, 0 worth, 3 nits. Worst: none. Prior first-paint worth is resolved for bundled resources.
Code Reviewer bot, sent on behalf of Cam.
Align the client locale test with the SSR case: check i18n.language instead of translated strings. Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid a CI miss where the verse paints before remove is installed, so the optional call never hits deleteHighlight. Co-authored-by: Cursor <cursoragent@cursor.com>
cameronapak
left a comment
There was a problem hiding this comment.
Spec
Re-review at e88925c1 (was 37a59fc). YPE-4813 and YPE-5119 still match. locale does not seed the picker.
YouVersionProvider locale
syncSdkLanguage (during render)
i18n.language === 'es' # client + SSR tests
BibleReader.Root languageId / defaultLanguageId / onLanguageChange
version picker (not locale)
Prior worth (client copy assert) — resolved. The client test now asserts i18n.language === 'es'. The test no longer looks for verseOfTheDay text.
Prior worth (first paint) — still resolved. Render-time syncSdkLanguage did not change.
nitpick: Unsupported locale tag, onLanguageChange, and omit-locale to navigator are still untested on the provider.
nitpick: Commit e88925c1 waits longer in the vapor-flash highlight test. That change is a test flake fix. The change is not part of the locale or picker work.
Standards
No documented-standard violation. The client locale test now asserts i18n.language. docs/testing.md forbids afterEach. The leftover cleanup note is retracted.
nitpick: syncBrowserLanguageFromNavigator is still a one-line wrapper. The provider calls syncSdkLanguage directly.
nitpick: No test shows that locale does not seed the picker.
Summary
- Standards: 0 must-fix, 0 worth, 2 nits. Worst: none.
- Spec: 0 must-fix, 0 worth, 4 nits. Worst: none.
Code Reviewer bot, sent on behalf of Cam.
Summary
Consolidates YPE-4813 and YPE-5119 onto one API. Expo DOM WebViews often report English in
navigator, which locked SDK chrome (including Verse of the Day) and the version picker to English.This keeps the Expo distinction between app locale and Bible language (see
platform-sdk-reactnative-expoADR 0007):YouVersionProvider locale— SDK UI strings andAccept-Languageon API callsBibleReader.Root defaultLanguageId/languageId— which Bible translation language the version picker opens onlocaledoes not pick a default Bible version. Regional tags such ases-MXresolve to a bundled locale. This also unblocks YPE-4820 once Expo forwards itslocaleinto the WebView.Supersedes #344 (
lngwas a second name for the same provider override).Changes
YouVersionProvideraccepts optionallocale(BCP-47). It drives i18n before paint and setsAccept-Languageunless the host already set that header.BibleReader.RootforwardslanguageId,defaultLanguageId, andonLanguageChangetoBibleVersionPicker.VITE_YVP_LOCALEandVITE_YVP_DEFAULT_LANGUAGE_ID.es-MX/ Verse of the Day copy), and Reader seeding the picker language.Test plan
Accept-LanguagesyncSdkLanguageover an English navigator, including regional tagslocaleBibleReaderdefaultLanguageId/languageIdVITE_YVP_LOCALE=es: Reader chrome, settings, version-picker headings, sign-in, and VOTD title are SpanishVITE_YVP_APP_KEY: John 1 stays BSB and the version picker lists Spanish Bibleslocalefromexpo-localizationinto the DOMYouVersionProvider, anddefaultLanguageIdintoBibleReaderif the picker should open on a Bible languageGreptile Summary
The PR adds host-controlled SDK locale selection while keeping UI locale separate from Bible translation language.
YouVersionProvider.localefor bundled UI language and APIAccept-Language.BibleReader.Rootto the version picker.Confidence Score: 5/5
The PR appears safe to merge.
No blocking failure remains.
Important Files Changed
Accept-Languageheader; the previously reported casing issue is fixed.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart LR Host[Host application] Provider[YouVersionProvider locale] I18n[SDK i18n resources] API[Platform API Accept-Language] Reader[BibleReader languageId / defaultLanguageId] Picker[Bible version picker] Host --> Provider Provider --> I18n Provider --> API Host --> Reader Reader --> PickerReviews (4): Last reviewed commit: "test(ui): wait for remove callback in va..." | Re-trigger Greptile
Context used: