feat(i18n): complete internationalization for iOS + watchOS across all views
Migrate every hardcoded Text("...") string to the L10n / LocalizedStringResource
type-safe key system with full en/fr/de/es translations (4 languages).
iOS changes (TabataGo target):
- Strings.swift: ~90 new L10n keys across 13 groups (action, tab, home, zone,
level, programs, programDetail, player, profile, settings, policy, paywall,
health, complete, activity, onboarding, goal)
- Localizable.xcstrings: 145 → 245+ keys with fr/de/es translations
- Model enums: FitnessLevel.label & FitnessGoal.label changed from String to
LocalizedStringResource, backed by L10n.level/goal keys
- Component param types changed to LocalizedStringResource: StatBadge,
SectionHeader, ProfileRow, PolicySection, CompletionStat, FeatureRow,
OnboardingHeader, PrimaryButton, SelectionCard
- All 18 view files updated: HomeTab, ActivityTab, ProgramsTab, ProfileTab,
MainTabView, SettingsView, PolicyViews, CompletionView, BodyZoneView,
ProgramDetailView, PaywallView, OnboardingView, PlayerView
Watch changes (TabataGoWatch target):
- New Localizable.xcstrings: 23 keys with en/fr/de/es (phase labels, idle
state, activity rings, complication strings)
- New WatchL10n.swift: type-safe enum (needs manual Xcode target membership)
- Updated: WatchPlayerView, WatchIdleView, WatchActivityView,
TabataGoComplication (inline LocalizedStringResource for widget target)
Both iOS and watchOS targets build with zero errors.
This commit is contained in:
@@ -38,14 +38,14 @@ struct TabataProvider: TimelineProvider {
|
||||
}
|
||||
|
||||
private func relativeLabel(for date: Date?) -> String {
|
||||
guard let date else { return "Not started" }
|
||||
guard let date else { return String(localized: LocalizedStringResource("watch.complication.notStarted")) }
|
||||
let days = Calendar.current.dateComponents([.day],
|
||||
from: Calendar.current.startOfDay(for: date),
|
||||
to: Calendar.current.startOfDay(for: Date())).day ?? 0
|
||||
switch days {
|
||||
case 0: return "Today"
|
||||
case 1: return "Yesterday"
|
||||
default: return "\(days) days ago"
|
||||
case 0: return String(localized: LocalizedStringResource("watch.complication.today"))
|
||||
case 1: return String(localized: LocalizedStringResource("watch.complication.yesterday"))
|
||||
default: return String(format: String(localized: LocalizedStringResource("watch.complication.daysAgoFmt")), days)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,13 +82,13 @@ struct RectangularComplicationView: View {
|
||||
Image(systemName: "bolt.fill")
|
||||
.foregroundStyle(.orange)
|
||||
.font(.system(size: 10, weight: .bold))
|
||||
Text("\(entry.streak) day streak")
|
||||
Text(String(format: String(localized: LocalizedStringResource("watch.complication.dayStreakFmt")), entry.streak))
|
||||
.font(.system(size: 12, weight: .bold, design: .rounded))
|
||||
}
|
||||
Text(entry.lastWorkoutLabel)
|
||||
.font(.system(size: 11))
|
||||
.foregroundStyle(.secondary)
|
||||
Text("Open TabataGo →")
|
||||
Text(String(localized: LocalizedStringResource("watch.complication.openApp")))
|
||||
.font(.system(size: 10, weight: .medium))
|
||||
.foregroundStyle(.orange)
|
||||
}
|
||||
@@ -108,7 +108,7 @@ struct CornerComplicationView: View {
|
||||
.font(.system(size: 14, weight: .bold))
|
||||
.foregroundStyle(.orange)
|
||||
}
|
||||
.widgetLabel("\(entry.streak) day streak")
|
||||
.widgetLabel(String(format: String(localized: LocalizedStringResource("watch.complication.dayStreakFmt")), entry.streak))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ struct TabataGoComplication: Widget {
|
||||
.containerBackground(.black, for: .widget)
|
||||
}
|
||||
.configurationDisplayName("TabataGo")
|
||||
.description("Your current workout streak.")
|
||||
.description(String(localized: LocalizedStringResource("watch.complication.description")))
|
||||
.supportedFamilies([
|
||||
.accessoryCircular,
|
||||
.accessoryRectangular,
|
||||
|
||||
Reference in New Issue
Block a user