Files
RouterOS/RouterOSAssistant/App/RouterOSAssistantApp.swift
T
KayandClaude Sonnet 5 3a26f50800 M31: Handbuch in der App (Textanker, DE+EN)
"?"-Hilfe-Buttons in allen 6 Haupt-Tabs, allen 6 Wizard-Schritten und
allen 45 Experte-Menüs öffnen ein Handbuch-Fenster (WKWebView) und
springen per Textanker direkt zur passenden Manual-Stelle.

build-manual.py generalisiert auf beliebig viele Sprachen (LANGUAGES-
Dict) statt hart DE/EN. Manual.en.md: komplette Handübersetzung aller
Fließtext-Kapitel. Kapitel 5 (Experte-Referenz) wird pro Sprache
automatisch übersetzt, indem L10n.swifts eigenes App-Übersetzungs-
Dictionary wiederverwendet wird (714 Einträge geparst) statt einer
zweiten, separat gepflegten Übersetzung.

Live bestätigt (DE und EN).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 17:15:29 +02:00

72 lines
3.9 KiB
Swift

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)
}
}
}