mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Localization work
This commit is contained in:
@@ -68,19 +68,19 @@ struct AccountsManagementView: View {
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(header: Text("Active Accounts", comment: "Active accounts section header")) {
|
||||
Section(header: Text("label.text.active-accounts", comment: "Active Accounts")) {
|
||||
ForEach(viewModel.sortedActiveAccounts, id: \.self) { account in
|
||||
accountRow(account)
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Inactive Accounts", comment: "Inactive accounts section header")) {
|
||||
Section(header: Text("label.text.inactive-accounts", comment: "Inactive Accounts")) {
|
||||
ForEach(viewModel.sortedInactiveAccounts, id: \.self) { account in
|
||||
accountRow(account)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(Text("Manage Accounts", comment: "Navigation title: Manage Accounts"))
|
||||
.navigationTitle(Text("navigation.title.manage-accounts", comment: "Manage Accounts"))
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button {
|
||||
@@ -93,21 +93,21 @@ struct AccountsManagementView: View {
|
||||
.sheet(isPresented: $viewModel.showAddAccountSheet) {
|
||||
AddAccountListView()
|
||||
}
|
||||
.alert(Text("Are you sure you want to remove “\(viewModel.accountToDelete?.nameForDisplay ?? "")”?", comment: "Alert title: confirm account removal"),
|
||||
.alert(Text("alert.title.remove-account.\(viewModel.accountToDelete?.nameForDisplay ?? "")", comment: "Are you sure you want to remove “%@“?"),
|
||||
isPresented: $viewModel.showAccountDeletionAlert) {
|
||||
Button(role: .destructive) {
|
||||
AccountManager.shared.deleteAccount(viewModel.accountToDelete!)
|
||||
} label: {
|
||||
Text("Remove Account", comment: "Button title")
|
||||
Text("button.title.remove-account", comment: "Remove Account")
|
||||
}
|
||||
|
||||
Button(role: .cancel) {
|
||||
viewModel.restoreAccount(viewModel.accountToDelete!)
|
||||
} label: {
|
||||
Text("Cancel", comment: "Button title")
|
||||
Text("button.title.cancel", comment: "Cancel")
|
||||
}
|
||||
} message: {
|
||||
Text("This action cannot be undone.", comment: "Alert message: remove account confirmation")
|
||||
Text("alert.message.cannot-undo-action", comment: "The action cannot be undone.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ struct AccountsManagementView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 25, height: 25)
|
||||
Text(account.nameForDisplay)
|
||||
Text(verbatim: account.nameForDisplay)
|
||||
}
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
||||
if account != AccountManager.shared.defaultAccount {
|
||||
@@ -127,21 +127,27 @@ struct AccountsManagementView: View {
|
||||
viewModel.temporarilyDeleteAccount(account)
|
||||
} label: {
|
||||
Label {
|
||||
Text("Remove Account", comment: "Button title")
|
||||
Text("button.title.remove-account", comment: "Remove Account")
|
||||
} icon: {
|
||||
Image(systemName: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
Button {
|
||||
withAnimation {
|
||||
account.isActive.toggle()
|
||||
}
|
||||
account.isActive.toggle()
|
||||
} label: {
|
||||
if account.isActive {
|
||||
Image(systemName: "minus.circle")
|
||||
} else {
|
||||
Image(systemName: "togglepower")
|
||||
Label {
|
||||
if account.isActive {
|
||||
Text("button.title.deactivate-account", comment: "Deactivate Account")
|
||||
} else {
|
||||
Text("button.title.activate-account", comment: "Activate Account")
|
||||
}
|
||||
} icon: {
|
||||
if account.isActive {
|
||||
Image(systemName: "minus.circle")
|
||||
} else {
|
||||
Image(systemName: "togglepower")
|
||||
}
|
||||
}
|
||||
}.tint(account.isActive ? .yellow : Color(uiColor: AppAssets.primaryAccentColor))
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ struct AddAccountListView: View {
|
||||
webAccountSection
|
||||
selfHostedSection
|
||||
}
|
||||
.navigationTitle(Text("Add Account", comment: "Navigation title: Add Account"))
|
||||
.navigationTitle(Text("navigation.title.add-account", comment: "Add Account"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.listItemTint(.primary)
|
||||
.toolbar {
|
||||
@@ -82,7 +82,7 @@ struct AddAccountListView: View {
|
||||
Button(role: .cancel) {
|
||||
dismiss()
|
||||
} label: {
|
||||
Text("Cancel", comment: "Button title")
|
||||
Text("button.title.cancel", comment: "Button title")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,11 +100,11 @@ struct AddAccountListView: View {
|
||||
Text(viewModel.showAddAccountSheet.accountType.localizedAccountName())
|
||||
}
|
||||
}
|
||||
.alert(Text("Error", comment: "Alert title: Error"),
|
||||
.alert(Text("alert.title.error", comment: "Error"),
|
||||
isPresented: $viewModel.showAddAccountError.1,
|
||||
actions: { },
|
||||
message: {
|
||||
Text("\(viewModel.showAddAccountError.0?.localizedDescription ?? "Unknown Error")")
|
||||
Text(verbatim: "\(viewModel.showAddAccountError.0?.localizedDescription ?? "Unknown Error")")
|
||||
})
|
||||
.dismissOnAccountAdd()
|
||||
}
|
||||
@@ -116,7 +116,7 @@ struct AddAccountListView: View {
|
||||
viewModel.showAddAccountSheet = (true, .onMyMac)
|
||||
} label: {
|
||||
Label {
|
||||
Text(AccountType.onMyMac.localizedAccountName())
|
||||
Text(verbatim: AccountType.onMyMac.localizedAccountName())
|
||||
.foregroundColor(.primary)
|
||||
} icon: {
|
||||
Image(uiImage: AppAssets.image(for: .onMyMac)!)
|
||||
@@ -125,9 +125,9 @@ struct AddAccountListView: View {
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Local", comment: "Add Account: Local account section header")
|
||||
Text("label.text.local-account", comment: "Local Account")
|
||||
} footer: {
|
||||
Text("Local accounts do not sync your feeds across devices", comment: "Local account section footer")
|
||||
Text("label.text.local-account-explainer", comment: "Local accounts do not sync your feeds across devices")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,9 +148,9 @@ struct AddAccountListView: View {
|
||||
}
|
||||
.disabled(interactionDisabled(for: .cloudKit))
|
||||
} header: {
|
||||
Text("iCloud", comment: "Add Account: iCloud section header")
|
||||
Text("label.text.cloudkit-account", comment: "iCloud")
|
||||
} footer: {
|
||||
Text("Your iCloud account syncs your feeds across your Mac and iOS devices", comment: "Add Account: iCloud section footer")
|
||||
Text("label.text.cloudkit-account-footer", comment: "Your iCloud account syncs your feeds across your Mac and iOS devices")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,9 +180,9 @@ struct AddAccountListView: View {
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Web Account", comment: "Add Account: Web Account section header")
|
||||
Text("label.text.web-account", comment: "Web Account")
|
||||
} footer: {
|
||||
Text("Web accounts sync your feeds across all your devices", comment: "Add Account: Web Account section footer")
|
||||
Text("label.text.web-account-explainer", comment: "Web accounts sync your feeds across all your devices")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,9 +202,9 @@ struct AddAccountListView: View {
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Self-Hosted", comment: "Add Accont: Self-hosted section header")
|
||||
Text("label.text.self-hosted-accounts", comment: "Self-Hosted Accounts")
|
||||
} footer: {
|
||||
Text("Self-hosted accounts sync your feeds across all your devices", comment: "Add Account: Self-hosted section footer")
|
||||
Text("label.text.self-hosted-accounts-explainer", comment: "Self-hosted accounts sync your feeds across all your devices")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ struct AddExtensionListView: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
Section(header: Text("Feed Providers", comment: "Feed Providers section header"),
|
||||
footer: Text("Feed Providers allow you to subscribe to some pages as if they were RSS feeds.", comment: "Feed Providers section footer.")) {
|
||||
Section(header: Text("label.text.feed-providers", comment: "Feed Providers"),
|
||||
footer: Text("label.text.feed-providers-explainer", comment: "Feed Providers allow you to subscribe to some pages as if they were RSS feeds")) {
|
||||
ForEach(0..<availableExtensionPointTypes.count, id: \.self) { i in
|
||||
Button {
|
||||
showExtensionPointView = (availableExtensionPointTypes[i], true)
|
||||
@@ -35,7 +35,7 @@ struct AddExtensionListView: View {
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationTitle(Text("Add Extensions", comment: "Navigation title: Add Extensions"))
|
||||
.navigationTitle(Text("navigation.title.add-extensions", comment: "Add Extensions"))
|
||||
.sheet(isPresented: $showExtensionPointView.1, content: {
|
||||
if showExtensionPointView.0 != nil {
|
||||
EnableExtensionPointView(extensionPoint: showExtensionPointView.0!)
|
||||
@@ -46,7 +46,7 @@ struct AddExtensionListView: View {
|
||||
Button(role: .cancel) {
|
||||
dismiss()
|
||||
} label: {
|
||||
Text("Cancel", comment: "Button title")
|
||||
Text("button.title.cancel", comment: "Cancel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ struct EnableExtensionPointView: View {
|
||||
Section(footer: extensionExplainer) {}
|
||||
Section { enableButton }
|
||||
}
|
||||
.alert(Text("Error", comment: "Alert title: Error"), isPresented: $extensionError.1, actions: {
|
||||
.alert(Text("alert.title.error", comment: "Error"), isPresented: $extensionError.1, actions: {
|
||||
}, message: {
|
||||
Text(extensionError.0?.localizedDescription ?? "Unknown Error")
|
||||
Text(verbatim: extensionError.0?.localizedDescription ?? "Unknown Error")
|
||||
})
|
||||
.alert(Text("Error", comment: "Alert title: Error"), isPresented: $viewModel.showExtensionError.1, actions: {
|
||||
.alert(Text("alert.title.error", comment: "Error"), isPresented: $viewModel.showExtensionError.1, actions: {
|
||||
}, message: {
|
||||
Text(viewModel.showExtensionError.0?.localizedDescription ?? "Unknown Error")
|
||||
Text(verbatim: viewModel.showExtensionError.0?.localizedDescription ?? "Unknown Error")
|
||||
})
|
||||
.navigationTitle(extensionPoint.title)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
@@ -56,7 +56,7 @@ struct EnableExtensionPointView: View {
|
||||
} label: {
|
||||
HStack {
|
||||
Spacer()
|
||||
Text("Enable Extension", comment: "Button title")
|
||||
Text("button.title.enable-extension", comment: "Enable Extension")
|
||||
Spacer()
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ struct ExtensionsManagementView: View {
|
||||
List {
|
||||
activeExtensionsSection
|
||||
}
|
||||
.navigationTitle(Text("Manage Extensions", comment: "Navigation title: Manage Extensions"))
|
||||
.navigationTitle(Text("navigation.title.manage-extensions", comment: " Manage Extensions"))
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button {
|
||||
@@ -33,13 +33,13 @@ struct ExtensionsManagementView: View {
|
||||
.sheet(isPresented: $showAddExtensionView) {
|
||||
AddExtensionListView()
|
||||
}
|
||||
.alert(Text("Are you sure you want to deactivate “\(extensionToDeactivate?.value.title ?? "")?", comment: "Alert title: confirm deactivate extension"),
|
||||
.alert(Text("alert.title.deactive-extension.\(extensionToDeactivate?.value.extensionPointID.extensionPointType.title ?? "").\(extensionToDeactivate?.value.title ?? "")", comment: "Are you sure you want to deactivate the %@ extension “%@“? Note: the ordering of the variables is "),
|
||||
isPresented: $showDeactivateAlert) {
|
||||
|
||||
Button(role: .destructive) {
|
||||
ExtensionPointManager.shared.deactivateExtensionPoint(extensionToDeactivate!.value.extensionPointID)
|
||||
} label: {
|
||||
Text("Deactivate Extension", comment: "Button: deactivate extension.")
|
||||
Text("button.title.deactivate-extension", comment: "Deactivate Extension")
|
||||
}
|
||||
|
||||
Button(role: .cancel) {
|
||||
@@ -49,7 +49,7 @@ struct ExtensionsManagementView: View {
|
||||
}
|
||||
|
||||
} message: {
|
||||
Text("This action cannot be undone.", comment: "Alert message: confirmation that deactivation of extension cannot be undone.")
|
||||
Text("alert.message.cannot-undo-action", comment: "This action cannot be undone.")
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .ActiveExtensionPointsDidChange)) { _ in
|
||||
availableExtensionPointTypes = ExtensionPointManager.shared.availableExtensionPointTypes.sorted(by: { $0.title < $1.title })
|
||||
@@ -58,7 +58,7 @@ struct ExtensionsManagementView: View {
|
||||
}
|
||||
|
||||
private var activeExtensionsSection: some View {
|
||||
Section(header: Text("Active Extensions", comment: "Active Extensions section header")) {
|
||||
Section(header: Text("label.text.active-extensions", comment: "Active Extensions")) {
|
||||
ForEach(0..<ExtensionPointManager.shared.activeExtensionPoints.count, id: \.self) { i in
|
||||
let point = Array(ExtensionPointManager.shared.activeExtensionPoints)[i]
|
||||
NavigationLink {
|
||||
@@ -74,7 +74,7 @@ struct ExtensionsManagementView: View {
|
||||
extensionToDeactivate = point
|
||||
showDeactivateAlert = true
|
||||
} label: {
|
||||
Text("Deactivate", comment: "Button: deactivates extension")
|
||||
Text("button.title.deactivate-extension", comment: "Deactivate Extension")
|
||||
Image(systemName: "minus.circle")
|
||||
}.tint(.red)
|
||||
}
|
||||
|
||||
@@ -21,21 +21,21 @@ struct ArticleThemeManagerView: View {
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Ranchero Software Themes", comment: "Section header for installed themes"), footer: Text("These themes cannot be deleted.", comment: "Section footer for installed themes.")) {
|
||||
Section(header: Text("label.text.default-themes", comment: "Default Themes"), footer: Text("label.text.default-themes-explainer", comment: "These themes cannot be deleted.")) {
|
||||
articleThemeRow(try! themeManager.articleThemeWithThemeName("Default"))
|
||||
ForEach(0..<installedFirstPartyThemes.count, id: \.self) { i in
|
||||
articleThemeRow(installedFirstPartyThemes[i])
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Third Party Themes", comment: "Section header for third party themes")) {
|
||||
Section(header: Text("label.text.third-party-themes", comment: "Third Party Themes")) {
|
||||
ForEach(0..<installedThirdPartyThemes.count, id: \.self) { i in
|
||||
articleThemeRow(installedThirdPartyThemes[i])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.navigationTitle(Text("Article Themes", comment: "Navigation bar title for Article Themes"))
|
||||
.navigationTitle(Text("navigation.title.article-themes", comment: "Article Themes"))
|
||||
.task {
|
||||
updateThemesArrays()
|
||||
}
|
||||
@@ -45,7 +45,7 @@ struct ArticleThemeManagerView: View {
|
||||
showImportThemeView = true
|
||||
} label: {
|
||||
Label {
|
||||
Text("Import Theme", comment: "Button title")
|
||||
Text("button.title.import-theme", comment: "Import Theme")
|
||||
} icon: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
@@ -69,23 +69,23 @@ struct ArticleThemeManagerView: View {
|
||||
showImportErrorAlert = (failure, true)
|
||||
}
|
||||
}
|
||||
.alert(Text("Are you sure you want to delete “\(showDeleteConfirmation.0)”?", comment: "Alert title: confirm theme deletion"),
|
||||
.alert(Text("alert.title.delete-theme.\(showDeleteConfirmation.0)", comment: "In English: Are you sure you want to delete “%@”?"),
|
||||
isPresented: $showDeleteConfirmation.1, actions: {
|
||||
Button(role: .destructive) {
|
||||
themeManager.deleteTheme(themeName: showDeleteConfirmation.0)
|
||||
} label: {
|
||||
Text("Delete Theme", comment: "Button title")
|
||||
Text("button.title.delete-theme", comment: "Delete Theme")
|
||||
}
|
||||
|
||||
Button(role: .cancel) {
|
||||
|
||||
} label: {
|
||||
Text("Cancel", comment: "Button title")
|
||||
Text("button.title.cancel", comment: "Cancel")
|
||||
}
|
||||
}, message: {
|
||||
Text("This action cannot be undone.", comment: "Alert message: confirm theme deletion")
|
||||
Text("alert.message.cannot-undo-action", comment: "This action cannot be undone.")
|
||||
})
|
||||
.alert(Text("Import Theme", comment: "Alert title: confirm theme import"),
|
||||
.alert(Text("alert.title.import-theme", comment: "Import Theme"),
|
||||
isPresented: $showImportConfirmationAlert.1,
|
||||
actions: {
|
||||
Button {
|
||||
@@ -107,40 +107,35 @@ struct ArticleThemeManagerView: View {
|
||||
} label: {
|
||||
let exists = themeManager.themeExists(filename: showImportConfirmationAlert.0?.path ?? "")
|
||||
if exists == true {
|
||||
Text("Overwrite Theme", comment: "Button title")
|
||||
Text("button.title.overwrite-theme", comment: "Overwrite Theme")
|
||||
} else {
|
||||
Text("Import Theme", comment: "Button title")
|
||||
Text("button.title.import-theme", comment: "Import Theme")
|
||||
}
|
||||
}
|
||||
|
||||
Button(role: .cancel) {
|
||||
|
||||
} label: {
|
||||
Text("Cancel", comment: "Button title")
|
||||
Text("button.title.cancel", comment: "Cancel")
|
||||
}
|
||||
}, message: {
|
||||
let exists = themeManager.themeExists(filename: showImportConfirmationAlert.0?.path ?? "")
|
||||
if exists {
|
||||
Text("The theme “\(showImportConfirmationAlert.0?.name ?? "")” already exists. Do you want to overwrite it?", comment: "Alert message: confirm theme import and overwrite of existing theme")
|
||||
Text("alert.message.duplicate-theme.\(showImportConfirmationAlert.0?.name ?? "")", comment: "In English: The theme “%@” already exists. Do you want to overwrite it?")
|
||||
} else {
|
||||
Text("Are you sure you want to import “\(showImportConfirmationAlert.0?.name ?? "")” by \(showImportConfirmationAlert.0?.creatorName ?? "")?", comment: "Alert message: confirm theme import")
|
||||
Text("alert.message.import-theme.\(showImportConfirmationAlert.0?.name ?? "").\(showImportConfirmationAlert.0?.creatorName ?? "")", comment: "Are you sure you want to import “%@” by %@")
|
||||
}
|
||||
})
|
||||
.alert(Text("Imported Successfully", comment: "Alert title: theme imported successfully"),
|
||||
.alert(Text("alert.title.imported-theme-succesfully", comment: "Imported Successfully"),
|
||||
isPresented: $showImportSuccessAlert,
|
||||
actions: {
|
||||
Button(role: .cancel) {
|
||||
|
||||
} label: {
|
||||
Text("Dismiss", comment: "Button title")
|
||||
}
|
||||
}, message: {
|
||||
Text("The theme “\(showImportConfirmationAlert.0?.name ?? "")” has been imported.", comment: "Alert message: theme imported successfully")
|
||||
actions: { },
|
||||
message: {
|
||||
Text("alert.message.imported-theme-successfully.\(showImportConfirmationAlert.0?.name ?? "")", comment: "The theme “%@” has been imported.")
|
||||
})
|
||||
.alert(Text("Error", comment: "Alert title: Error"),
|
||||
.alert(Text("alert.title.error", comment: "Error"),
|
||||
isPresented: $showImportErrorAlert.1,
|
||||
actions: { }, message: {
|
||||
Text("\(showImportErrorAlert.0?.localizedDescription ?? "")")
|
||||
Text(verbatim: "\(showImportErrorAlert.0?.localizedDescription ?? "")")
|
||||
})
|
||||
.onReceive(themeManager.objectWillChange) { _ in
|
||||
updateThemesArrays()
|
||||
@@ -153,9 +148,9 @@ struct ArticleThemeManagerView: View {
|
||||
} label: {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text(theme.name)
|
||||
Text(verbatim: theme.name)
|
||||
.foregroundColor(.primary)
|
||||
Text("Created by \(theme.creatorName)", comment: "Article theme creator byline.")
|
||||
Text("label.text.theme-created-byline.\(theme.creatorName)", comment: "Created by %@")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
@@ -174,7 +169,7 @@ struct ArticleThemeManagerView: View {
|
||||
Button {
|
||||
showDeleteConfirmation = (theme.name, true)
|
||||
} label: {
|
||||
Text("Delete", comment: "Button title")
|
||||
Text("button.title.delete", comment: "Delete")
|
||||
Image(systemName: "trash")
|
||||
}
|
||||
.tint(.red)
|
||||
|
||||
@@ -28,7 +28,7 @@ struct ColorPaletteSelectorView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 40.0, height: 40.0)
|
||||
Text("Always Light", comment: "Button: always use light display mode")
|
||||
Text("label.text.use-light-appearance", comment: "Always Light")
|
||||
.font(.subheadline)
|
||||
if AppDefaults.userInterfaceColorPalette == .light {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
@@ -47,7 +47,7 @@ struct ColorPaletteSelectorView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 40.0, height: 40.0)
|
||||
Text("Always Dark", comment: "Button: always use dark display mode")
|
||||
Text("label.text.use-dark-appearance", comment: "Always Dark")
|
||||
.font(.subheadline)
|
||||
if AppDefaults.userInterfaceColorPalette == .dark {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
@@ -66,7 +66,7 @@ struct ColorPaletteSelectorView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 40.0, height: 40.0)
|
||||
Text("Use Device", comment: "Button: always use device display mode")
|
||||
Text("label.text.use-device-appearance", comment: "Use Device")
|
||||
.font(.subheadline)
|
||||
if AppDefaults.userInterfaceColorPalette == .automatic {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
|
||||
@@ -14,19 +14,19 @@ struct DisplayAndBehaviorsView: View {
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(header: Text("Application", comment: "Display & Behaviours: Application section header")) {
|
||||
Section(header: Text("label.text.application", comment: "Application")) {
|
||||
ColorPaletteSelectorView()
|
||||
.listRowBackground(Color.clear)
|
||||
}
|
||||
|
||||
Section(header: Text("Timeline", comment: "Display & Behaviours: Timeline section header")) {
|
||||
Section(header: Text("label.text.timeline", comment: "Timeline")) {
|
||||
SettingsViewRows.sortOldestToNewest($appDefaults.timelineSortDirectionBool)
|
||||
SettingsViewRows.groupByFeed($appDefaults.timelineGroupByFeed)
|
||||
SettingsViewRows.refreshToClearReadArticles($appDefaults.refreshClearsReadArticles)
|
||||
SettingsViewRows.timelineLayout
|
||||
}
|
||||
|
||||
Section(header: Text("Articles", comment: "Display & Behaviours: Articles section header")) {
|
||||
Section(header: Text("label.text.articles", comment: "Articles")) {
|
||||
SettingsViewRows.themeSelection
|
||||
SettingsViewRows.confirmMarkAllAsRead($appDefaults.confirmMarkAllAsRead)
|
||||
SettingsViewRows.openLinksInNetNewsWire(Binding<Bool>(
|
||||
@@ -36,7 +36,7 @@ struct DisplayAndBehaviorsView: View {
|
||||
// TODO: Add Reader Mode Defaults here. See #3684.
|
||||
}
|
||||
}
|
||||
.navigationTitle(Text("Display & Behaviors", comment: "Navigation title for Display & Behaviours"))
|
||||
.navigationTitle(Text("navigation.title.display-and-behaviors", comment: "Display & Behaviors"))
|
||||
.tint(Color(uiColor: AppAssets.primaryAccentColor))
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ struct TimelineCustomizerView: View {
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(header: Text("Icon Size", comment: "Timline Customiser: Icon size section header")) {
|
||||
Section(header: Text("label.text.icon-size", comment: "Icon Size")) {
|
||||
ZStack {
|
||||
TickMarkSliderView(minValue: 1, maxValue: 3, currentValue: Binding(get: {
|
||||
Float(appDefaults.timelineIconSize.rawValue)
|
||||
@@ -27,7 +27,7 @@ struct TimelineCustomizerView: View {
|
||||
.listRowBackground(Color.clear)
|
||||
.listRowSeparator(.hidden)
|
||||
|
||||
Section(header: Text("Number of Lines", comment: "Timeline customiser: Number of lines section header")) {
|
||||
Section(header: Text("label.text.number-of-lines", comment: "Number of Lines")) {
|
||||
ZStack {
|
||||
TickMarkSliderView(minValue: 1, maxValue: 5, currentValue: Binding(get: {
|
||||
Float(appDefaults.timelineNumberOfLines)
|
||||
@@ -45,7 +45,7 @@ struct TimelineCustomizerView: View {
|
||||
}
|
||||
}
|
||||
.listStyle(.grouped)
|
||||
.navigationTitle(Text("Timeline Layout", comment: "Navigation bar title for Timeline Layout"))
|
||||
.navigationTitle(Text("navigation.title.timeline-layout", comment: "Timeline Layout"))
|
||||
|
||||
}
|
||||
|
||||
@@ -70,11 +70,11 @@ struct TimelineCustomizerView: View {
|
||||
.bold()
|
||||
.lineLimit(appDefaults.timelineNumberOfLines)
|
||||
HStack {
|
||||
Text("Feed name", comment: "Feed name placeholder used in timeline preview")
|
||||
Text("label.placeholder.feed-name", comment: "Feed name")
|
||||
.foregroundColor(.secondary)
|
||||
.font(.caption)
|
||||
Spacer()
|
||||
Text("08:51", comment: "Sample time used in timeline preview")
|
||||
Text(verbatim: localizedTime())
|
||||
.foregroundColor(.secondary)
|
||||
.font(.caption)
|
||||
}.padding(0)
|
||||
@@ -84,6 +84,13 @@ struct TimelineCustomizerView: View {
|
||||
.padding(.vertical, 4)
|
||||
.padding(.leading, 4)
|
||||
}
|
||||
|
||||
func localizedTime() -> String {
|
||||
let now = Date.now
|
||||
let formatter = DateFormatter()
|
||||
formatter.setLocalizedDateFormatFromTemplate("hh:mm")
|
||||
return formatter.string(from: now)
|
||||
}
|
||||
}
|
||||
|
||||
struct TimelineCustomizerView_Previews: PreviewProvider {
|
||||
|
||||
@@ -20,19 +20,19 @@ struct ArticleThemeImporter: Logging {
|
||||
return
|
||||
}
|
||||
|
||||
let localizedTitleText = NSLocalizedString("Install theme “%@” by %@?", comment: "Theme message text")
|
||||
let localizedTitleText = NSLocalizedString("alert.title.install-theme.%@.%@", comment: "Variable ordering is theme name; author name. In English, the alert title is: Install theme “%@” by %@?")
|
||||
let title = NSString.localizedStringWithFormat(localizedTitleText as NSString, theme.name, theme.creatorName) as String
|
||||
|
||||
let localizedMessageText = NSLocalizedString("Author‘s website:\n%@", comment: "Authors website")
|
||||
let localizedMessageText = NSLocalizedString("alert.message.author-website.%@", comment: "The variable is the author's home page. In English, the alert message is: Author‘s website:\n%@")
|
||||
let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, theme.creatorHomePage) as String
|
||||
|
||||
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||
|
||||
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
|
||||
let cancelTitle = NSLocalizedString("button.title.cancel", comment: "Cancel")
|
||||
alertController.addAction(UIAlertAction(title: cancelTitle, style: .cancel))
|
||||
|
||||
if let url = URL(string: theme.creatorHomePage) {
|
||||
let visitSiteTitle = NSLocalizedString("Show Website", comment: "Show Website")
|
||||
let visitSiteTitle = NSLocalizedString("button.title.show-website", comment: "Show Website")
|
||||
let visitSiteAction = UIAlertAction(title: visitSiteTitle, style: .default) { action in
|
||||
UIApplication.shared.open(url)
|
||||
Self.importTheme(controller: controller, filename: filename)
|
||||
@@ -50,20 +50,20 @@ struct ArticleThemeImporter: Logging {
|
||||
}
|
||||
}
|
||||
|
||||
let installThemeTitle = NSLocalizedString("Install Theme", comment: "Install Theme")
|
||||
let installThemeTitle = NSLocalizedString("alert.title.install-theme", comment: "Install Theme")
|
||||
let installThemeAction = UIAlertAction(title: installThemeTitle, style: .default) { action in
|
||||
|
||||
if ArticleThemesManager.shared.themeExists(filename: filename) {
|
||||
let title = NSLocalizedString("Duplicate Theme", comment: "Duplicate Theme")
|
||||
let localizedMessageText = NSLocalizedString("The theme “%@” already exists. Overwrite it?", comment: "Overwrite theme")
|
||||
let title = NSLocalizedString("alert.title.duplicate-theme", comment: "Duplicate Theme")
|
||||
let localizedMessageText = NSLocalizedString("alert.message.duplicate-theme.%@", comment: "This message details that this theme is a duplicate and gives the user the option to overwrite the existing theme. In English, the message is: The theme “%@” already exists. Overwrite it?")
|
||||
let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, theme.name) as String
|
||||
|
||||
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||
|
||||
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
|
||||
let cancelTitle = NSLocalizedString("button.title.cancel", comment: "Cancel")
|
||||
alertController.addAction(UIAlertAction(title: cancelTitle, style: .cancel))
|
||||
|
||||
let overwriteAction = UIAlertAction(title: NSLocalizedString("Overwrite", comment: "Overwrite"), style: .default) { action in
|
||||
let overwriteAction = UIAlertAction(title: NSLocalizedString("button.title.overwrite", comment: "Overwrite"), style: .default) { action in
|
||||
importTheme()
|
||||
}
|
||||
alertController.addAction(overwriteAction)
|
||||
@@ -88,14 +88,14 @@ struct ArticleThemeImporter: Logging {
|
||||
private extension ArticleThemeImporter {
|
||||
|
||||
static func confirmImportSuccess(controller: UIViewController, themeName: String) {
|
||||
let title = NSLocalizedString("Theme installed", comment: "Theme installed")
|
||||
let title = NSLocalizedString("alert.title.theme-installed", comment: "Theme installed")
|
||||
|
||||
let localizedMessageText = NSLocalizedString("The theme “%@” has been installed.", comment: "Theme installed")
|
||||
let localizedMessageText = NSLocalizedString("alert.message.theme-installed.%@", comment: "This alert message provides confirmation that the theme has been installed. In English, the message is: The theme “%@” has been installed.")
|
||||
let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, themeName) as String
|
||||
|
||||
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||
|
||||
let doneTitle = NSLocalizedString("Done", comment: "Done")
|
||||
let doneTitle = NSLocalizedString("button.title.done", comment: "Done")
|
||||
alertController.addAction(UIAlertAction(title: doneTitle, style: .default))
|
||||
|
||||
controller.present(alertController, animated: true)
|
||||
|
||||
@@ -18,7 +18,7 @@ struct SettingsViewRows {
|
||||
/// This row, when tapped, will open iOS System Settings.
|
||||
static var openSystemSettings: some View {
|
||||
Label {
|
||||
Text("Open System Settings", comment: "Button: opens device Settings app.")
|
||||
Text("button.title.open-system-settings", comment: "Open System Settings")
|
||||
} icon: {
|
||||
Image("system.settings")
|
||||
.resizable()
|
||||
@@ -36,7 +36,7 @@ struct SettingsViewRows {
|
||||
static var configureNewArticleNotifications: some View {
|
||||
NavigationLink(destination: NewArticleNotificationsView()) {
|
||||
Label {
|
||||
Text("New Article Notifications", comment: "Button: opens New Article Notifications view")
|
||||
Text("button.title.new-article-notifications", comment: "New Article Notifications")
|
||||
} icon: {
|
||||
Image("notifications.sounds")
|
||||
.resizable()
|
||||
@@ -51,7 +51,7 @@ struct SettingsViewRows {
|
||||
static var addAccount: some View {
|
||||
NavigationLink(destination: AccountsManagementView()) {
|
||||
Label {
|
||||
Text("Manage Accounts", comment: "Button: opens Accounts Management view")
|
||||
Text("button.title.manage-accounts", comment: "Manage Accounts")
|
||||
} icon: {
|
||||
Image("app.account")
|
||||
.resizable()
|
||||
@@ -66,7 +66,7 @@ struct SettingsViewRows {
|
||||
static var manageExtensions: some View {
|
||||
NavigationLink(destination: ExtensionsManagementView()) {
|
||||
Label {
|
||||
Text("Manage Extensions", comment: "Button: opens Extensions Management view")
|
||||
Text("button.title.manage-extensions", comment: "Manage Extensions")
|
||||
} icon: {
|
||||
Image("app.extension")
|
||||
.resizable()
|
||||
@@ -83,7 +83,7 @@ struct SettingsViewRows {
|
||||
showImportActionSheet.wrappedValue.toggle()
|
||||
} label: {
|
||||
Label {
|
||||
Text("Import Subscriptions", comment: "Button: opens import subscriptions view")
|
||||
Text("button.title.import-subscriptions", comment: "Import Subscriptions")
|
||||
.foregroundColor(.primary)
|
||||
|
||||
} icon: {
|
||||
@@ -102,7 +102,7 @@ struct SettingsViewRows {
|
||||
showExportActionSheet.wrappedValue.toggle()
|
||||
} label: {
|
||||
Label {
|
||||
Text("Export Subscriptions", comment: "Button: opens Export Subscriptions view")
|
||||
Text("button.title.export-subscriptions", comment: "Export Subscriptions")
|
||||
.foregroundColor(.primary)
|
||||
|
||||
} icon: {
|
||||
@@ -119,7 +119,7 @@ struct SettingsViewRows {
|
||||
/// - Returns: `Toggle`
|
||||
static func sortOldestToNewest(_ preference: Binding<Bool>) -> some View {
|
||||
Toggle(isOn: preference) {
|
||||
Text("Sort Oldest to Newest", comment: "Toggle: Sort articles from oldest to newest when enabled.")
|
||||
Text("toggle.title.sort-oldest-to-newest", comment: "Sort Oldest to Newest")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ struct SettingsViewRows {
|
||||
/// - Returns: `Toggle`
|
||||
static func groupByFeed(_ preference: Binding<Bool>) -> some View {
|
||||
Toggle(isOn: preference) {
|
||||
Text("Group by Feed", comment: "Toggle: groups articles by feed when enabled.")
|
||||
Text("toggle.title.group-by-feed", comment: "Group by Feed")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ struct SettingsViewRows {
|
||||
/// - Returns: `Toggle`
|
||||
static func refreshToClearReadArticles(_ preference: Binding<Bool>) -> some View {
|
||||
Toggle(isOn: preference) {
|
||||
Text("Refresh to Clear Read Articles", comment: "Toggle: when enabled, articles will be cleared when the timeline is refreshed")
|
||||
Text("toggle.title.refresh-to-clear-articles", comment: "Refresh to Clear Articles")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ struct SettingsViewRows {
|
||||
NavigationLink {
|
||||
TimelineCustomizerView()
|
||||
} label: {
|
||||
Text("Timeline Layout", comment: "Button: opens the timeline customiser")
|
||||
Text("button.title.timeline-layout", comment: "Timeline Layout")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ struct SettingsViewRows {
|
||||
static var themeSelection: some View {
|
||||
NavigationLink(destination: ArticleThemeManagerView()) {
|
||||
HStack {
|
||||
Text("Article Theme", comment: "Button: opens the Article Theme manager view")
|
||||
Text("button.title.artice-themes", comment: "Article Themes")
|
||||
Spacer()
|
||||
Text(ArticleThemesManager.shared.currentTheme.name)
|
||||
.font(.callout)
|
||||
@@ -170,7 +170,7 @@ struct SettingsViewRows {
|
||||
/// - Returns: `Toggle`
|
||||
static func confirmMarkAllAsRead(_ preference: Binding<Bool>) -> some View {
|
||||
Toggle(isOn: preference) {
|
||||
Text("Confirm Mark All as Read", comment: "Toggle: when enabled, the app will confirm whether to mark all items as read")
|
||||
Text("toggle.title.confirm-mark-all-as-read", comment: "Confirm Mark All as Read")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ struct SettingsViewRows {
|
||||
/// - Returns: `Toggle`
|
||||
static func openLinksInNetNewsWire(_ preference: Binding<Bool>) -> some View {
|
||||
Toggle(isOn: preference) {
|
||||
Text("Open Links in NetNewsWire", comment: "Toggle: when enabled, links will open in NetNewsWire")
|
||||
Text("toggle.title.open-links-in-netnewswire", comment: "Open Links in NetNewsWire")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ struct SettingsViewRows {
|
||||
static func configureAppearance(_ isShown: Binding<Bool>) -> some View {
|
||||
NavigationLink(destination: DisplayAndBehaviorsView(), isActive: isShown) {
|
||||
Label {
|
||||
Text("Display & Behaviours", comment: "Button: opens the Display and Appearance view.")
|
||||
Text("button.title.display-and-behaviors", comment: "Display & Behaviors")
|
||||
} icon: {
|
||||
Image("app.appearance")
|
||||
.resizable()
|
||||
@@ -228,7 +228,7 @@ struct SettingsViewRows {
|
||||
AboutView()
|
||||
} label: {
|
||||
Label {
|
||||
Text("About", comment: "Button: opens the NetNewsWire about view.")
|
||||
Text("button.title.about", comment: "About")
|
||||
} icon: {
|
||||
Image(systemName: "info.circle")
|
||||
.resizable()
|
||||
|
||||
@@ -23,18 +23,18 @@ struct SettingsView: View {
|
||||
NavigationView {
|
||||
List {
|
||||
// Device Permissions
|
||||
Section(header: Text("Device Permissions", comment: "Settings: Device Permissions section header."),
|
||||
footer: Text("Configure NetNewsWire's access to Siri, background app refresh, mobile data, and more.", comment: "Settings: Device Permissions section footer.")) {
|
||||
Section(header: Text("label.text.device-permissions", comment: "Device Permissions"),
|
||||
footer: Text("label.text.device-permissions-explainer", comment: "Configure NetNewsWire's access to Siri, background app refresh, mobile data, and more.")) {
|
||||
SettingsViewRows.openSystemSettings
|
||||
}
|
||||
|
||||
// Account/Extensions/OPML Management
|
||||
Section(header: Text("Accounts & Extensions", comment: "Settings: Accounts and Extensions section header."),
|
||||
footer: Text("Add, delete, enable, or disable accounts and extensions.", comment: "Settings: Accounts and Extensions section footer.")) {
|
||||
Section(header: Text("label.text.accounts-and-extensions", comment: "Settings: Accounts & Extensions section header."),
|
||||
footer: Text("label.text.account-and-extensions-explainer", comment: "Add, delete, enable, or disable accounts and extensions.")) {
|
||||
SettingsViewRows.addAccount
|
||||
SettingsViewRows.manageExtensions
|
||||
SettingsViewRows.importOPML(showImportActionSheet: $viewModel.showImportActionSheet)
|
||||
.confirmationDialog(Text("Choose an account to receive the imported feeds and folders", comment: "Import OPML confirmation title."),
|
||||
.confirmationDialog(Text("actionsheet.title.choose-opml-destination", comment: "Choose an account to receive the imported feeds and folders"),
|
||||
isPresented: $viewModel.showImportActionSheet,
|
||||
titleVisibility: .visible) {
|
||||
ForEach(AccountManager.shared.sortedActiveAccounts, id: \.self) { account in
|
||||
@@ -46,7 +46,7 @@ struct SettingsView: View {
|
||||
}
|
||||
|
||||
SettingsViewRows.exportOPML(showExportActionSheet: $viewModel.showExportActionSheet)
|
||||
.confirmationDialog(Text("Choose an account with the subscriptions to export", comment: "Export OPML confirmation title."),
|
||||
.confirmationDialog(Text("actionsheet.title.choose-opml-export-account", comment: "Choose an account with the subscriptions to export"),
|
||||
isPresented: $viewModel.showExportActionSheet,
|
||||
titleVisibility: .visible) {
|
||||
ForEach(AccountManager.shared.sortedAccounts, id: \.self) { account in
|
||||
@@ -65,8 +65,8 @@ struct SettingsView: View {
|
||||
}
|
||||
|
||||
// Appearance
|
||||
Section(header: Text("Appearance", comment: "Settings: Appearance section header."),
|
||||
footer: Text("Manage the look, feel, and behavior of NetNewsWire.", comment: "Settings: Appearance section footer.")) {
|
||||
Section(header: Text("label.text.appearance", comment: "Settings: Appearance section header."),
|
||||
footer: Text("label.text.appearance-explainer", comment: "Manage the look, feel, and behavior of NetNewsWire.")) {
|
||||
SettingsViewRows.configureAppearance($isConfigureAppearanceShown)
|
||||
if viewModel.notificationPermissions == .authorized {
|
||||
SettingsViewRows.configureNewArticleNotifications
|
||||
@@ -83,11 +83,11 @@ struct SettingsView: View {
|
||||
}
|
||||
.tint(Color(uiColor: AppAssets.primaryAccentColor))
|
||||
.listStyle(.insetGrouped)
|
||||
.navigationTitle(Text("Settings", comment: "Navigation bar title for Settings."))
|
||||
.navigationTitle(Text("navigation.title.settings", comment: "Settings"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading, content: {
|
||||
Button(action: { dismiss() }, label: { Text("Done", comment: "Button title") })
|
||||
Button(action: { dismiss() }, label: { Text("button.title.done", comment: "Done") })
|
||||
})
|
||||
}
|
||||
.sheet(isPresented: $viewModel.showAddAccountView) {
|
||||
@@ -144,18 +144,18 @@ struct SettingsView: View {
|
||||
viewModel.showImportExportError = true
|
||||
}
|
||||
})
|
||||
.alert(Text("Imported Successfully", comment: "Alert title: imported OPML file successfully."),
|
||||
.alert(Text("alert.title.opml.opml-import-success", comment: "Alert title: Imported Successfully"),
|
||||
isPresented: $viewModel.showImportSuccess,
|
||||
actions: {},
|
||||
message: { Text("Subscriptions have been imported to your \(viewModel.importAccount?.nameForDisplay ?? "") account.", comment: "Alert message: imported OPML file successfully.") })
|
||||
.alert(Text("Exported Successfully", comment: "Alert title: exported OPML file successfully."),
|
||||
message: { Text("alert.message.opml-import-success.%@", comment: "Subscriptions have been imported to your “%@“ account.") })
|
||||
.alert(Text("alert.title.opml.opml-export-success", comment: "Alert title: Exported Successfully"),
|
||||
isPresented: $viewModel.showExportSuccess,
|
||||
actions: {},
|
||||
message: { Text("Your OPML file has been successfully exported.", comment: "Alert message: exported OPML file successfully.") })
|
||||
.alert(Text("Error", comment: "Alert title: Error"),
|
||||
message: { Text("alert.message.opml.opml-export-success", comment: "Your subscriptions have been exported successfully.") })
|
||||
.alert(Text("alert.title.error", comment: "Error"),
|
||||
isPresented: $viewModel.showImportExportError,
|
||||
actions: {},
|
||||
message: { Text(viewModel.importExportError?.localizedDescription ?? "Import/Export Error") } )
|
||||
message: { Text(verbatim: viewModel.importExportError?.localizedDescription ?? "") } )
|
||||
}.navigationViewStyle(.stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,21 +13,21 @@ struct AboutView: View, LoadableAboutData {
|
||||
var body: some View {
|
||||
List {
|
||||
Section(header: aboutHeaderView) {}
|
||||
Section(header: Text("Primary Contributors", comment: "About: Primary Contributors section header")) {
|
||||
Section(header: Text("label.text.primary-contributors", comment: "Primary Contributors")) {
|
||||
ForEach(0..<about.PrimaryContributors.count, id: \.self) { i in
|
||||
contributorView(about.PrimaryContributors[i])
|
||||
}
|
||||
}
|
||||
Section(header: Text("Additional Contributors", comment: "About: Additional Contributors section header")) {
|
||||
Section(header: Text("label.text.additional-contributors", comment: "Additional Contributors")) {
|
||||
ForEach(0..<about.AdditionalContributors.count, id: \.self) { i in
|
||||
contributorView(about.AdditionalContributors[i])
|
||||
}
|
||||
}
|
||||
Section(header: Text("Thanks", comment: "About: Thanks section header"), footer: thanks, content: {})
|
||||
Section(header: Text("label.text.thanks", comment: "Thanks"), footer: thanks, content: {})
|
||||
Section(footer: copyright, content: {})
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
.navigationTitle(Text("About", comment: "Navigation title: About"))
|
||||
.navigationTitle(Text("navigation.title.about", comment: "About"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ struct AboutView: View, LoadableAboutData {
|
||||
.foregroundColor(.secondary)
|
||||
.font(.callout)
|
||||
|
||||
Text("By Brent Simmons and the Ranchero Software team.", comment: "NetNewsWire byline.")
|
||||
Text("label.text.netnewswire-byline", comment: "By Brent Simmons and the Ranchero Software team.")
|
||||
.font(.subheadline)
|
||||
|
||||
Text("[netnewswire.com](https://netnewswire.com)")
|
||||
Text("label.markdown.netnewswire-website", comment: "Markdown formatted link to netnewswire.com")
|
||||
|
||||
}
|
||||
Spacer()
|
||||
|
||||
@@ -16,9 +16,9 @@ public enum HelpSheet: CustomStringConvertible, CaseIterable {
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .help:
|
||||
return String(localized: "NetNewsWire Help", comment: "Button: opens NetNewsWire Help page")
|
||||
return NSLocalizedString("button.title.netnewswire-help", comment: "NetNewsWire Help")
|
||||
case .website:
|
||||
return String(localized: "NetNewsWire Website", comment: "Button: opens NetNewsWire website")
|
||||
return NSLocalizedString("button.title.netnewswire-website", comment: "NetNewsWire Website")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ struct NewArticleNotificationsView: View, Logging {
|
||||
.id(feed.webFeedID)
|
||||
}
|
||||
}
|
||||
.navigationTitle(Text("New Article Notifications", comment: "Navigation title: New Article Notifications"))
|
||||
.navigationTitle(Text("navigation.title.new-article-notifications", comment: "New Article Notifications"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user