Skip to content

fix: [SDK-5202] canonicalize Chinese locales and make setLanguage("") use device default - #1746

Merged
fadi-george merged 8 commits into
mainfrom
fadi/sdk-5202
Sep 18, 2026
Merged

fadi-george merged 8 commits into
mainfrom
fadi/sdk-5202

Conversation

@fadi-george

@fadi-george fadi-george commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Description

One Line Summary

Fix IAM variant matching for Simplified and Traditional Chinese language tags.

Screenshot 2026-09-17 at 4 50 51 PM Screenshot 2026-09-17 at 4 50 54 PM

Details

Motivation

The SDK truncated language tags to two characters, causing zh-Hans and zh-Hant IAMs to miss their configured variants and fall back to the default variant.

Scope

  • Match exact, normalized Chinese, and base-language variants while preserving platform precedence.
  • Handle persisted tags such as zh-Hans-CN, zh-Hant-TW, zh-CN, and zh-TW.
  • Normalize device Chinese locales to zh-Hans or zh-Hant.
  • Treat an empty setLanguage value as restoring the device language.
  • Add language selection and persistence to the iOS demo.

Testing

Unit testing

  • Added device-language normalization and empty-language reset coverage.
  • Added IAM coverage for exact, script-region, region-only, base-language, and default fallbacks.
  • Focused language tests pass.
  • SwiftLint passes with only pre-existing warnings.
  • Demo Release build for the iOS Simulator passes.

Manual testing

Not run on a physical device; covered by focused simulator tests and the demo Release build.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

@fadi-george
fadi-george requested a review from nan-li September 17, 2026 23:50
@fadi-george fadi-george changed the title fix: [SDK-5202] match Chinese IAM language variants fix: [SDK-5202] match IAM variants and handle empty setLanguage Sep 17, 2026

@cursor cursor 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.

Multi-model review (Opus 5, GPT 5.6 Sol, Grok 4.6)

Substantive diff +329/−34 = 363 across 11 source/test/demo/docs files (nothing generated, lock, vendor, or snapshot). The IAM candidate walk and Chinese script/region mapping look directionally right, and dropping substringToIndex:2 removes a real crash on short tags. One production crash remains.

Act on

  • containsObject: on a nil region (Grok): languageVariantCandidatesForLanguage: treats bare "zh" (no script, no region) as !scriptCode && [@["HK",@"MO",@"TW"] containsObject:regionCode]. NSArray containsObject: raises NSInvalidArgumentException on nil. Reachable via setLanguage("zh") and a hydrated server "zh". Device init never emits "zh", and the IAM tests never use it, so the suite stays green.

Consider

  • Dropped zh candidate (Opus): the old matcher always used the first two characters, so a dashboard zh variant still matched. The new Chinese path never adds "zh". Appending it last is cheap insurance.
  • Demo override vs fetch hydration (Sol+Grok): restoreLanguageOverride() runs immediately after login. Existing switch-user tests show fetch hydration then overwrites language with remote_language, so the selector and IAM can diverge.
  • Device language now stores the base code (Opus): new users get en instead of en-US. Cached installs keep the old tag. Call this out if intentional.
  • setLanguage("zh-CN") is not normalized (Opus): IAM still matches via the ObjC path; the stored/backend property stays zh-CN.

Noted / dismissed

  • Dual Swift/ObjC normalizers diverge on exotic scripts (zh-Latn-TW).
  • language is no longer nil when _user is missing.
  • yue/wuu stay unmapped — outside this ticket’s zh-Hans/zh-Hant scope.
  • setLanguage("") snapshots the device language once; it does not track later system changes.
Open in Web View Automation 

Sent by Cursor Automation: PR Reviews

Comment thread iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSInAppMessageController.m Outdated
Comment thread examples/demo/App/Services/OneSignalService.swift
@fadi-george fadi-george changed the title fix: [SDK-5202] match IAM variants and handle empty setLanguage fix: [SDK-5202] canonicalize Chinese locales and make setLanguage("") use device default Sep 17, 2026

@nan-li nan-li left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving.

One small thing, fine to do later. The code that turns a Chinese locale into zh-Hans or zh-Hant now exists in two places, OSLanguageProviderDevice and languageVariantCandidatesForLanguage:. They give the same answers today, but two copies will not stay in sync. Put it in one function that both can call.

@fadi-george

fadi-george commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Done. Chinese locale canonicalization now lives only in OSLanguageProviderDevice. IAM uses the existing language value, matching Android and leaving hydrated values backend-driven.

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.

2 participants