Fix #23: Tour-Übersetzung – deutsche Strings als Keys, Lokalisierungen ergänzt
- TourCatalog.swift: Technische Keys (tour.onboarding.*) durch deutschen Klartext ersetzt (konform mit Projekt-xcstrings-Konvention) - TourCardView.swift: Ternary-Ausdrucks-Bug behoben (String statt LocalizedStringKey); Button-Labels mit deutschen Strings - SettingsView.swift: settings.tours.* durch deutsche Keys ersetzt - Localizable.xcstrings: Technische Keys entfernt, alle Tour-Strings als deutsche Keys mit EN-Übersetzungen hinzugefügt (19 neue Einträge) - TourCatalogTests: import Foundation ergänzt (LocalizedStringResource) - TourCoordinatorTests: import CoreGraphics ergänzt (CGRect) - StoreTests: Closure-Argument-Fehler behoben (_ in) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -228,6 +228,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"%lld Schritte" : {
|
||||||
|
"comment" : "SettingsView – tour step count label (e.g. '6 Schritte')",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"variations" : {
|
||||||
|
"plural" : {
|
||||||
|
"one" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "%lld step"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"other" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "%lld steps"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"%lld von %lld" : {
|
||||||
|
"comment" : "TourCardView – step counter (e.g. '2 von 6')",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "%lld of %lld"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"%lld von %lld — Maximum erreicht" : {
|
"%lld von %lld — Maximum erreicht" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"de" : {
|
"de" : {
|
||||||
@@ -859,6 +893,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"App-Einführung" : {
|
||||||
|
"comment" : "TourCatalog – onboarding tour title shown in SettingsView",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "App Introduction"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"App-Schutz" : {
|
"App-Schutz" : {
|
||||||
"comment" : "SettingsView – section header for app lock settings",
|
"comment" : "SettingsView – section header for app lock settings",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -871,7 +916,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"App-Touren" : {
|
"App-Touren" : {
|
||||||
|
"comment" : "SettingsView – Tour section header",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "App Tours"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Arbeit" : {
|
"Arbeit" : {
|
||||||
"comment" : "PersonTag.work raw value",
|
"comment" : "PersonTag.work raw value",
|
||||||
@@ -1467,6 +1520,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Deine Menschen im Mittelpunkt" : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 2 title",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Your People at the Center"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Details" : {
|
"Details" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -1945,6 +2009,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Einblicke, wenn du willst" : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 6 title",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Insights When You Want Them"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Einrichten" : {
|
"Einrichten" : {
|
||||||
"comment" : "CallWindowSetupView – setup button label when onboarding",
|
"comment" : "CallWindowSetupView – setup button label when onboarding",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -2034,6 +2109,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Erfasse Treffen, Nachrichten und Erlebnisse. So weißt du, worüber ihr das letzte Mal geredet habt." : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 3 body",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Record meetings, messages, and experiences. So you know what you last talked about."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Ergebnis bestätigen und fortfahren" : {
|
"Ergebnis bestätigen und fortfahren" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -2350,8 +2436,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Füge Personen hinzu, die dir wichtig sind. Notiere Interessen, Gesprächsthemen und was euch verbindet." : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 2 body",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Add people who matter to you. Note interests, conversation topics, and what connects you."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Füge zuerst Personen im Tab „Menschen“ hinzu." : {
|
"Füge zuerst Personen im Tab „Menschen“ hinzu." : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Füge zuerst Personen im Tab „Menschen” hinzu." : {
|
||||||
"comment" : "TodayPersonPickerSheet – empty state hint when no contacts exist yet",
|
"comment" : "TodayPersonPickerSheet – empty state hint when no contacts exist yet",
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -3270,6 +3371,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Leg Vorhaben an und erhalte eine Erinnerung – damit aus 'Wir müssen mal wieder…' ein echtes Treffen wird." : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 4 body",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Create intentions and get a reminder – so 'We should catch up…' becomes a real meeting."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Limit erreicht" : {
|
"Limit erreicht" : {
|
||||||
"comment" : "LogbuchView – AI refresh button label when at request limit",
|
"comment" : "LogbuchView – AI refresh button label when at request limit",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -3335,6 +3447,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Loslegen" : {
|
||||||
|
"comment" : "TourCardView – finish button label on last tour step",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Let's go"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Mag ich" : {
|
"Mag ich" : {
|
||||||
"comment" : "IchView – likes preferences field label",
|
"comment" : "IchView – likes preferences field label",
|
||||||
"extractionState" : "stale",
|
"extractionState" : "stale",
|
||||||
@@ -3589,6 +3712,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Momente festhalten" : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 3 title",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Capture Moments"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Momente planen und hinzufügen" : {
|
"Momente planen und hinzufügen" : {
|
||||||
"comment" : "TodayView – empty state CTA button subtitle",
|
"comment" : "TodayView – empty state CTA button subtitle",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -3869,6 +4003,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nahbar erinnert dich, wenn du lange nichts von jemandem gehört hast. Du entscheidest, wie oft." : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 5 body",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "nahbar reminds you when you haven't heard from someone in a while. You decide how often."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nahbar hilft dir, echte Verbindungen zu pflegen – ohne Stress, ohne Algorithmen." : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 1 body",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "nahbar helps you nurture real connections – without stress, without algorithms."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"nahbar Max freischalten für KI-Analyse" : {
|
"nahbar Max freischalten für KI-Analyse" : {
|
||||||
"comment" : "LogbuchView – upsell button for AI analysis",
|
"comment" : "LogbuchView – upsell button for AI analysis",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -4288,6 +4444,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Optionale KI-Analyse zeigt Muster in deinen Verbindungen. Alles optional – deine Daten bleiben bei dir." : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 6 body",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Optional AI analysis shows patterns in your connections. Everything optional – your data stays with you."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Passend für dich" : {
|
"Passend für dich" : {
|
||||||
"extractionState" : "stale",
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -4384,6 +4551,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Plane das Nächste" : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 4 title",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Plan What's Next"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Plane Unternehmungen mit Erinnerung – nahbar erinnert dich zur richtigen Zeit." : {
|
"Plane Unternehmungen mit Erinnerung – nahbar erinnert dich zur richtigen Zeit." : {
|
||||||
"comment" : "OnboardingContainerView – feature tour card description for Unternehmung (intention type)",
|
"comment" : "OnboardingContainerView – feature tour card description for Unternehmung (intention type)",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -4546,6 +4724,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Sanfte Erinnerungen" : {
|
||||||
|
"comment" : "TourCatalog – onboarding step 5 title",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Gentle Reminders"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Schließen" : {
|
"Schließen" : {
|
||||||
"comment" : "PersonDetailView / ShareExtensionView – close button",
|
"comment" : "PersonDetailView / ShareExtensionView – close button",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -4691,32 +4880,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.tours.start" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"settings.tours.stepCount %lld" : {
|
|
||||||
"comment" : "SettingsView – step count label (e.g. '6 Schritte')",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"variations" : {
|
|
||||||
"plural" : {
|
|
||||||
"one" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "%lld step"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"other" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "%lld steps"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Signal" : {
|
"Signal" : {
|
||||||
"comment" : "MomentSource.signal raw value",
|
"comment" : "MomentSource.signal raw value",
|
||||||
"extractionState" : "stale",
|
"extractionState" : "stale",
|
||||||
@@ -5036,69 +5199,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tour.common.back" : {
|
"Tour schließen" : {
|
||||||
|
"comment" : "TourCardView – accessibility label for close button",
|
||||||
},
|
|
||||||
"tour.common.close" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.common.finish" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.common.next" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.common.skip" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.common.stepCounter %lld %lld" : {
|
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"de" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "new",
|
"state" : "translated",
|
||||||
"value" : "tour.common.stepCounter %1$lld %2$lld"
|
"value" : "Close tour"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tour.onboarding.step1.body" : {
|
"Tour starten" : {
|
||||||
|
"comment" : "SettingsView – button to replay a tour",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Start tour"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tour.onboarding.step1.title" : {
|
"Tour überspringen" : {
|
||||||
|
"comment" : "TourCardView – skip button label",
|
||||||
},
|
"localizations" : {
|
||||||
"tour.onboarding.step2.body" : {
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
},
|
"state" : "translated",
|
||||||
"tour.onboarding.step2.title" : {
|
"value" : "Skip tour"
|
||||||
|
}
|
||||||
},
|
}
|
||||||
"tour.onboarding.step3.body" : {
|
}
|
||||||
|
|
||||||
},
|
|
||||||
"tour.onboarding.step3.title" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.onboarding.step4.body" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.onboarding.step4.title" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.onboarding.step5.body" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.onboarding.step5.title" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.onboarding.step6.body" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.onboarding.step6.title" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"tour.onboarding.title" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Treffen" : {
|
"Treffen" : {
|
||||||
"comment" : "MomentType.meeting rawValue + VisitHistorySection / SettingsView section header",
|
"comment" : "MomentType.meeting rawValue + VisitHistorySection / SettingsView section header",
|
||||||
@@ -6135,6 +6267,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Zurück" : {
|
||||||
|
"comment" : "TourCardView – back button label",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Back"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Zusammen essen" : {
|
"Zusammen essen" : {
|
||||||
"comment" : "PersonDetailView – activity suggestion: have a meal together (group)",
|
"comment" : "PersonDetailView – activity suggestion: have a meal together (group)",
|
||||||
"extractionState" : "stale",
|
"extractionState" : "stale",
|
||||||
|
|||||||
@@ -608,12 +608,12 @@ struct SettingsView: View {
|
|||||||
Text(tour.title)
|
Text(tour.title)
|
||||||
.font(.system(size: 15))
|
.font(.system(size: 15))
|
||||||
.foregroundStyle(theme.contentPrimary)
|
.foregroundStyle(theme.contentPrimary)
|
||||||
Text(String.localizedStringWithFormat(String(localized: "settings.tours.stepCount %lld"), Int64(tour.steps.count)))
|
Text(String.localizedStringWithFormat(String(localized: "%lld Schritte"), Int64(tour.steps.count)))
|
||||||
.font(.system(size: 12))
|
.font(.system(size: 12))
|
||||||
.foregroundStyle(theme.contentTertiary)
|
.foregroundStyle(theme.contentTertiary)
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
Button(String(localized: "settings.tours.start")) {
|
Button("Tour starten") {
|
||||||
tourCoordinator.start(tour.id)
|
tourCoordinator.start(tour.id)
|
||||||
}
|
}
|
||||||
.font(.system(size: 13, weight: .medium))
|
.font(.system(size: 13, weight: .medium))
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ struct TourCardView: View {
|
|||||||
.padding(8)
|
.padding(8)
|
||||||
.background(Color.secondary.opacity(0.12), in: Circle())
|
.background(Color.secondary.opacity(0.12), in: Circle())
|
||||||
}
|
}
|
||||||
.accessibilityLabel(Text("tour.common.close"))
|
.accessibilityLabel("Tour schließen")
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 20)
|
||||||
.padding(.top, 18)
|
.padding(.top, 18)
|
||||||
@@ -56,14 +56,13 @@ struct TourCardView: View {
|
|||||||
Button {
|
Button {
|
||||||
coordinator.skip()
|
coordinator.skip()
|
||||||
} label: {
|
} label: {
|
||||||
Text("tour.common.skip")
|
Text("Tour überspringen")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(.tertiary)
|
.foregroundStyle(.tertiary)
|
||||||
}
|
}
|
||||||
.accessibilityLabel(Text("tour.common.skip"))
|
|
||||||
|
|
||||||
Text(verbatim: String.localizedStringWithFormat(
|
Text(verbatim: String.localizedStringWithFormat(
|
||||||
String(localized: "tour.common.stepCounter %lld %lld"),
|
String(localized: "%lld von %lld"),
|
||||||
Int64(currentIndex + 1),
|
Int64(currentIndex + 1),
|
||||||
Int64(totalSteps)
|
Int64(totalSteps)
|
||||||
))
|
))
|
||||||
@@ -78,18 +77,19 @@ struct TourCardView: View {
|
|||||||
Button {
|
Button {
|
||||||
coordinator.previous()
|
coordinator.previous()
|
||||||
} label: {
|
} label: {
|
||||||
Text("tour.common.back")
|
Text("Zurück")
|
||||||
.font(.subheadline.weight(.medium))
|
.font(.subheadline.weight(.medium))
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
.padding(.trailing, 8)
|
.padding(.trailing, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next / Finish button
|
// Next / Finish button — explicit LocalizedStringKey to ensure lookup
|
||||||
|
let nextLabel: LocalizedStringKey = coordinator.isLastStep ? "Loslegen" : "Weiter"
|
||||||
Button {
|
Button {
|
||||||
coordinator.next()
|
coordinator.next()
|
||||||
} label: {
|
} label: {
|
||||||
Text(coordinator.isLastStep ? "tour.common.finish" : "tour.common.next")
|
Text(nextLabel)
|
||||||
.font(.subheadline.weight(.semibold))
|
.font(.subheadline.weight(.semibold))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.padding(.horizontal, 18)
|
.padding(.horizontal, 18)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Foundation
|
|||||||
// MARK: - TourCatalog
|
// MARK: - TourCatalog
|
||||||
|
|
||||||
/// Static registry of all tours defined in the app.
|
/// Static registry of all tours defined in the app.
|
||||||
|
/// Strings use German text as keys (consistent with project xcstrings convention).
|
||||||
/// New tours are added as static properties and included in `all`.
|
/// New tours are added as static properties and included in `all`.
|
||||||
enum TourCatalog {
|
enum TourCatalog {
|
||||||
|
|
||||||
@@ -10,41 +11,41 @@ enum TourCatalog {
|
|||||||
|
|
||||||
static let onboarding = Tour(
|
static let onboarding = Tour(
|
||||||
id: .onboarding,
|
id: .onboarding,
|
||||||
title: "tour.onboarding.title",
|
title: "App-Einführung",
|
||||||
steps: [
|
steps: [
|
||||||
TourStep(
|
TourStep(
|
||||||
title: "tour.onboarding.step1.title",
|
title: "Willkommen bei nahbar",
|
||||||
body: "tour.onboarding.step1.body",
|
body: "nahbar hilft dir, echte Verbindungen zu pflegen – ohne Stress, ohne Algorithmen.",
|
||||||
target: nil,
|
target: nil,
|
||||||
preferredCardPosition: .center
|
preferredCardPosition: .center
|
||||||
),
|
),
|
||||||
TourStep(
|
TourStep(
|
||||||
title: "tour.onboarding.step2.title",
|
title: "Deine Menschen im Mittelpunkt",
|
||||||
body: "tour.onboarding.step2.body",
|
body: "Füge Personen hinzu, die dir wichtig sind. Notiere Interessen, Gesprächsthemen und was euch verbindet.",
|
||||||
target: nil,
|
target: nil,
|
||||||
preferredCardPosition: .center
|
preferredCardPosition: .center
|
||||||
),
|
),
|
||||||
TourStep(
|
TourStep(
|
||||||
title: "tour.onboarding.step3.title",
|
title: "Momente festhalten",
|
||||||
body: "tour.onboarding.step3.body",
|
body: "Erfasse Treffen, Nachrichten und Erlebnisse. So weißt du, worüber ihr das letzte Mal geredet habt.",
|
||||||
target: nil,
|
target: nil,
|
||||||
preferredCardPosition: .center
|
preferredCardPosition: .center
|
||||||
),
|
),
|
||||||
TourStep(
|
TourStep(
|
||||||
title: "tour.onboarding.step4.title",
|
title: "Plane das Nächste",
|
||||||
body: "tour.onboarding.step4.body",
|
body: "Leg Vorhaben an und erhalte eine Erinnerung – damit aus 'Wir müssen mal wieder…' ein echtes Treffen wird.",
|
||||||
target: nil,
|
target: nil,
|
||||||
preferredCardPosition: .center
|
preferredCardPosition: .center
|
||||||
),
|
),
|
||||||
TourStep(
|
TourStep(
|
||||||
title: "tour.onboarding.step5.title",
|
title: "Sanfte Erinnerungen",
|
||||||
body: "tour.onboarding.step5.body",
|
body: "nahbar erinnert dich, wenn du lange nichts von jemandem gehört hast. Du entscheidest, wie oft.",
|
||||||
target: nil,
|
target: nil,
|
||||||
preferredCardPosition: .center
|
preferredCardPosition: .center
|
||||||
),
|
),
|
||||||
TourStep(
|
TourStep(
|
||||||
title: "tour.onboarding.step6.title",
|
title: "Einblicke, wenn du willst",
|
||||||
body: "tour.onboarding.step6.body",
|
body: "Optionale KI-Analyse zeigt Muster in deinen Verbindungen. Alles optional – deine Daten bleiben bei dir.",
|
||||||
target: nil,
|
target: nil,
|
||||||
preferredCardPosition: .center
|
preferredCardPosition: .center
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -483,7 +483,7 @@ struct InterestTagHelperSuggestionsTests {
|
|||||||
@Test("Duplikate werden dedupliziert")
|
@Test("Duplikate werden dedupliziert")
|
||||||
func deduplicates() {
|
func deduplicates() {
|
||||||
let result = InterestTagHelper.allSuggestions(from: [], likes: "Kino, Musik", dislikes: "Kino")
|
let result = InterestTagHelper.allSuggestions(from: [], likes: "Kino, Musik", dislikes: "Kino")
|
||||||
#expect(!result.contains { result.filter { $0 == "Kino" }.count > 1 })
|
#expect(!result.contains { _ in result.filter { $0 == "Kino" }.count > 1 })
|
||||||
#expect(result.filter { $0 == "Kino" }.count == 1)
|
#expect(result.filter { $0 == "Kino" }.count == 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import Foundation
|
||||||
import Testing
|
import Testing
|
||||||
@testable import nahbar
|
@testable import nahbar
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Testing
|
import CoreGraphics
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Testing
|
||||||
@testable import nahbar
|
@testable import nahbar
|
||||||
|
|
||||||
// MARK: - TourCoordinator Tests
|
// MARK: - TourCoordinator Tests
|
||||||
|
|||||||
Reference in New Issue
Block a user