Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Platform/Shared/BusyOverlay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct BusyOverlay: View {
.alert(item: $data.alertItem) { item in
switch item {
case .downloadUrl(let url):
return Alert(title: Text("Download VM"), message: Text("Do you want to download '\(url)'?"), primaryButton: .cancel(), secondaryButton: .default(Text("Download")) {
return Alert(title: Text(NSLocalizedString("Download VM", comment: "BusyOverlay")), message: Text(String.localizedStringWithFormat(NSLocalizedString("Do you want to download '%@'?", comment: "BusyOverlay"), url.absoluteString)), primaryButton: .cancel(), secondaryButton: .default(Text(NSLocalizedString("Download", comment: "BusyOverlay"))) {
data.downloadUTMZip(from: url)
})
case .message(let message):
Expand Down
4 changes: 2 additions & 2 deletions Platform/Shared/UTMTips.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ struct UTMTipDonate: Tip {
}

var actions: [Action] {
Action(id: "donate", title: "Donate")
Action(id: "no-thanks", title: "No Thanks")
Action(id: "donate", title: NSLocalizedString("Donate", comment: "UTMTips"))
Action(id: "no-thanks", title: NSLocalizedString("No Thanks", comment: "UTMTips"))
}

var rules: [Rule] {
Expand Down
6 changes: 3 additions & 3 deletions Platform/Shared/VMConfigDriveDetailsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ struct VMConfigDriveDetailsView: View {
}.alert(item: $confirmAlert) { item in
switch item {
case .reclaim(let imageURL):
return Alert(title: Text("Would you like to re-convert this disk image to reclaim unused space? Note this will require enough temporary space to perform the conversion. You are strongly encouraged to back-up this VM before proceeding."), primaryButton: .destructive(Text("Reclaim")) { reclaimSpace(for: imageURL, withCompression: false) }, secondaryButton: .cancel())
return Alert(title: Text(NSLocalizedString("Would you like to re-convert this disk image to reclaim unused space? Note this will require enough temporary space to perform the conversion. You are strongly encouraged to back-up this VM before proceeding.", comment: "VMConfigDriveDetailsView")), primaryButton: .destructive(Text("Reclaim")) { reclaimSpace(for: imageURL, withCompression: false) }, secondaryButton: .cancel())
case .compress(let imageURL):
return Alert(title: Text("Would you like to re-convert this disk image to reclaim unused space and apply compression? Note this will require enough temporary space to perform the conversion. Compression only applies to existing data and new data will still be written uncompressed. You are strongly encouraged to back-up this VM before proceeding."), primaryButton: .destructive(Text("Reclaim")) { reclaimSpace(for: imageURL, withCompression: true) }, secondaryButton: .cancel())
return Alert(title: Text(NSLocalizedString("Would you like to re-convert this disk image to reclaim unused space and apply compression? Note this will require enough temporary space to perform the conversion. Compression only applies to existing data and new data will still be written uncompressed. You are strongly encouraged to back-up this VM before proceeding.", comment: "VMConfigDriveDetailsView")), primaryButton: .destructive(Text("Reclaim")) { reclaimSpace(for: imageURL, withCompression: true) }, secondaryButton: .cancel())
case .resize(let imageURL):
return Alert(title: Text("Resizing is experimental and could result in data loss. You are strongly encouraged to back-up this VM before proceeding. Would you like to resize to \(proposedSizeMib / mibInGib) GiB?"), primaryButton: .destructive(Text("Resize")) {
return Alert(title: Text(String.localizedStringWithFormat(NSLocalizedString("Resizing is experimental and could result in data loss. You are strongly encouraged to back-up this VM before proceeding. Would you like to resize to %lld GiB?", comment: "VMConfigDriveDetailsView"), proposedSizeMib / mibInGib)), primaryButton: .destructive(Text("Resize")) {
Comment on lines +146 to +150

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alert titles were localized, but the destructive button labels ("Reclaim" / "Resize") are still hardcoded, so the user-facing alert remains partially untranslated. Consider localizing these button titles as well (and ensure the button label matches the action for the .compress case if the copy is intended to differ).

Copilot uses AI. Check for mistakes.
resizeDrive(for: imageURL, sizeInMib: proposedSizeMib)
}, secondaryButton: .cancel())
}
Expand Down
2 changes: 1 addition & 1 deletion Platform/Shared/VMConfigNetworkView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct VMConfigNetworkView: View {
}
}
if config.mode == .host {
Picker("Host Network", selection: $config.hostNetUuid) {
Picker(NSLocalizedString("Host Network", comment: "VMConfigNetworkView"), selection: $config.hostNetUuid) {
Text("Default (private)")
.tag(nil as String?)
Comment on lines +50 to 52

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the Picker title is localized here; the visible option label Default (private) (and the .help(...) text right after the Picker) remain hardcoded, which results in a partially localized control even after this change. Consider applying the same localization approach to the option text (and related help/note strings in this block) so the entire host-network UI is translated together.

Copilot uses AI. Check for mistakes.
ForEach(hostNetworks) { interface in
Expand Down
12 changes: 6 additions & 6 deletions Platform/Shared/VMDetailsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -375,14 +375,14 @@ struct Details: View {
}
ForEach(network.currentIpAddresses) { guestIP in
HStack {
plainLabel("Guest IP", systemImage: "network.badge.shield.half.filled")
plainLabel(LocalizedStringKey(NSLocalizedString("Guest IP", comment: "VMDetailsView")), systemImage: "network.badge.shield.half.filled")

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plainLabel expects a LocalizedStringKey, but wrapping NSLocalizedString(...) inside LocalizedStringKey(...) is a double-localization pattern (the localized value becomes the SwiftUI localization key). This is inconsistent with the rest of the PR (which uses Text(NSLocalizedString(...)) as a verbatim, already-localized string) and can lead to extra lookups or incorrect results if a translation matches another key. Prefer either passing a plain key (e.g. keep the string literal / LocalizedStringKey("Guest IP")) or add a plainLabel(_ text: String, ...) overload that uses Text(verbatim:) so you can pass NSLocalizedString directly (and apply it consistently to the other new uses below).

Copilot uses AI. Check for mistakes.
Spacer()
OptionalSelectableText(guestIP)
}
}
if network.mode == .bridged, let interface = network.bridgeInterface {
HStack {
plainLabel("Bridge Interface", systemImage: "arrow.triangle.branch")
plainLabel(LocalizedStringKey(NSLocalizedString("Bridge Interface", comment: "VMDetailsView")), systemImage: "arrow.triangle.branch")
Spacer()
Text(interface)
.foregroundColor(.secondary)
Expand All @@ -405,7 +405,7 @@ struct Details: View {
ForEach(appleConfig.serials) { serial in
if serial.mode == .ptty {
HStack {
plainLabel("Serial (TTY)", systemImage: "phone.connection")
plainLabel(LocalizedStringKey(NSLocalizedString("Serial (TTY)", comment: "VMDetailsView")), systemImage: "phone.connection")
Spacer()
OptionalSelectableText(serial.interface?.name)
}
Expand All @@ -417,14 +417,14 @@ struct Details: View {
ForEach(qemuConfig.serials) { serial in
if serial.mode == .tcpClient {
HStack {
plainLabel("Serial (Client)", systemImage: "network")
plainLabel(LocalizedStringKey(NSLocalizedString("Serial (Client)", comment: "VMDetailsView")), systemImage: "network")
Spacer()
let address = "\(serial.tcpHostAddress ?? "example.com"):\(serial.tcpPort ?? 1234)"
OptionalSelectableText(vm.state == .started ? address : nil)
}
} else if serial.mode == .tcpServer {
HStack {
plainLabel("Serial (Server)", systemImage: "network")
plainLabel(LocalizedStringKey(NSLocalizedString("Serial (Server)", comment: "VMDetailsView")), systemImage: "network")
Spacer()
let address = "\(serial.tcpPort ?? 1234)"
OptionalSelectableText(vm.state == .started ? address : nil)
Expand All @@ -433,7 +433,7 @@ struct Details: View {
#if os(macOS)
if serial.mode == .ptty {
HStack {
plainLabel("Serial (TTY)", systemImage: "phone.connection")
plainLabel(LocalizedStringKey(NSLocalizedString("Serial (TTY)", comment: "VMDetailsView")), systemImage: "phone.connection")
Spacer()
OptionalSelectableText(serial.pttyDevice?.path)
}
Expand Down
2 changes: 1 addition & 1 deletion Platform/iOS/UTMDonateView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private struct StoreView: View {
if store.consumables.isEmpty && store.subscriptions.isEmpty {
Link("GitHub Sponsors", destination: URL(string: "https://github.com/sponsors/utmapp")!)
} else if !store.subscriptions.isEmpty {
Button("Restore Purchases") {
Button(NSLocalizedString("Restore Purchases", comment: "UTMDonateView")) {
Task {
try? await AppStore.sync()
}
Expand Down
Loading