SIGN IN SIGN UP

Fall back to "en" when a paywall screen omits `default_locale` (#4111)

<!-- Thank you for contributing to Purchases! Before pressing the
"Create Pull Request" button, please provide the following: -->

### Checklist
- [x] If applicable, unit tests
- [x] If applicable, create follow-up issues for `purchases-ios` and
hybrids

### Motivation
`default_locale` was a required field on both paywall screen models. The
backend serves it as `null` for template-derived screens, so those
paywalls fail to decode and fall back to the default paywall. On the
workflow path the failure is
not scoped to the field, it discards the entire `PublishedWorkflow`, so
one bad screen takes every other screen in the workflow with it.

### Description
This needs two fixes, not one: a default handles a missing value, but an
explicit null still fails. We now fall back to en in both cases.

I applied the same behavior to both paywall models. Only the workflow
path is failing in production right now, but both models have the same
requirement.

I verified the fix against the payload the backend actually sends.
Previously, both null and a missing value failed; now present, null, and
missing values all behave consistently, falling back to en when needed.

All relevant test suites and checks pass. The four existing HTTP timeout
failures also reproduce on a clean HEAD, so they’re unrelated.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Localized deserialization-only change with a safe default; no auth,
billing, or persistence impact.
> 
> **Overview**
> Paywall screen JSON decoding no longer fails when the backend sends
**`default_locale` as `null`** (common on template-derived screens) or
omits the key. **`WorkflowScreen`** and **`PaywallComponentsData`** now
use **`DefaultLocaleIdSerializer`** plus a property default of **`en`**,
so valid strings are kept and null, missing, or non-string JSON values
all resolve to English instead of aborting deserialization.
> 
> On the workflow path, a decode failure previously dropped the entire
**`PublishedWorkflow`**, not just one screen; this change keeps those
workflows loadable. Malformed **`default_locale`** values are not
coerced into odd locale strings, aligning with iOS string-only behavior.
> 
> Unit tests cover present, null, missing, and invalid
**`default_locale`** payloads and assert both models decode the same
way.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b78cc5df10e70470f3d75fc4c0209091e7c32a0b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
M
Monika Mateska committed
cfa1e4c9f5ce1681193332580745ed8dba22cdf3
Parent: 2ca15ec
Committed by GitHub <noreply@github.com> on 8/28/2026, 10:19:01 AM