import SwiftUI @main struct RouterOSAssistantApp: App { @StateObject private var connectionService = ConnectionService() @StateObject private var manualNavigator = ManualNavigator() /// Manual language override — independent of the system locale, per the user's explicit /// request for an in-app toggle button. `.environment(\.locale, ...)` does NOT make /// `Text(LocalizedStringKey)` re-resolve against Localizable.xcstrings at runtime (confirmed /// live: toggling had no visible effect), so views read this same AppStorage key directly and /// translate via `L10n.t(_:_:)` instead. @AppStorage("appLanguage") private var appLanguage: String = "de" @AppStorage(AppPreferences.textSizeKey) private var textSizeRaw: String = AppTextSize.standard.rawValue @AppStorage(AppPreferences.uiDensityKey) private var uiDensityRaw: String = UIDensity.standard.rawValue init() { AppPreferences.registerDefaults() } var body: some Scene { WindowGroup { TabView { ConnectView(connectionService: connectionService) .tabItem { Label(L10n.t("Verbinden", appLanguage), systemImage: "network") } SetupView(connectionService: connectionService) .tabItem { Label(L10n.t("Einrichten", appLanguage), systemImage: "checklist") } OverviewView(connectionService: connectionService) .tabItem { Label(L10n.t("Übersicht", appLanguage), systemImage: "point.3.connected.trianglepath.dotted") } DevicesView(connectionService: connectionService) .tabItem { Label(L10n.t("LAN-Scanner", appLanguage), systemImage: "laptopcomputer.and.iphone") } ExpertView(connectionService: connectionService) .tabItem { Label(L10n.t("Experte", appLanguage), systemImage: "wrench.and.screwdriver") } BackupListView(connectionService: connectionService) .tabItem { Label(L10n.t("Sicherungen", appLanguage), systemImage: "clock.arrow.circlepath") } } .toolbar { ToolbarItem { Button { appLanguage = (appLanguage == "de") ? "en" : "de" } label: { // Flag of the language a tap switches TO — matches the "DE"/"EN" text // labels this replaces, which showed the same "switch to" target. Text(appLanguage == "de" ? "🇬🇧" : "🇩🇪") } .help(appLanguage == "de" ? "Switch to English" : "Auf Deutsch umschalten") } } .controlSize((UIDensity(rawValue: uiDensityRaw) ?? .standard).controlSize) .environment(\.appFontScale, (AppTextSize(rawValue: textSizeRaw) ?? .standard).scale) // Fallback for every `Text`/`TextField`/`Label` that has no explicit `.font(...)` of // its own (confirmed live: the Experte tab's whole sidebar list and every Parameter/ // Wert `TextField` have none — `.appFont(...)` only touches call sites that already // had a `.font(...)` to replace, so unstyled text stayed fixed-size). `.environment // (\.font, ...)` only ever supplies a *default*: anywhere `.appFont(...)` already sets // an explicit font, that still wins. .environment(\.font, .system(size: 13 * ((AppTextSize(rawValue: textSizeRaw) ?? .standard).scale))) .environmentObject(manualNavigator) } .environment(\.locale, Locale(identifier: appLanguage)) Settings { SettingsView() .environmentObject(manualNavigator) } Window(L10n.t("Handbuch", appLanguage), id: "manual") { ManualView() .environmentObject(manualNavigator) } } }