Skip to content

feat(ui): let hosts supply locale and Reader Bible language (YPE-4813, YPE-5119) - #345

Merged
Dustin-Kelley merged 10 commits into
mainfrom
cursor/ype-4813-reader-default-lang-e5f7
Aug 20, 2026
Merged

feat(ui): let hosts supply locale and Reader Bible language (YPE-4813, YPE-5119)#345
Dustin-Kelley merged 10 commits into
mainfrom
cursor/ype-4813-reader-default-lang-e5f7

Conversation

@Dustin-Kelley

@Dustin-Kelley Dustin-Kelley commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

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-expo ADR 0007):

  • YouVersionProvider locale — SDK UI strings and Accept-Language on API calls
  • BibleReader.Root defaultLanguageId / languageId — which Bible translation language the version picker opens on

locale does not pick a default Bible version. Regional tags such as es-MX resolve to a bundled locale. This also unblocks YPE-4820 once Expo forwards its locale into the WebView.

Supersedes #344 (lng was a second name for the same provider override).

Changes

  • YouVersionProvider accepts optional locale (BCP-47). It drives i18n before paint and sets Accept-Language unless the host already set that header.
  • BibleReader.Root forwards languageId, defaultLanguageId, and onLanguageChange to BibleVersionPicker.
  • The Vite demo reads optional VITE_YVP_LOCALE and VITE_YVP_DEFAULT_LANGUAGE_ID.
  • Tests cover locale header forwarding, explicit locale over navigator (including es-MX / Verse of the Day copy), and Reader seeding the picker language.

Test plan

  • UI unit tests for provider locale / Accept-Language
  • UI unit tests for syncSdkLanguage over an English navigator, including regional tags
  • UI unit tests for Verse of the Day heading following locale
  • UI unit tests for BibleReader defaultLanguageId / languageId
  • Vite demo with VITE_YVP_LOCALE=es: Reader chrome, settings, version-picker headings, sign-in, and VOTD title are Spanish
  • Vite demo with a real VITE_YVP_APP_KEY: John 1 stays BSB and the version picker lists Spanish Bibles
  • In Expo: pass locale from expo-localization into the DOM YouVersionProvider, and defaultLanguageId into BibleReader if the picker should open on a Bible language

Greptile Summary

The PR adds host-controlled SDK locale selection while keeping UI locale separate from Bible translation language.

  • Adds YouVersionProvider.locale for bundled UI language and API Accept-Language.
  • Forwards controlled and uncontrolled Bible-language props from BibleReader.Root to the version picker.
  • Updates the Vite example, public documentation, exports, and tests for the new APIs.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/ui/src/components/YouVersionProvider.tsx Adds explicit locale synchronization and case-insensitive host override handling for the Accept-Language header; the previously reported casing issue is fixed.
packages/ui/src/i18n/index.ts Introduces a shared locale resolver that supports explicit host locale tags while retaining browser-language fallback.
packages/ui/src/components/bible-reader.tsx Threads controlled and default Bible-language properties through Reader context into the version picker.
packages/ui/src/components/YouVersionProvider.test.tsx Covers locale-driven headers, case-insensitive host overrides, browser precedence, regional tags, and SSR synchronization.
packages/ui/src/components/bible-reader.test.tsx Verifies that Reader-provided default and controlled language IDs seed version-picker requests.

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 --> Picker
Loading

Reviews (4): Last reviewed commit: "test(ui): wait for remove callback in va..." | Re-trigger Greptile

Context used:

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-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e88925c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@youversion/platform-react-ui Minor
vite-react Patch
@youversion/platform-core Minor
@youversion/platform-react-hooks Minor

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

cursoragent and others added 3 commits August 19, 2026 20:16
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>
@Dustin-Kelley Dustin-Kelley changed the title feat(ui): let hosts supply locale and Reader Bible language (YPE-4813) feat(ui): let hosts supply locale and Reader Bible language (YPE-4813, YPE-5119) Aug 19, 2026
@Dustin-Kelley
Dustin-Kelley marked this pull request as ready for review August 20, 2026 16:48
Comment thread packages/ui/src/components/YouVersionProvider.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread packages/ui/src/components/YouVersionProvider.tsx
cameronapak
cameronapak previously approved these changes Aug 20, 2026

@cameronapak cameronapak left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 locale is set.

Code Reviewer bot, sent on behalf of Cam.

Comment thread packages/ui/src/components/YouVersionProvider.tsx
Comment thread packages/ui/src/components/YouVersionProvider.test.tsx Outdated
Dustin-Kelley and others added 2 commits August 20, 2026 12:06
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
cameronapak previously approved these changes Aug 20, 2026

@cameronapak cameronapak left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread packages/ui/src/components/YouVersionProvider.tsx
Comment thread packages/ui/src/components/YouVersionProvider.test.tsx Outdated
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 cameronapak left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@Dustin-Kelley
Dustin-Kelley merged commit aef57f3 into main Aug 20, 2026
14 checks passed
@Dustin-Kelley
Dustin-Kelley deleted the cursor/ype-4813-reader-default-lang-e5f7 branch August 20, 2026 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants