feat: add setLocaleIdentifier for runtime locale changes#162
feat: add setLocaleIdentifier for runtime locale changes#162funCapital wants to merge 1 commit intosuperwall:mainfrom
Conversation
Expose Superwall.shared.localeIdentifier as a runtime-settable property across iOS, Android, TypeScript module, Zustand store, and compat layer. This allows changing the paywall language at runtime without needing to reconfigure the SDK. Previously, localeIdentifier could only be set via SuperwallOptions at configure time, making dynamic language switching impossible. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| async setLocaleIdentifier(localeIdentifier: string | null): Promise<void> { | ||
| SuperwallExpoModule.setLocaleIdentifier(localeIdentifier) | ||
| } |
There was a problem hiding this comment.
Swallowed native errors
setLocaleIdentifier is async but doesn't await/return the underlying SuperwallExpoModule.setLocaleIdentifier(...) call. If the native module throws synchronously (e.g., module unavailable), this method will still resolve successfully and hide the failure. Consider return await SuperwallExpoModule.setLocaleIdentifier(localeIdentifier) for parity with other wrappers here.
Also appears in src/useSuperwall.ts:332-334.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/compat/index.ts
Line: 730:732
Comment:
**Swallowed native errors**
`setLocaleIdentifier` is `async` but doesn't `await`/`return` the underlying `SuperwallExpoModule.setLocaleIdentifier(...)` call. If the native module throws synchronously (e.g., module unavailable), this method will still resolve successfully and hide the failure. Consider `return await SuperwallExpoModule.setLocaleIdentifier(localeIdentifier)` for parity with other wrappers here.
Also appears in `src/useSuperwall.ts:332-334`.
How can I resolve this? If you propose a fix, please make it concise.| setLocaleIdentifier: async (localeIdentifier) => { | ||
| SuperwallExpoModule.setLocaleIdentifier(localeIdentifier) | ||
| }, |
There was a problem hiding this comment.
Async call not awaited
This store action is async but doesn't await/return SuperwallExpoModule.setLocaleIdentifier(...). If the native module call throws synchronously, the returned Promise resolves and the error is swallowed. Returning/awaiting the call will preserve failures for callers.
(Compat layer has the same issue in src/compat/index.ts:730-732.)
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/useSuperwall.ts
Line: 332:334
Comment:
**Async call not awaited**
This store action is `async` but doesn't `await`/`return` `SuperwallExpoModule.setLocaleIdentifier(...)`. If the native module call throws synchronously, the returned Promise resolves and the error is swallowed. Returning/awaiting the call will preserve failures for callers.
(Compat layer has the same issue in `src/compat/index.ts:730-732`.)
How can I resolve this? If you propose a fix, please make it concise.
Summary
setLocaleIdentifieras a runtime-settable property across all layers (iOS, Android, TS, Zustand store, compat)setLogLevelProblem
Currently,
localeIdentifiercan only be set viaSuperwallOptionsat configure time. Apps that support runtime language switching (e.g., via i18next or user preferences) have no way to update the paywall locale afterconfigure()has been called. SinceSuperwall.configureignores subsequent calls, the only option was to restart the app.The native SDKs (both iOS and Android) already support setting
localeIdentifierat runtime viaSuperwall.shared.localeIdentifier, but the Expo wrapper doesn't expose it.Changes
SuperwallExpoModule.swiftFunction("setLocaleIdentifier")settingSuperwall.shared.localeIdentifierSuperwallExpoModule.ktFunction("setLocaleIdentifier")settingSuperwall.instance.localeIdentifierSuperwallExpoModule.tssetLocaleIdentifieruseSuperwall.tscompat/index.tsUsage
Test plan
setLocaleIdentifier("es")Greptile Overview
Greptile Summary
This PR exposes a runtime
setLocaleIdentifierAPI through the Expo wrapper so apps can change paywall language without re-callingconfigure(). It adds a new JS-exposed function in both native modules (iOS setsSuperwall.shared.localeIdentifier, Android setsSuperwall.instance.localeIdentifier), wires the method into the TS native module typing, and surfaces it through both the Zustand hook store and the compat class wrapper.One correctness issue: the newly-added JS wrapper methods in the compat layer and Zustand store are declared
asyncbut don’tawait/returnthe underlying native call, which can cause synchronous native errors (e.g., module unavailable) to be silently swallowed rather than propagated to callers.Confidence Score: 4/5
asyncmethods currently don’t await/return the native call, which can hide failures and make runtime issues hard to diagnose.Important Files Changed
setLocaleIdentifierfunction that assignsSuperwall.instance.localeIdentifier.setLocaleIdentifierfunction to setSuperwall.shared.localeIdentifierfrom JS.setLocaleIdentifier, but it doesn’t await/return the native call (can swallow synchronous native errors).setLocaleIdentifier, but it doesn’t await/return the native call (can swallow synchronous native errors).Sequence Diagram
sequenceDiagram participant App as App (JS) participant Store as useSuperwall (Zustand) participant Compat as compat/Superwall participant Expo as SuperwallExpoModule (TS) participant IOS as iOS SuperwallExpoModule.swift participant Droid as Android SuperwallExpoModule.kt participant SDK as Native Superwall SDK alt Hooks SDK path App->>Store: "setLocaleIdentifier('es')" Store->>Expo: "setLocaleIdentifier('es')" Expo-->>IOS: "Function(setLocaleIdentifier)" IOS->>SDK: "localeIdentifier = 'es'" Expo-->>Droid: "Function(setLocaleIdentifier)" Droid->>SDK: "localeIdentifier = 'es'" else Compat wrapper path App->>Compat: "setLocaleIdentifier('es')" Compat->>Expo: "setLocaleIdentifier('es')" Expo-->>IOS: "Function(setLocaleIdentifier)" IOS->>SDK: "localeIdentifier = 'es'" Expo-->>Droid: "Function(setLocaleIdentifier)" Droid->>SDK: "localeIdentifier = 'es'" end(2/5) Greptile learns from your feedback when you react with thumbs up/down!
Context used:
dashboard- CLAUDE.md (source)