diff --git a/Termind/Features/Settings/SettingsPageView.swift b/Termind/Features/Settings/SettingsPageView.swift index 8462a958..01dd55b2 100644 --- a/Termind/Features/Settings/SettingsPageView.swift +++ b/Termind/Features/Settings/SettingsPageView.swift @@ -594,15 +594,26 @@ private struct ProSettings: View { } Section("Included") { - Label("Permanent unlock", systemImage: "infinity") - Label("Apple Family Sharing", systemImage: "person.3") - Label("No subscription or automatic renewal", systemImage: "checkmark.seal") + includedFeature("Permanent unlock", systemImage: "infinity") + includedFeature("Apple Family Sharing", systemImage: "person.3") + includedFeature("No subscription or automatic renewal", systemImage: "checkmark.seal") Text("AI provider usage and charges are separate from Termind Pro.") .font(.caption).foregroundStyle(.secondary) } } + private func includedFeature( + _ title: LocalizedStringKey, + systemImage: String + ) -> some View { + HStack(spacing: Metrics.Space.s) { + Image(systemName: systemImage) + .frame(width: 20, alignment: .center) + Text(title) + } + } + @ViewBuilder private var statusLabel: some View { switch app.proAccess.status { diff --git a/Termind/Features/Sidebar/WindowSidebarView.swift b/Termind/Features/Sidebar/WindowSidebarView.swift index 6f2ad4f3..d6ea5731 100644 --- a/Termind/Features/Sidebar/WindowSidebarView.swift +++ b/Termind/Features/Sidebar/WindowSidebarView.swift @@ -265,8 +265,10 @@ nonisolated enum SnippetSidebarListBuilder { return items } - static func searchItems(_ snippets: [Snippet]) -> [SidebarListItem] { - [.section(.results, title: "Results", count: snippets.count)] + static func searchItems( + _ snippets: [Snippet], title: String + ) -> [SidebarListItem] { + [.section(.results, title: title, count: snippets.count)] + snippets.map(SidebarListItem.snippet) } } @@ -454,6 +456,7 @@ final class SidebarListContainer: NSView { private struct SnippetsSidebarView: View { @Environment(AppModel.self) private var app @Environment(WindowModel.self) private var window + @Environment(\.locale) private var locale @State private var query = "" @State private var destructiveSnippet: Snippet? @@ -491,7 +494,10 @@ private struct SnippetsSidebarView: View { } } - SidebarSearchFooter(text: $query, placeholder: String(localized: "Search Snippets")) + SidebarSearchFooter( + text: $query, + placeholder: localized("Search Snippets") + ) } .confirmationDialog( "Execute a destructive script?", @@ -512,7 +518,9 @@ private struct SnippetsSidebarView: View { private var snippetListItems: [SidebarListItem] { if !query.isEmpty { - return SnippetSidebarListBuilder.searchItems(displayedSnippets) + return SnippetSidebarListBuilder.searchItems( + displayedSnippets, title: localized("Results") + ) } var groups = packageSections.map { SnippetSidebarGroup( @@ -521,7 +529,9 @@ private struct SnippetsSidebarView: View { } if !ungrouped.isEmpty { groups.append( - SnippetSidebarGroup(id: .ungrouped, title: "Ungrouped", snippets: ungrouped) + SnippetSidebarGroup( + id: .ungrouped, title: localized("Ungrouped"), snippets: ungrouped + ) ) } return SnippetSidebarListBuilder.groupedItems( @@ -536,8 +546,8 @@ private struct SnippetsSidebarView: View { /// way wherever it lands. private var blankAreaMenu: [NativeMenuEntry] { [ - NativeMenuEntry(title: String(localized: "Copy"), isEnabled: false), - NativeMenuEntry(title: String(localized: "Execute"), isEnabled: false), + NativeMenuEntry(title: localized("Copy"), isEnabled: false), + NativeMenuEntry(title: localized("Execute"), isEnabled: false), ] } @@ -547,10 +557,10 @@ private struct SnippetsSidebarView: View { ) .termindSidebarRow(isSelected: selectedSnippetID == snippet.id) { [ - NativeMenuEntry(title: String(localized: "Copy")) { + NativeMenuEntry(title: localized("Copy")) { copyToPasteboard(snippet.body) }, - NativeMenuEntry(title: String(localized: "Execute")) { + NativeMenuEntry(title: localized("Execute")) { requestExecution(snippet) }, ] @@ -565,6 +575,10 @@ private struct SnippetsSidebarView: View { private var ungrouped: [Snippet] { app.hostLibrary.snippets(in: nil) } + private func localized(_ key: String.LocalizationValue) -> String { + AppLocalization.string(key, locale: locale) + } + private var packageSections: [(package: SnippetPackage, path: String, snippets: [Snippet])] { flattenPackages(app.hostLibrary.rootSnippetPackages) } diff --git a/TermindTests/AppLanguageTests.swift b/TermindTests/AppLanguageTests.swift index 2d4e2305..922690bf 100644 --- a/TermindTests/AppLanguageTests.swift +++ b/TermindTests/AppLanguageTests.swift @@ -103,6 +103,7 @@ struct AppLanguageTests { "Version": "版本", "Welcome": "欢迎", "Snippets": "片段", + "Ungrouped": "未分组", "Pin": "置顶", "Pinned": "置顶", "Unpin": "取消置顶", diff --git a/TermindTests/ListViewMigrationTests.swift b/TermindTests/ListViewMigrationTests.swift index 9581720a..82591b56 100644 --- a/TermindTests/ListViewMigrationTests.swift +++ b/TermindTests/ListViewMigrationTests.swift @@ -255,7 +255,9 @@ struct ListViewMigrationTests { ] ) - let search = SnippetSidebarListBuilder.searchItems([firstSnippet, secondSnippet]) + let search = SnippetSidebarListBuilder.searchItems( + [firstSnippet, secondSnippet], title: "Results" + ) #expect( search.map(\.id) == [ .section(.results),