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>
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user