Files
MatchLiveTv/docs/IOS_ANDROID_I18N_GAP.md
T

12 KiB
Raw Blame History

Gap Android → iOS: allineamento app nativa

Documento operativo per continuare su Mac lo sviluppo iOS e rilasciare unapp allineata ad Android 2.0.5-native.

Aggiornato: 24 luglio 2026
Riferimento Android (produzione / telefono / Play): 2.0.5-native (versionCode 26), API https://www.matchlivetv.it
Stato iOS attuale: marketing 2.0.0, build 21 — i18n solo Login parziale

Obiettivo iOS: stessa copertura lingua di Android (Login, hub, sheet/dialog, wizard, broadcast) + bump versione, senza i bug di sessione/crash già risolti su Android 2.0.5.


Contesto

Su Android (rilasciato) la lingua scelta dallutente vale su tutta lapp usabile:

  • Persistenza + apply live (AppLocale / SharedPreferences mltv_locale + ProvideAppLocale)
  • Icona globo su Login (TopAppBar) e Matches
  • Hub Partite localizzato
  • Bottom sheet e dialog Matches (es. «Choose team», nuova partita, programma, elimina, riprendi)
  • Wizard 3 step + branding colori
  • Broadcast overlay, snackbar, dialog fine set/partita
  • ~230+ chiavi × 5 lingue in res/values*

Su iOS esistono già AppLanguage + LanguagePickerView + Login localizzato, ma Matches/sheet/wizard/broadcast restano in italiano hardcoded. Va replicato il lavoro Android in SwiftUI.

API produzione: entrambe le app puntano già a https://www.matchlivetv.itnessun gap di endpoint.


Lezioni Android 2.0.5 (obbligatorie su iOS)

Queste sono regressioni/bug già visti su Android; non ripeterli su iOS.

Problema Sintomo Fix Android (da replicare in spirito)
Recreate Activity al cambio lingua Torna al Login / perde nav Niente recreate obbligatorio: aggiorna UI via stato lingua + refresh stringhe
Context “nudo” per le stringhe Crash wizard: No ActivityResultRegistryOwner / picker foto Mantieni Activity come host; localizza solo Resources / environment
findActivity() su context configurazione Cambio lingua non applica (apply silent no-op) Applica lingua con applicationContext / store globale, non dipendere da Activity dal dialog
Globe sotto lo scroll del form Login Tap ignorato Globe in toolbar/top bar, non overlay sotto ScrollView/Column
Splash che richiede rete per restare loggato Dopo cambio lingua → Login se API lenta Se token locale presente → resta autenticato; refresh rete best-effort

Pattern Android di riferimento (Compose)

  1. AppLocale.tagFlow + prefs mltv_locale
  2. ProvideAppLocale: LocalConfiguration + LocalizedContextWrapper(Activity, localizedResources)
    → stringhe aggiornate e LocalActivityResultRegistryOwner integro
  3. LanguagePickerDialog chiama AppLocale.apply(context, tag) (applicationContext), non findActivity() obbligatorio
  4. Splash: currentSession() != null → Matches; validateOrRefresh() in background

Equivalente SwiftUI consigliato

  1. AppLanguage / @AppStorage + NotificationCenter (già presente) o environment(\.locale, …)
  2. Root: .environment(\.locale, locale) e .id(languageTick) sulle schermate che mostrano testo
  3. Non distruggere NavigationStack / session store al cambio lingua
  4. Photo picker / PhotosPicker / UIImagePicker: restano agganciati alla View host, non a un context “fake”
  5. Cold start: se token in Keychain/UserDefaults → vai a Matches anche se /me fallisce temporaneamente

Stato a confronto (target = Android 2.0.5)

Area Android 2.0.5 iOS oggi Da fare su iOS
Persistenza lingua SharedPreferences + ProvideAppLocale (no recreate nav) UserDefaults + notification Refresh UI su tutte le schermate senza reset sessione/nav
Picker Login Icona globo in TopAppBar Testo / picker presente Allineare a icona globo in toolbar
Picker Matches Icona globo top bar Presente OK se già icona; altrimenti allineare
Login stringhe Sì (L10n) OK
Slogan wordmark app_slogan Chiave app.slogan non usata Collegare L10n.t("app.slogan")
Hub Matches Quasi tutto IT fisso Localizzare con chiavi matches.*
Sheet/dialog Matches Sì (sheet_*) IT fisso Localizzare (priorità: scegli squadra)
Status badge partita match_status_* IT Localizzare
Snackbar hub matches_msg_* IT Localizzare
Wizard 3 step Sì (wizard_*) IT Localizzare
Branding / color picker IT Localizzare
Broadcast + score dialog Sì (broadcast_*, score_*) IT Localizzare
Catalogo stringhe values + values-en/fr/de/es (~230 chiavi) ~14 chiavi in AppLanguage.swift Espandere L10n (o migrare a Localizable.xcstrings)
Logout UI Icona Testo Icona SF Symbol
Versione 2.0.5-native / 26 2.0.0 / 21 Bump a 2.0.5 / 26 (o build successiva se conflitto TestFlight)
RTMP ingest RtmpIngestUrl.kt MediaUrl.swift OK in prod; allineare solo semantica dev se serve

File di riferimento

Android (sorgente di verità — già fatto)

Ruolo Path
Locale + ProvideAppLocale native/android/.../core/AppLocale.kt
Picker native/android/.../ui/components/LanguagePickerDialog.kt
Activity native/android/.../MainActivity.kt
Splash (sessione locale) native/android/.../ui/splash/SplashScreen.kt
Stringhe native/android/app/src/main/res/values/strings.xml + values-{en,fr,de,es}/
Login .../ui/login/LoginScreen.kt
Hub .../ui/matches/MatchesScreen.kt
Sheet/dialog .../ui/matches/MatchSheets.kt
Wizard .../ui/wizard/*.kt
Broadcast .../ui/broadcast/*.kt
Versione native/android/app/build.gradle.kts

iOS (da aggiornare)

Ruolo Path
Lingua + L10n native/ios/MatchLiveTv/Core/AppLanguage.swift
Login native/ios/MatchLiveTv/UI/Login/LoginScreen.swift
Hub native/ios/MatchLiveTv/UI/Matches/MatchesScreen.swift
Sheet/dialog Matches file sheet/alert equivalenti sotto UI/Matches/ (cercare stringhe IT)
Wizard UI/Wizard/ (o path equivalente)
Broadcast UI/Broadcast/ (o path equivalente)
Wordmark native/ios/MatchLiveTv/UI/Components/MatchLiveWordmark.swift
Auth / splash equivalent entry root / session restore
Versioni generate_xcodeproj.py, project.pbxproj, Info.plist
Build scripts/build_ios_release.sh

Piano di lavoro iOS (replicare Android — ordine obbligato)

Fase A — Infrastruttura stringhe (prima di tutto)

  1. Aprire Android values/strings.xml e values-en|fr|de|es/strings.xml come catalogo.
  2. Portare in L10n.table (o meglio Localizable.xcstrings) tutte le chiavi usate da:
    • matches_*, sheet_*, match_status_*, matches_msg_*
    • wizard_*, wizard_color_hue
    • broadcast_*, score_*
    • login_*, language_*, action_*, app_slogan, common_* se presenti
  3. Convenzione chiavi iOS: matches.hello ↔ Android matches_hello (punto al posto di _).
  4. Placeholder: Android %1$s → Swift "Ciao, \(name)" o String(format: L10n.t("matches.hello"), name).

Fase B — Login + wordmark (rapido)

  1. Login: icona globo in toolbar (come Android TopAppBar), non overlay che lo scroll può coprire.
  2. MatchLiveWordmark: L10n.t("app.slogan").
  3. Cambio lingua: aggiorna stringhe senza buttare fuori lutente (se già loggato altrove, stessa regola).

Fase C — Hub Matches + sheet/dialog (priorità UX — screenshot «Scegli squadra»)

  1. MatchesScreen.swift: ogni Text("…") hardcoded → L10n.t(...).
  2. Sheet/dialog equivalenti a MatchSheets.kt:
    • scegli squadra → sheet.choose_team
    • nuova partita / programma / avvia subito
    • scegli partita, badge BOZZA/PROGRAMMATA
    • riprendi diretta, continua setup
    • configura ora?, elimina partita
  3. Snackbar/alert hub → matches.msg_*.
  4. Badge status riga partita → match.status_*.
  5. Assicurare .id(languageTick) (o environment) su root Matches e sheet presentati.

Fase D — Wizard

  1. Localizzare step Partita / Trasmissione / Test rete + branding editor + color hue (wizard.*).
  2. Errori validazione e CTA AVANTI/INDIETRO/INIZIA.
  3. Verificare photo/logo picker dopo cambio lingua (su Android crashava senza Activity host).

Fase E — Broadcast

  1. Overlay controlli, contentDescription, snackbar pausa/ripresa/regia.
  2. Dialog termina diretta, set concluso, chiudi set, partita terminata (broadcast.*, score.*).

Fase F — Sessione + versione e release

  1. Cold start / cambio lingua: token locale → resta in Matches (non forzare Login se /me fallisce).
  2. Bump MARKETING_VERSION2.0.5, CURRENT_PROJECT_VERSION26 (o successivo se conflitto TestFlight).
  3. Aggiornare generate_xcodeproj.py e Info.plist, poi python3 generate_xcodeproj.py.
  4. ./scripts/build_ios_release.sh (API default già produzione).

Mapping chiavi — gruppi da copiare da Android

Sorgente: native/android/app/src/main/res/values*/strings.xml.

Prefisso Android Uso Priorità
language_*, login_*, app_slogan, action_* Login / chrome Alta
matches_* Hub Alta
sheet_*, match_status_*, matches_msg_* Sheet/dialog hub Alta (bug «Scegli squadra» in EN)
wizard_* Wizard Alta (stessa sessione utente dopo hub)
broadcast_*, score_* Diretta Alta
streaming_notification_* Solo Android FGS N/A su iOS

Non lasciare fuori scope wizard/broadcast: su Android sono già tradotti; iOS deve seguirli per parità.


Verifica manuale su Mac (acceptance)

  1. cd native/ios && python3 generate_xcodeproj.py
  2. Build simulatore; login produzione.
  3. Login: globo → English → label/errori/slogan in EN.
  4. Loggato: cambio lingua da Matches → resti su Matches, testi EN (niente ritorno al Login).
  5. Matches: saluto, CTA, empty state in EN.
  6. Apri «Change» / scegli squadra: titolo «Choose team» (non «Scegli squadra»).
  7. Nuova partita → Avvia ora → wizard si apre senza crash; step in EN.
  8. Wizard 3 step in EN; logo picker funziona.
  9. (Se possibile) overlay diretta: dialog/termina in EN.
  10. Kill app → riapri: lingua persistita e sessione resta se token valido.
  11. Spot-check FR/DE/ES.
  12. Release: ./scripts/build_ios_release.sh

Test:

cd native/ios
python3 generate_xcodeproj.py
xcodebuild -project MatchLiveTv.xcodeproj -scheme MatchLiveTv \
  -destination 'platform=iOS Simulator,name=iPhone 17' \
  -derivedDataPath build/DerivedData \
  ONLY_ACTIVE_ARCH=YES ARCHS=arm64 EXCLUDED_ARCHS=x86_64 \
  test -only-testing:MatchLiveTvTests

Note API / produzione

Android iOS
Default BuildConfig / -PAPI_BASE_URL API_BASE_URL → Info.plist
Fallback https://www.matchlivetv.it idem
REST / Cable /api/v1, wss://…/cable idem

Nessuna modifica server richiesta.

Artefatti Android Play (riferimento)

# APK installazione diretta
./scripts/build_native_android_apk_prod.sh

# AAB per Google Play Console
cd native/android && ./gradlew bundleRelease -PAPI_BASE_URL=https://www.matchlivetv.it
# → app/build/outputs/bundle/release/app-release.aab

Versione corrente store: 2.0.5-native / versionCode 26.


Sintesi priorità (ordine di esecuzione)

  1. A Catalogo stringhe completo (copiare da Android values*)
  2. C Hub + sheet/dialog (fix «Scegli squadra» in EN)
  3. B Slogan + globo Login (toolbar)
  4. D Wizard (+ no crash picker)
  5. E Broadcast
  6. F Sessione stabile al cambio lingua + versione 2.0.5 / 26 + build release

Quando AF sono chiusi, iOS è allineato ad Android 2.0.5-native per UX multilingua, stabilità sessione e versioning store.