diff --git a/Strand/Resources/Localizable.xcstrings b/Strand/Resources/Localizable.xcstrings index eabb5820..b7cbfd78 100644 --- a/Strand/Resources/Localizable.xcstrings +++ b/Strand/Resources/Localizable.xcstrings @@ -1,6 +1,52 @@ { "sourceLanguage": "en", "strings": { + "Night": { + "localizations": { + "de": { + "stringUnit": { + "state": "translated", + "value": "Nacht" + } + }, + "es": { + "stringUnit": { + "state": "translated", + "value": "Noche" + } + }, + "fr": { + "stringUnit": { + "state": "translated", + "value": "Nuit" + } + }, + "it": { + "stringUnit": { + "state": "translated", + "value": "Notte" + } + }, + "pt-PT": { + "stringUnit": { + "state": "translated", + "value": "Noite" + } + }, + "zh-Hans": { + "stringUnit": { + "state": "translated", + "value": "夜间" + } + }, + "zh-Hant": { + "stringUnit": { + "state": "translated", + "value": "夜間" + } + } + } + }, "": { "localizations": { "de": { diff --git a/Strand/Screens/SettingsView.swift b/Strand/Screens/SettingsView.swift index bfdf66b7..bc0a7c8d 100644 --- a/Strand/Screens/SettingsView.swift +++ b/Strand/Screens/SettingsView.swift @@ -249,10 +249,17 @@ struct SettingsView: View { /// iOS 16+ and macOS 13+ (NOOP's floor), so the same control serves both platforms — no /// availability gating needed. The photo is stored only on this device (NOOP is fully offline). private var profilePhotoCard: some View { - SettingsSection( + // #153: resolve the whole blurb through `String(localized:)` first, then hand SwiftUI the plain + // String via `LocalizedStringKey(_:)`. Interpolating `Platform.deviceNounPhrase` (itself an + // already-resolved localized String) straight into the `blurb:` `LocalizedStringKey` literal + // confused SwiftUI's text-measurement pass — the blurb rendered with zero trailing margin and + // clipped to the card edge instead of wrapping inside the card padding. The localization key is + // unchanged (`…Stored only on %@…`), so the existing translations still apply. + let blurbText = String(localized: "Optional. Add a photo for the avatar in the top-left. Stored only on \(Platform.deviceNounPhrase). NOOP is offline, so it's never uploaded.") + return SettingsSection( icon: "person.crop.circle", title: "Profile photo", - blurb: "Optional. Add a photo for the avatar in the top-left. Stored only on \(Platform.deviceNounPhrase). NOOP is offline, so it's never uploaded." + blurb: LocalizedStringKey(blurbText) ) { HStack(spacing: 16) { ProfileAvatarView(imageData: profile.avatarImageData, size: 64) @@ -270,7 +277,6 @@ struct SettingsView: View { .accessibilityHint("Reverts to the default profile icon") } } - .frame(maxWidth: .infinity) } } // Load the picked photo's bytes, then hand them to the store (which downscales + persists). @@ -889,7 +895,10 @@ struct SettingsView: View { // re-baselines (like a sleep edit). FormRow(label: "HRV window") { Picker("HRV window", selection: $hrvWindowRaw) { - Text("Whole night").tag(HrvWindow.whole.rawValue) + // #153: "Night" (not "Whole night") — a single short word so the two-segment + // control doesn't truncate once it sizes to the row (some locales' longer + // translations overflowed), matching the Temperature/Theme pickers above. + Text("Night").tag(HrvWindow.whole.rawValue) Text("Deep sleep").tag(HrvWindow.deep.rawValue) } .labelsHidden() diff --git a/android/app/src/main/java/com/noop/ui/SettingsScreen.kt b/android/app/src/main/java/com/noop/ui/SettingsScreen.kt index 17f6c835..05f20645 100644 --- a/android/app/src/main/java/com/noop/ui/SettingsScreen.kt +++ b/android/app/src/main/java/com/noop/ui/SettingsScreen.kt @@ -1355,7 +1355,9 @@ fun SettingsScreen( SegmentedPillControl( items = listOf(HrvWindow.WHOLE_NIGHT, HrvWindow.DEEP_SLEEP), selection = hrvWindow, - label = { if (it == HrvWindow.DEEP_SLEEP) "Deep sleep" else "Whole night" }, + // #153: "Night" (not "Whole night") so the two-segment pill reads the same as the iOS + // picker and stays short — keeps the label consistent across platforms. + label = { if (it == HrvWindow.DEEP_SLEEP) "Deep sleep" else "Night" }, onSelect = { hrvWindow = it UnitPrefs.setHrvWindow(context, it)