Files
emergency/lib/core/country_locale_map.dart
rootandClaude Sonnet 5 e3aa088bc2 Notrufnummern-Datenbasis, Ländererkennung, State-Management und Lokalisierung (AP1-AP7)
Implementiert den kompletten Kern-Flow der Emergency App gemäß docs/plan.md:
- Notrufnummern-Datenbasis für 199 Länder + Modelle/Repository (AP1)
- DialerService für tel:-Notrufe ohne Auto-Dial (AP2)
- Statisches UI mit Panik-Button-Fallback (AP3)
- Priorisierte Ländererkennung: SIM/Netz -> GPS/Geocoding -> Cache (AP4)
- EmergencyProvider verdrahtet Repository/LocationService mit der UI (AP5)
- Manuelle Länderauswahl als Fallback samt eigener Priorität (AP6)
- UI-Lokalisierung (de/en/fr/es), an erkanntes Land gekoppelt (AP7)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 11:29:38 +02:00

244 lines
4.9 KiB
Dart
Raw Permalink 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.
import 'package:flutter/widgets.dart';
/// Ordnet ISO 3166-1 alpha-2 Ländercodes eine primäre Amts-/Mehrheitssprache
/// (ISO 639-1) zu (`docs/plan.md`, Abschnitt 2 + 8, AP7: "Lokalisierung:
/// Sprache an erkanntes Land gekoppelt").
///
/// **Bewusst pragmatisch, nicht für jedes Land 100% exakt:** Viele Länder
/// sind mehrsprachig (z. B. Belgien, Kamerun); hier wird jeweils die
/// praktisch sinnvollste/meistgesprochene Amtssprache gewählt. Deckt alle
/// Länder aus `assets/data/emergency_numbers.json` ab, ohne Anspruch auf
/// linguistische Vollständigkeit die App braucht daraus nur eine
/// plausible UI-Sprache, nicht eine sprachwissenschaftlich exakte Aussage.
///
/// Die meisten hier gelisteten Sprachen haben (Stand AP7) **keine** eigene
/// ARB-Übersetzung (nur `de`/`en`/`fr`/`es` existieren) das ist gewollt,
/// siehe [resolveAppLocale]: Nicht unterstützte Sprachen fallen automatisch
/// auf Englisch zurück.
const Map<String, String> countryLocaleMap = {
'AD': 'ca',
'AE': 'ar',
'AF': 'fa',
'AG': 'en',
'AL': 'sq',
'AM': 'hy',
'AO': 'pt',
'AR': 'es',
'AT': 'de',
'AU': 'en',
'AZ': 'az',
'BA': 'bs',
'BB': 'en',
'BD': 'bn',
'BE': 'nl',
'BF': 'fr',
'BG': 'bg',
'BH': 'ar',
'BI': 'rn',
'BJ': 'fr',
'BN': 'ms',
'BO': 'es',
'BR': 'pt',
'BS': 'en',
'BT': 'dz',
'BW': 'en',
'BY': 'be',
'BZ': 'en',
'CA': 'en',
'CD': 'fr',
'CF': 'fr',
'CG': 'fr',
'CH': 'de',
'CI': 'fr',
'CL': 'es',
'CM': 'fr',
'CN': 'zh',
'CO': 'es',
'CR': 'es',
'CU': 'es',
'CV': 'pt',
'CY': 'el',
'CZ': 'cs',
'DE': 'de',
'DJ': 'fr',
'DK': 'da',
'DM': 'en',
'DO': 'es',
'DZ': 'ar',
'EC': 'es',
'EE': 'et',
'EG': 'ar',
'ER': 'ti',
'ES': 'es',
'ET': 'am',
'FI': 'fi',
'FJ': 'en',
'FM': 'en',
'FR': 'fr',
'GA': 'fr',
'GB': 'en',
'GD': 'en',
'GE': 'ka',
'GH': 'en',
'GM': 'en',
'GN': 'fr',
'GQ': 'es',
'GR': 'el',
'GT': 'es',
'GW': 'pt',
'GY': 'en',
'HK': 'zh',
'HN': 'es',
'HR': 'hr',
'HT': 'fr',
'HU': 'hu',
'ID': 'id',
'IE': 'en',
'IL': 'he',
'IN': 'hi',
'IQ': 'ar',
'IR': 'fa',
'IS': 'is',
'IT': 'it',
'JM': 'en',
'JO': 'ar',
'JP': 'ja',
'KE': 'sw',
'KG': 'ky',
'KH': 'km',
'KI': 'en',
'KM': 'ar',
'KN': 'en',
'KP': 'ko',
'KR': 'ko',
'KW': 'ar',
'KZ': 'kk',
'LA': 'lo',
'LB': 'ar',
'LC': 'en',
'LI': 'de',
'LK': 'si',
'LR': 'en',
'LS': 'en',
'LT': 'lt',
'LU': 'fr',
'LV': 'lv',
'LY': 'ar',
'MA': 'ar',
'MC': 'fr',
'MD': 'ro',
'ME': 'sr',
'MG': 'fr',
'MH': 'en',
'MK': 'mk',
'ML': 'fr',
'MM': 'my',
'MN': 'mn',
'MO': 'zh',
'MR': 'ar',
'MT': 'mt',
'MU': 'en',
'MV': 'dv',
'MW': 'en',
'MX': 'es',
'MY': 'ms',
'MZ': 'pt',
'NA': 'en',
'NE': 'fr',
'NG': 'en',
'NI': 'es',
'NL': 'nl',
'NO': 'nb',
'NP': 'ne',
'NR': 'en',
'NZ': 'en',
'OM': 'ar',
'PA': 'es',
'PE': 'es',
'PG': 'en',
'PH': 'en',
'PK': 'ur',
'PL': 'pl',
'PS': 'ar',
'PT': 'pt',
'PW': 'en',
'PY': 'es',
'QA': 'ar',
'RO': 'ro',
'RS': 'sr',
'RU': 'ru',
'RW': 'rw',
'SA': 'ar',
'SB': 'en',
'SC': 'en',
'SD': 'ar',
'SE': 'sv',
'SG': 'en',
'SI': 'sl',
'SK': 'sk',
'SL': 'en',
'SM': 'it',
'SN': 'fr',
'SO': 'so',
'SR': 'nl',
'SS': 'en',
'ST': 'pt',
'SV': 'es',
'SY': 'ar',
'SZ': 'en',
'TD': 'fr',
'TG': 'fr',
'TH': 'th',
'TJ': 'tg',
'TL': 'pt',
'TM': 'tk',
'TN': 'ar',
'TO': 'en',
'TR': 'tr',
'TT': 'en',
'TV': 'en',
'TW': 'zh',
'TZ': 'sw',
'UA': 'uk',
'UG': 'en',
'US': 'en',
'UY': 'es',
'UZ': 'uz',
'VA': 'it',
'VC': 'en',
'VE': 'es',
'VN': 'vi',
'VU': 'en',
'WS': 'en',
'XK': 'sq',
'YE': 'ar',
'ZA': 'en',
'ZM': 'en',
'ZW': 'en',
};
/// Sprache, auf die zurückgefallen wird, wenn kein gemapptes/unterstütztes
/// Ergebnis ermittelbar ist. Muss immer als `AppLocalizations.supportedLocales`
/// vorhanden sein.
const _fallbackLanguageCode = 'en';
/// Berechnet die effektiv zu verwendende App-[Locale] aus einem (optionalen)
/// ISO 3166-1 alpha-2 Ländercode und der Liste tatsächlich unterstützter
/// Locales (`AppLocalizations.supportedLocales`).
///
/// Regeln (`docs/plan.md`, Abschnitt 2 + 8, AP7):
/// - [isoCode] ist `null` (Land noch nicht ermittelt/unbekannt) → Fallback
/// Englisch, kein Rätselraten über die Gerätesystemsprache.
/// - [isoCode] ist nicht in [countryLocaleMap] gelistet → Fallback Englisch.
/// - Die gemappte Sprache ist nicht in [supportedLocales] enthalten (also
/// keine ARB-Übersetzung vorhanden) → Fallback Englisch.
/// - Sonst: die gemappte Sprache.
Locale resolveAppLocale(String? isoCode, List<Locale> supportedLocales) {
final languageCode = isoCode == null ? null : countryLocaleMap[isoCode.toUpperCase()];
if (languageCode != null &&
supportedLocales.any((locale) => locale.languageCode == languageCode)) {
return Locale(languageCode);
}
return const Locale(_fallbackLanguageCode);
}