mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
feat(apple): generate type-safe L10n accessors and migrate all key literals
Replaces every stringly-typed localization key in the Apple app with compile-time-checked accessors generated from localization/strings.json. A mistyped key is now a build error instead of a silent fallback to the raw key at runtime. The runtime path is unchanged: plain keys are String.LocalizationValue constants resolved with String(localized:) and Apple's String Catalog still does the lookup; keys with arguments become typed, named functions applying args through String(format:). Generator: new renderSwiftAccessors emits apple/VniDrop/Generated/L10n.swift, wired into generate. Renamed generic arg1/arg2 tokens on four keys to semantic names (receiver, transferName, deviceId) and updated their context notes; positional output is unchanged so .xcstrings (bar the 4 comments) and the Android XML regenerate identical. Migration: every key-carrying value flipped to String.LocalizationValue end to end, resolved only at the leaf. Zero key literals and zero LocalizedStringKey remain in app or test code. macOS build passes; iOS test run pending.
This commit is contained in:
@@ -22,17 +22,17 @@ struct ReceiveScreen: View {
|
||||
history
|
||||
}
|
||||
}
|
||||
.navigationTitle(Text(LocalizedStringKey("receive_title")))
|
||||
.navigationTitle(Text(String(localized: L10n.Receive.title)))
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: model.openAcquisition) {
|
||||
Label(String(localized: "button_receive_files"), systemImage: "plus")
|
||||
Label(String(localized: L10n.Button.receiveFiles), systemImage: "plus")
|
||||
}
|
||||
}
|
||||
if !deletable.isEmpty {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(role: .destructive, action: model.requestClearHistory) {
|
||||
Label(String(localized: "receive_clear_history"), systemImage: "trash")
|
||||
Label(String(localized: L10n.Receive.clearHistory), systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,11 +50,11 @@ struct ReceiveScreen: View {
|
||||
}
|
||||
}
|
||||
.alert(
|
||||
Text(LocalizedStringKey(clearAllPending ? "receive_clear_history_title" : "receive_delete_history_title")),
|
||||
Text(String(localized: clearAllPending ? L10n.Receive.clearHistoryTitle : L10n.Receive.deleteHistoryTitle)),
|
||||
isPresented: Binding(get: { model.state.historyDeleteTarget != nil }, set: { if !$0 { Task { @MainActor in model.dismissHistoryDelete() } } })
|
||||
) {
|
||||
Button(String(localized: "button_cancel"), role: .cancel, action: model.dismissHistoryDelete)
|
||||
Button(String(localized: clearAllPending ? "receive_clear_history" : "button_delete_transfer"),
|
||||
Button(String(localized: L10n.Button.cancel), role: .cancel, action: model.dismissHistoryDelete)
|
||||
Button(String(localized: clearAllPending ? L10n.Receive.clearHistory : L10n.Button.deleteTransfer),
|
||||
role: .destructive, action: model.confirmHistoryDelete)
|
||||
} message: {
|
||||
historyDeleteMessage
|
||||
@@ -74,27 +74,27 @@ struct ReceiveScreen: View {
|
||||
Button(role: .destructive) {
|
||||
model.requestDeleteHistoryItem(transfer.transferId)
|
||||
} label: {
|
||||
Label(String(localized: "button_delete_transfer"), systemImage: "trash")
|
||||
Label(String(localized: L10n.Button.deleteTransfer), systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text(LocalizedStringKey("receive_history_title"))
|
||||
Text(String(localized: L10n.Receive.historyTitle))
|
||||
} footer: {
|
||||
Text(LocalizedStringKey("receive_new_subtitle"))
|
||||
Text(String(localized: L10n.Receive.newSubtitle))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var emptyState: some View {
|
||||
ContentUnavailableView {
|
||||
Label(String(localized: "receive_empty_title"), systemImage: "tray.and.arrow.down")
|
||||
Label(String(localized: L10n.Receive.emptyTitle), systemImage: "tray.and.arrow.down")
|
||||
} description: {
|
||||
Text(LocalizedStringKey("receive_empty_body"))
|
||||
Text(String(localized: L10n.Receive.emptyBody))
|
||||
} actions: {
|
||||
Button(action: model.openAcquisition) {
|
||||
Label(String(localized: "button_receive_files"), systemImage: "plus")
|
||||
Label(String(localized: L10n.Button.receiveFiles), systemImage: "plus")
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.controlSize(.large)
|
||||
@@ -107,10 +107,10 @@ struct ReceiveScreen: View {
|
||||
private var historyDeleteMessage: some View {
|
||||
if let target = model.state.historyDeleteTarget {
|
||||
if target == .all {
|
||||
Text(LocalizedStringKey("receive_clear_history_description"))
|
||||
Text(String(localized: L10n.Receive.clearHistoryDescription))
|
||||
} else {
|
||||
Text(String(format: String(localized: "receive_delete_history_description"),
|
||||
transferName(for: target) ?? String(localized: "receive_unknown_transfer")))
|
||||
Text(L10n.Receive.deleteHistoryDescription(
|
||||
transferName: transferName(for: target) ?? String(localized: L10n.Receive.unknownTransfer)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ private struct ReceiveTransferRow: View {
|
||||
.frame(width: 40, height: 40)
|
||||
.background(.quaternary, in: RoundedRectangle(cornerRadius: 9))
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
Text(transfer.transferName ?? String(localized: "receive_unknown_transfer"))
|
||||
Text(transfer.transferName ?? String(localized: L10n.Receive.unknownTransfer))
|
||||
.font(.body).lineLimit(1)
|
||||
Text("\(formatBytes(transfer.totalSize)) · \(statusLabel(transfer.status))")
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
|
||||
Reference in New Issue
Block a user