Files
MatchLiveTv/docs/IOS_ANDROID_I18N_GAP.md
T
eminuxandCursor adceb8f13f Documenta il gap i18n Android→iOS per continuare sul Mac.
Checklist operativa con file, chiavi stringa e bump versione per allineare l’app iOS alla release Android 2.0.3.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 01:04:42 +02:00

185 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Gap Android → iOS: allineamento app nativa
Documento operativo per continuare su **Mac** lo sviluppo iOS e rilasciare unapp allineata a quanto già fatto (e rilasciato) su Android.
**Data:** 24 luglio 2026
**Riferimento Android rilasciato:** `2.0.3-native` (`versionCode` 24), API `https://www.matchlivetv.it`
**Stato iOS attuale:** marketing `2.0.0`, build `21` — i18n solo parziale
---
## Contesto
Dopo il rilascio web i18n (IT/EN/FR/DE/ES) e dellAPK Android di produzione, lapp Android ha:
- selettore lingua persistito
- Login + hub Partite localizzati in 5 lingue
- bump versione 2.0.3 / 24
Su iOS linfrastruttura lingua esiste (`AppLanguage` + picker), ma **Matches e slogan restano in italiano** e la versione è indietro.
API produzione: entrambe le app puntano già a `https://www.matchlivetv.it` di default — **nessun gap di endpoint**.
---
## Stato a confronto
| Area | Android | iOS |
|------|---------|-----|
| Persistenza lingua | SharedPreferences `mltv_locale` + `AppLocale.wrap` + recreate | UserDefaults `mltv.appLanguage` + notification |
| Picker lingua | `LanguagePickerDialog` su Login + Matches | `LanguagePickerView` su Login + Matches |
| Login localizzato | Sì (5 lingue) | Sì (5 lingue via `L10n`) |
| Hub Partite localizzato | Sì (~20 stringhe hub) | **No** — testi IT hardcoded |
| Slogan wordmark | `R.string.app_slogan` | Chiave `app.slogan` in `L10n` **non usata** |
| Catalogo stringhe | `res/values*` (47 chiavi × 5) | Dizionario in `AppLanguage.swift` (~14 chiavi) |
| Logout UI | Icona | Testo «Esci» |
| Versione | `2.0.3-native` / 24 | `2.0.0` / 21 |
| RTMP ingest rewrite | `RtmpIngestUrl.kt` + test | `MediaUrl.swift` (ok in prod; semantica dev leggermente diversa) |
| Wizard / Broadcast | Ancora IT hardcoded | Ancora IT hardcoded (stesso debito) |
---
## File di riferimento
### Android (sorgente “già fatto”)
| Ruolo | Path |
|-------|------|
| Locale | `native/android/app/src/main/kotlin/.../core/AppLocale.kt` |
| Picker | `native/android/app/src/main/kotlin/.../ui/components/LanguagePickerDialog.kt` |
| Activity | `native/android/app/src/main/kotlin/.../MainActivity.kt` |
| Stringhe IT | `native/android/app/src/main/res/values/strings.xml` |
| Stringhe EN/FR/DE/ES | `native/android/app/src/main/res/values-{en,fr,de,es}/strings.xml` |
| Hub | `.../ui/matches/MatchesScreen.kt`, `MatchSheets.kt` |
| Login | `.../ui/login/LoginScreen.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` |
| Wordmark | `native/ios/MatchLiveTv/UI/Components/MatchLiveWordmark.swift` (verificare path esatto) |
| Versioni | `native/ios/generate_xcodeproj.py`, `MatchLiveTv.xcodeproj/project.pbxproj`, `Info.plist` |
| Build release | `scripts/build_ios_release.sh` |
| README | `native/ios/README.md` |
---
## Checklist allineamento iOS (ordine consigliato)
### 1. Completare stringhe hub (priorità alta)
In `AppLanguage.swift` (`L10n.table`), aggiungere chiavi allineate ad Android per **it/en/fr/de/es**. Mapping suggerito:
| Chiave iOS (`L10n`) | Android `strings.xml` | Note |
|---------------------|----------------------|------|
| `matches.hello` | `matches_hello` | formato `"Ciao, %@"` / `"Hi, %@"` |
| `matches.subtitle` | `matches_subtitle` | |
| `matches.schedule` | `matches_schedule` | |
| `matches.new` | `matches_new` | |
| `matches.empty_title` | `matches_empty_title` | |
| `matches.scheduled_title` | `matches_scheduled_title` | |
| `matches.ready_title` | `matches_ready_title` | |
| `matches.empty_hint` | `matches_empty_hint` | |
| `matches.active_team` | `matches_active_team` | `%@` |
| `matches.multi_team_hint` | `matches_multi_team_hint` | |
| `matches.no_other` | `matches_no_other` | |
| `matches.retry` | `matches_retry` | |
| `matches.load_error` | `matches_load_error` | |
| `matches.no_team_title` | `matches_no_team_title` | |
| `matches.no_team_body` | `matches_no_team_body` | |
| `matches.tap_change_team` | `matches_tap_change_team` | |
| `matches.team_for_live` | `matches_team_for_live` | |
| `matches.change` | `matches_change` | |
| `action.save` | `action_save` | se usato in sheet |
| `language.*` | già presenti | |
Copiare le traduzioni da `values-en|fr|de|es/strings.xml` (testo già validato su Android).
Poi in `MatchesScreen.swift`:
- sostituire ogni `Text("…")` / titolo sezione / empty state / alert con `L10n.t(...)`
- empty “nessuna squadra” → `matches.no_team_title` / `matches.no_team_body`
- assicurarsi che `.id(languageTick)` (o equivalente) ricarichi lhub al cambio lingua
### 2. Slogan wordmark (priorità alta)
In `MatchLiveWordmark` (o componente equivalente):
- usare `L10n.t("app.slogan")` al posto della stringa italiana fissa
- verificare sul Login in EN/FR/DE/ES
### 3. Versione release (priorità media)
Allineare a Android (o policy store equivalente):
- `MARKETING_VERSION``2.0.3` (o `2.0.3-native` se accettato da App Store Connect)
- `CURRENT_PROJECT_VERSION``24` (o build successiva se 21/22/23 già usati su TestFlight)
Aggiornare **sia** `generate_xcodeproj.py` **sia** `Info.plist` (`CFBundleShortVersionString` / `CFBundleVersion`) prima di regenerare il progetto.
### 4. Logout icon (priorità bassa)
In top bar Matches: SF Symbol tipo `rectangle.portrait.and.arrow.right` + `accessibilityLabel` da `L10n.t("action.logout")`, come icona logout Android.
### 5. Opzionale — tooling stringhe
Migrare da dizionario Swift a `Localizable.xcstrings` (o `*.lproj`) per parità con Android `values-*` e revisione traduzioni in Xcode.
### 6. Fuori scope immediato (stesso debito Android)
Wizard 3 step, Broadcast overlay, dialoghi set/partita: ancora IT hardcoded su **entrambe** le piattaforme. Non bloccano lallineamento Login/Matches/i18n di questa release.
---
## Verifica manuale su Mac (pre-release)
1. `cd native/ios && python3 generate_xcodeproj.py`
2. Build debug su simulatore; login con utenza di produzione (o staging).
3. Cambia lingua Login → English: label + errori + slogan in EN.
4. Entra in Matches: saluto, sezioni, empty state, CTA in EN (non italiano).
5. Kill app e riapri: lingua persistita.
6. Ripeti spot-check FR/DE/ES.
7. Release: dalla root repo
`./scripts/build_ios_release.sh`
(default API già `https://www.matchlivetv.it`; override con `API_BASE_URL=...` se serve).
Test automatici (da README iOS):
```bash
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 | `-PAPI_BASE_URL` / BuildConfig | `API_BASE_URL` in build settings → Info.plist |
| Fallback | `https://www.matchlivetv.it` | idem in `AppConfig` |
| REST | `{base}/api/v1` | idem |
| Cable | `wss://…/cable` | idem |
Nessuna modifica server richiesta per allineare iOS: stesso backend già in produzione con i18n web.
---
## Sintesi priorità
1. **Alta** — Localizzare hub Matches (oggi cambio lingua incompleto).
2. **Alta** — Collegare slogan wordmark a `L10n`.
3. **Media** — Bump versione 2.0.3 / 24.
4. **Bassa** — Icona logout; migrazione a xcstrings; fine-tuning RTMP solo per dev.
Quando questi punti sono chiusi, lapp iOS è allineata alla release Android `2.0.3-native` per UX lingua e store versioning.