mirror of
https://github.com/passepartoutvpn/passepartout-apple.git
synced 2025-01-18 22:49:10 +00:00
Refactor String identifiers (#920)
- Group all views under "views.*" - Split global strings into actions and nouns - Use underscores - Clean up unused Fixes #835
This commit is contained in:
parent
3e2823c2e0
commit
f13a292b4b
@ -96,7 +96,7 @@ extension AboutCoordinator {
|
||||
LinksView()
|
||||
|
||||
default:
|
||||
Text(Strings.Global.noSelection)
|
||||
Text(Strings.Global.Nouns.noSelection)
|
||||
.themeEmptyMessage()
|
||||
}
|
||||
}
|
||||
@ -124,7 +124,7 @@ extension AboutCoordinator {
|
||||
}
|
||||
|
||||
default:
|
||||
Text(Strings.Global.noSelection)
|
||||
Text(Strings.Global.Nouns.noSelection)
|
||||
.themeEmptyMessage()
|
||||
}
|
||||
}
|
||||
|
@ -74,11 +74,11 @@ private extension AboutContentView {
|
||||
.themeSection(header: Strings.Views.About.Sections.resources)
|
||||
Section {
|
||||
linkContent(.diagnostics)
|
||||
Text(Strings.Global.version)
|
||||
Text(Strings.Global.Nouns.version)
|
||||
.themeTrailingValue(BundleConfiguration.mainVersionString)
|
||||
}
|
||||
}
|
||||
.navigationTitle(Strings.Global.settings)
|
||||
.navigationTitle(Strings.Global.Nouns.settings)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ struct AboutContentView<LinkContent, AboutDestination, LogDestination>: View whe
|
||||
.themeNavigationStack(closable: false, path: $path)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button(Strings.Global.ok) {
|
||||
Button(Strings.Global.Nouns.ok) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
@ -52,10 +52,10 @@ struct AddProfileMenu: View {
|
||||
private extension AddProfileMenu {
|
||||
var newProfileButton: some View {
|
||||
Button {
|
||||
let profile = profileManager.new(withName: Strings.Entities.Profile.Name.new)
|
||||
let profile = profileManager.new(withName: Strings.Placeholders.Profile.name)
|
||||
onNewProfile(profile)
|
||||
} label: {
|
||||
ThemeImageLabel(Strings.Views.Profiles.Toolbar.newProfile, .profileEdit)
|
||||
ThemeImageLabel(Strings.Views.App.Toolbar.newProfile, .profileEdit)
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,13 +63,13 @@ private extension AddProfileMenu {
|
||||
Button {
|
||||
isImporting = true
|
||||
} label: {
|
||||
ThemeImageLabel(Strings.Views.Profiles.Toolbar.importProfile.withTrailingDots, .profileImport)
|
||||
ThemeImageLabel(Strings.Views.App.Toolbar.importProfile.withTrailingDots, .profileImport)
|
||||
}
|
||||
}
|
||||
|
||||
var migrateProfilesButton: some View {
|
||||
Button(action: onMigrateProfiles) {
|
||||
ThemeImageLabel(Strings.Views.Profiles.Toolbar.migrateProfiles.withTrailingDots, .profileMigrate)
|
||||
ThemeImageLabel(Strings.Views.App.Toolbar.migrateProfiles.withTrailingDots, .profileMigrate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ private extension InstalledProfileView {
|
||||
}
|
||||
|
||||
var nameView: some View {
|
||||
Text(profile?.name ?? Strings.Views.Profiles.Rows.notInstalled)
|
||||
Text(profile?.name ?? Strings.Views.App.Rows.notInstalled)
|
||||
.font(.title2)
|
||||
.fontWeight(theme.relevantWeight)
|
||||
.themeTruncating(.tail)
|
||||
|
@ -70,7 +70,7 @@ struct ProfileAttributesView: View {
|
||||
case .tv:
|
||||
return (
|
||||
isRemoteImportingEnabled ? .tvOn : .tvOff,
|
||||
Strings.Modules.General.Rows.appleTv(Strings.Unlocalized.appleTV)
|
||||
Strings.Modules.General.Rows.appletv(Strings.Unlocalized.appleTV)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ struct ProfileCardView: View {
|
||||
.font(.headline)
|
||||
.themeTruncating()
|
||||
|
||||
Text(preview.subtitle ?? Strings.Views.Profiles.Rows.noModules)
|
||||
Text(preview.subtitle ?? Strings.Views.App.Rows.noModules)
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
|
@ -96,8 +96,8 @@ private extension ProfileContainerView {
|
||||
InteractiveCoordinator(style: .modal, manager: interactiveManager) {
|
||||
errorHandler.handle(
|
||||
$0,
|
||||
title: Strings.Global.connection,
|
||||
message: Strings.Views.Profiles.Errors.tunnel
|
||||
title: Strings.Global.Nouns.connection,
|
||||
message: Strings.Views.App.Errors.tunnel
|
||||
)
|
||||
}
|
||||
.presentationDetents([.medium])
|
||||
@ -122,10 +122,10 @@ private struct ContainerModifier: ViewModifier {
|
||||
isEmpty: !profileManager.hasProfiles,
|
||||
emptyContent: {
|
||||
VStack(spacing: 16) {
|
||||
Text(Strings.Views.Profiles.Folders.noProfiles)
|
||||
Text(Strings.Views.App.Folders.noProfiles)
|
||||
.themeEmptyMessage(fullScreen: false)
|
||||
|
||||
Button(Strings.Views.Profiles.Folders.NoProfiles.migrate) {
|
||||
Button(Strings.Views.App.Folders.NoProfiles.migrate) {
|
||||
flow?.onMigrateProfiles()
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ private extension ProfileContextMenu {
|
||||
},
|
||||
label: {
|
||||
ThemeImageLabel(
|
||||
$0 ? Strings.Global.enable : Strings.Global.disable,
|
||||
$0 ? Strings.Global.Actions.enable : Strings.Global.Actions.disable,
|
||||
$0 ? .tunnelEnable : .tunnelDisable
|
||||
)
|
||||
}
|
||||
@ -89,7 +89,7 @@ private extension ProfileContextMenu {
|
||||
profile?
|
||||
.selectedProvider
|
||||
.map { _ in
|
||||
Button(Strings.Ui.ProfileContext.connectTo) {
|
||||
Button(Strings.Views.App.ProfileContext.connectTo) {
|
||||
flow?.onEditProviderEntity(profile!)
|
||||
}
|
||||
}
|
||||
@ -104,7 +104,7 @@ private extension ProfileContextMenu {
|
||||
flow?.onPurchaseRequired($0)
|
||||
},
|
||||
label: {
|
||||
ThemeImageLabel(Strings.Global.restart, .tunnelRestart)
|
||||
ThemeImageLabel(Strings.Global.Actions.restart, .tunnelRestart)
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -113,7 +113,7 @@ private extension ProfileContextMenu {
|
||||
Button {
|
||||
flow?.onEditProfile(preview)
|
||||
} label: {
|
||||
ThemeImageLabel(Strings.Global.edit.withTrailingDots, .profileEdit)
|
||||
ThemeImageLabel(Strings.Global.Actions.edit.withTrailingDots, .profileEdit)
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ private extension ProfileContextMenu {
|
||||
preview: preview,
|
||||
errorHandler: errorHandler
|
||||
) {
|
||||
ThemeImageLabel(Strings.Global.duplicate, .contextDuplicate)
|
||||
ThemeImageLabel(Strings.Global.Actions.duplicate, .contextDuplicate)
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@ private extension ProfileContextMenu {
|
||||
profileManager: profileManager,
|
||||
preview: preview
|
||||
) {
|
||||
ThemeImageLabel(Strings.Global.remove, .contextRemove)
|
||||
ThemeImageLabel(Strings.Global.Actions.remove, .contextRemove)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,8 @@ struct ProfileDuplicateButton<Label>: View where Label: View {
|
||||
} catch {
|
||||
errorHandler.handle(
|
||||
error,
|
||||
title: Strings.Global.duplicate,
|
||||
message: Strings.Views.Profiles.Errors.duplicate(preview.name)
|
||||
title: Strings.Global.Actions.duplicate,
|
||||
message: Strings.Views.App.Errors.duplicate(preview.name)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ struct ProfileGridView: View, Routable, TunnelInstallationProviding {
|
||||
}
|
||||
}
|
||||
}
|
||||
.themeGridHeader(title: Strings.Views.Profiles.Folders.default)
|
||||
.themeGridHeader(title: Strings.Views.App.Folders.default)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ struct ProfileImporterModifier: ViewModifier {
|
||||
handleResult(.success($0))
|
||||
}
|
||||
.alert(
|
||||
Strings.Views.Profiles.Toolbar.importProfile,
|
||||
Strings.Views.App.Toolbar.importProfile,
|
||||
isPresented: $importer.isPresentingPassphrase,
|
||||
presenting: importer.nextURL,
|
||||
actions: actions,
|
||||
@ -79,7 +79,7 @@ private extension ProfileImporterModifier {
|
||||
)
|
||||
}
|
||||
}
|
||||
Button(Strings.Global.cancel, role: .cancel) {
|
||||
Button(Strings.Global.Actions.cancel, role: .cancel) {
|
||||
importer.cancelImport()
|
||||
}
|
||||
}
|
||||
@ -100,8 +100,8 @@ private extension ProfileImporterModifier {
|
||||
} catch {
|
||||
await errorHandler.handle(
|
||||
error,
|
||||
title: Strings.Views.Profiles.Toolbar.importProfile,
|
||||
message: Strings.Views.Profiles.Errors.import
|
||||
title: Strings.Views.App.Toolbar.importProfile,
|
||||
message: Strings.Views.App.Errors.import
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ struct ProfileListView: View, Routable, TunnelInstallationProviding {
|
||||
}
|
||||
}
|
||||
}
|
||||
.themeSection(header: Strings.Views.Profiles.Folders.default)
|
||||
.themeSection(header: Strings.Views.App.Folders.default)
|
||||
}
|
||||
.themeForm()
|
||||
}
|
||||
|
@ -59,8 +59,8 @@ struct TunnelRestartButton<Label>: View where Label: View {
|
||||
} catch {
|
||||
errorHandler.handle(
|
||||
error,
|
||||
title: Strings.Global.connection,
|
||||
message: Strings.Views.Profiles.Errors.tunnel
|
||||
title: Strings.Global.Nouns.connection,
|
||||
message: Strings.Views.App.Errors.tunnel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -66,24 +66,24 @@ private extension AppMenu {
|
||||
}
|
||||
|
||||
var showToggle: some View {
|
||||
Button(Strings.Global.show) {
|
||||
Button(Strings.Global.Actions.show) {
|
||||
settings.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
var loginToggle: some View {
|
||||
Toggle(Strings.Views.Settings.launchesOnLogin, isOn: $settings.launchesOnLogin)
|
||||
Toggle(Strings.Views.Preferences.launchesOnLogin, isOn: $settings.launchesOnLogin)
|
||||
}
|
||||
|
||||
var keepToggle: some View {
|
||||
Toggle(Strings.Views.Settings.keepsInMenu, isOn: $settings.keepsInMenu)
|
||||
Toggle(Strings.Views.Preferences.keepsInMenu, isOn: $settings.keepsInMenu)
|
||||
}
|
||||
|
||||
var profilesList: some View {
|
||||
Group {
|
||||
ForEach(profileManager.previews, id: \.id, content: profileToggle)
|
||||
}
|
||||
.themeSection(header: Strings.Views.Profiles.Folders.default)
|
||||
.themeSection(header: Strings.Views.App.Folders.default)
|
||||
}
|
||||
|
||||
func profileToggle(for preview: ProfilePreview) -> some View {
|
||||
@ -112,14 +112,14 @@ private extension AppMenu {
|
||||
}
|
||||
|
||||
var aboutButton: some View {
|
||||
Button(Strings.Global.about.withTrailingDots) {
|
||||
Button(Strings.Global.Nouns.about.withTrailingDots) {
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
NSApp.orderFrontStandardAboutPanel(self)
|
||||
}
|
||||
}
|
||||
|
||||
var quitButton: some View {
|
||||
Button(Strings.AppMenu.Items.quit(BundleConfiguration.mainDisplayName)) {
|
||||
Button(Strings.Views.AppMenu.Items.quit(BundleConfiguration.mainDisplayName)) {
|
||||
NSApp.terminate(self)
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ struct DiagnosticsView: View {
|
||||
.themeForm()
|
||||
.navigationTitle(Strings.Views.Diagnostics.title)
|
||||
.alert(Strings.Views.Diagnostics.ReportIssue.title, isPresented: $isPresentingUnableToEmail) {
|
||||
Button(Strings.Global.ok, role: .cancel) {
|
||||
Button(Strings.Global.Nouns.ok, role: .cancel) {
|
||||
isPresentingUnableToEmail = false
|
||||
}
|
||||
} message: {
|
||||
|
@ -40,10 +40,10 @@ private extension MigrateButton {
|
||||
var title: String {
|
||||
switch step {
|
||||
case .initial, .fetching, .fetched:
|
||||
return Strings.Views.Migrate.Items.migrate
|
||||
return Strings.Views.Migration.Items.migrate
|
||||
|
||||
case .migrating, .migrated:
|
||||
return Strings.Global.done
|
||||
return Strings.Global.Nouns.done
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ private extension MigrateContentView.ListView {
|
||||
}
|
||||
|
||||
var messageView: some View {
|
||||
Text(Strings.Views.Migrate.Sections.Main.header(Strings.Unlocalized.appName))
|
||||
Text(Strings.Views.Migration.Sections.Main.header(Strings.Unlocalized.appName))
|
||||
.padding([.top, .leading, .trailing])
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ private extension MigrateContentView.ListView {
|
||||
}
|
||||
.listStyle(.plain)
|
||||
.disabled(!step.canSelect)
|
||||
.themeEmpty(if: isEmpty, message: Strings.Views.Migrate.noProfiles)
|
||||
.themeEmpty(if: isEmpty, message: Strings.Views.Migration.noProfiles)
|
||||
}
|
||||
|
||||
func isIncludedBinding(for profileId: UUID) -> Binding<Bool> {
|
||||
@ -142,7 +142,7 @@ private extension MigrateContentView.ListView {
|
||||
var body: some View {
|
||||
HStack {
|
||||
if isEditing {
|
||||
Button(Strings.Global.cancel) {
|
||||
Button(Strings.Global.Actions.cancel) {
|
||||
isEditing = false
|
||||
}
|
||||
}
|
||||
@ -165,7 +165,7 @@ private extension MigrateContentView.ListView {
|
||||
}
|
||||
|
||||
var title: String {
|
||||
isEditing ? Strings.Views.Migrate.Items.discard : Strings.Global.edit
|
||||
isEditing ? Strings.Views.Migration.Items.discard : Strings.Global.Actions.edit
|
||||
}
|
||||
|
||||
var role: ButtonRole? {
|
||||
|
@ -61,18 +61,18 @@ private extension MigrateContentView.TableView {
|
||||
}
|
||||
|
||||
var messageView: some View {
|
||||
Text(Strings.Views.Migrate.Sections.Main.header(Strings.Unlocalized.appName))
|
||||
Text(Strings.Views.Migration.Sections.Main.header(Strings.Unlocalized.appName))
|
||||
.padding([.top, .leading, .trailing])
|
||||
}
|
||||
|
||||
var profilesForm: some View {
|
||||
Form {
|
||||
Table(profiles) {
|
||||
TableColumn(Strings.Global.name) {
|
||||
TableColumn(Strings.Global.Nouns.name) {
|
||||
Text($0.name)
|
||||
.foregroundStyle(statuses.style(for: $0.id))
|
||||
}
|
||||
TableColumn(Strings.Global.lastUpdate) {
|
||||
TableColumn(Strings.Global.Nouns.lastUpdate) {
|
||||
Text($0.timestamp)
|
||||
.foregroundStyle(statuses.style(for: $0.id))
|
||||
}
|
||||
@ -98,7 +98,7 @@ private extension MigrateContentView.TableView {
|
||||
}
|
||||
.disabled(!step.canSelect)
|
||||
.themeForm()
|
||||
.themeEmpty(if: isEmpty, message: Strings.Views.Migrate.noProfiles)
|
||||
.themeEmpty(if: isEmpty, message: Strings.Views.Migration.noProfiles)
|
||||
}
|
||||
|
||||
func isIncludedBinding(for profileId: UUID) -> Binding<Bool> {
|
||||
|
@ -81,7 +81,7 @@ struct MigrateView: View {
|
||||
.themeAnimation(on: model, category: .profiles)
|
||||
.themeConfirmation(
|
||||
isPresented: $isDeleting,
|
||||
title: Strings.Views.Migrate.Items.discard,
|
||||
title: Strings.Views.Migration.Items.discard,
|
||||
message: messageForDeletion,
|
||||
isDestructive: true,
|
||||
action: confirmPendingDeletion
|
||||
@ -96,7 +96,7 @@ struct MigrateView: View {
|
||||
|
||||
private extension MigrateView {
|
||||
var title: String {
|
||||
Strings.Views.Migrate.title
|
||||
Strings.Views.Migration.title
|
||||
}
|
||||
|
||||
var messageForDeletion: String? {
|
||||
@ -105,7 +105,7 @@ private extension MigrateView {
|
||||
.map(\.name)
|
||||
.joined(separator: "\n")
|
||||
|
||||
return Strings.Views.Migrate.Alerts.Delete.message(nameList)
|
||||
return Strings.Views.Migration.Alerts.Delete.message(nameList)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ private extension DNSView {
|
||||
|
||||
var protocolSection: some View {
|
||||
Section {
|
||||
Picker(Strings.Global.protocol, selection: draft.protocolType) {
|
||||
Picker(Strings.Global.Nouns.protocol, selection: draft.protocolType) {
|
||||
ForEach(Self.allProtocols, id: \.self) {
|
||||
Text($0.localizedDescription)
|
||||
}
|
||||
@ -77,7 +77,7 @@ private extension DNSView {
|
||||
.labelsHidden()
|
||||
|
||||
case .tls:
|
||||
ThemeTextField(Strings.Global.hostname, text: draft.dotHostname, placeholder: Strings.Unlocalized.Placeholders.dotHostname)
|
||||
ThemeTextField(Strings.Global.Nouns.hostname, text: draft.dotHostname, placeholder: Strings.Unlocalized.Placeholders.dotHostname)
|
||||
.labelsHidden()
|
||||
}
|
||||
}
|
||||
@ -85,9 +85,9 @@ private extension DNSView {
|
||||
|
||||
var domainSection: some View {
|
||||
Group {
|
||||
ThemeTextField(Strings.Global.domain, text: draft.domainName ?? "", placeholder: Strings.Unlocalized.Placeholders.hostname)
|
||||
ThemeTextField(Strings.Global.Nouns.domain, text: draft.domainName ?? "", placeholder: Strings.Unlocalized.Placeholders.hostname)
|
||||
}
|
||||
.themeSection(header: Strings.Global.domain)
|
||||
.themeSection(header: Strings.Global.Nouns.domain)
|
||||
}
|
||||
|
||||
var serversSection: some View {
|
||||
|
@ -53,16 +53,16 @@ struct HTTPProxyView: View, ModuleDraftEditing {
|
||||
private extension HTTPProxyView {
|
||||
var httpSection: some View {
|
||||
Group {
|
||||
ThemeTextField(Strings.Global.address, text: draft.address, placeholder: Strings.Unlocalized.Placeholders.proxyIPv4Address)
|
||||
ThemeTextField(Strings.Global.port, text: draft.port.toString(omittingZero: true), placeholder: Strings.Unlocalized.Placeholders.proxyPort)
|
||||
ThemeTextField(Strings.Global.Nouns.address, text: draft.address, placeholder: Strings.Unlocalized.Placeholders.proxyIPv4Address)
|
||||
ThemeTextField(Strings.Global.Nouns.port, text: draft.port.toString(omittingZero: true), placeholder: Strings.Unlocalized.Placeholders.proxyPort)
|
||||
}
|
||||
.themeSection(header: Strings.Unlocalized.http)
|
||||
}
|
||||
|
||||
var httpsSection: some View {
|
||||
Group {
|
||||
ThemeTextField(Strings.Global.address, text: draft.secureAddress, placeholder: Strings.Unlocalized.Placeholders.proxyIPv4Address)
|
||||
ThemeTextField(Strings.Global.port, text: draft.securePort.toString(omittingZero: true), placeholder: Strings.Unlocalized.Placeholders.proxyPort)
|
||||
ThemeTextField(Strings.Global.Nouns.address, text: draft.secureAddress, placeholder: Strings.Unlocalized.Placeholders.proxyIPv4Address)
|
||||
ThemeTextField(Strings.Global.Nouns.port, text: draft.securePort.toString(omittingZero: true), placeholder: Strings.Unlocalized.Placeholders.proxyPort)
|
||||
}
|
||||
.themeSection(header: Strings.Unlocalized.https)
|
||||
}
|
||||
|
@ -48,24 +48,24 @@ extension IPView {
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
Toggle(Strings.Global.default, isOn: $isDefault.animation(theme.animation(for: .modules)))
|
||||
Toggle(Strings.Global.Nouns.default, isOn: $isDefault.animation(theme.animation(for: .modules)))
|
||||
}
|
||||
if !isDefault {
|
||||
Section {
|
||||
ThemeTextField(Strings.Global.destination, text: $destinationString, placeholder: Strings.Unlocalized.Placeholders.ipDestination(forFamily: family))
|
||||
ThemeTextField(Strings.Global.gateway, text: $gatewayString, placeholder: Strings.Unlocalized.Placeholders.ipGateway(forFamily: family))
|
||||
ThemeTextField(Strings.Global.Nouns.destination, text: $destinationString, placeholder: Strings.Unlocalized.Placeholders.ipDestination(forFamily: family))
|
||||
ThemeTextField(Strings.Global.Nouns.gateway, text: $gatewayString, placeholder: Strings.Unlocalized.Placeholders.ipGateway(forFamily: family))
|
||||
}
|
||||
}
|
||||
}
|
||||
.themeForm()
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button(Strings.Global.cancel, role: .cancel) {
|
||||
Button(Strings.Global.Actions.cancel, role: .cancel) {
|
||||
onSubmit(nil)
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button(Strings.Global.ok, action: parseAndSubmit)
|
||||
Button(Strings.Global.Nouns.ok, action: parseAndSubmit)
|
||||
}
|
||||
}
|
||||
.themeNavigationDetail()
|
||||
|
@ -138,7 +138,7 @@ private extension IPView {
|
||||
placeholder: Strings.Unlocalized.Placeholders.mtu
|
||||
)
|
||||
}
|
||||
.themeSection(header: Strings.Global.interface)
|
||||
.themeSection(header: Strings.Global.Nouns.interface)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ private extension OnDemandView {
|
||||
|
||||
var enabledSection: some View {
|
||||
Section {
|
||||
Toggle(Strings.Global.enabled, isOn: draft.isEnabled)
|
||||
Toggle(Strings.Global.Nouns.enabled, isOn: draft.isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ private extension OnDemandView {
|
||||
Toggle(Strings.Modules.OnDemand.ethernet, isOn: draft.withEthernetNetwork)
|
||||
}
|
||||
}
|
||||
.themeSection(header: Strings.Global.networks)
|
||||
.themeSection(header: Strings.Global.Nouns.networks)
|
||||
}
|
||||
|
||||
var wifiSection: some View {
|
||||
|
@ -35,7 +35,7 @@ extension OpenVPNView {
|
||||
let credentialsRoute: any Hashable
|
||||
|
||||
var body: some View {
|
||||
moduleSection(for: accountRows, header: Strings.Global.account)
|
||||
moduleSection(for: accountRows, header: Strings.Global.Nouns.account)
|
||||
moduleSection(for: remotesRows, header: Strings.Modules.Openvpn.remotes)
|
||||
if !isServerPushed {
|
||||
moduleSection(for: pullRows, header: Strings.Modules.Openvpn.pull)
|
||||
@ -56,7 +56,7 @@ extension OpenVPNView {
|
||||
if !isServerPushed {
|
||||
moduleSection(for: tlsRows, header: Strings.Unlocalized.tls)
|
||||
}
|
||||
moduleSection(for: otherRows, header: Strings.Global.other)
|
||||
moduleSection(for: otherRows, header: Strings.Global.Nouns.other)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,10 +92,10 @@ private extension OpenVPNView.ConfigurationView {
|
||||
var rows: [ModuleRow] = []
|
||||
if let ip {
|
||||
ip.localizedDescription(optionalStyle: .address).map {
|
||||
rows.append(.copiableText(caption: Strings.Global.address, value: $0))
|
||||
rows.append(.copiableText(caption: Strings.Global.Nouns.address, value: $0))
|
||||
}
|
||||
ip.localizedDescription(optionalStyle: .defaultGateway).map {
|
||||
rows.append(.copiableText(caption: Strings.Global.gateway, value: $0))
|
||||
rows.append(.copiableText(caption: Strings.Global.Nouns.gateway, value: $0))
|
||||
}
|
||||
|
||||
ip.includedRoutes
|
||||
@ -118,7 +118,7 @@ private extension OpenVPNView.ConfigurationView {
|
||||
}
|
||||
}
|
||||
routes?.forEach {
|
||||
rows.append(.longContent(caption: Strings.Global.route, value: $0.localizedDescription))
|
||||
rows.append(.longContent(caption: Strings.Global.Nouns.route, value: $0.localizedDescription))
|
||||
}
|
||||
return rows.nilIfEmpty
|
||||
}
|
||||
@ -147,14 +147,14 @@ private extension OpenVPNView.ConfigurationView {
|
||||
.nilIfEmpty
|
||||
.map {
|
||||
rows.append(.textList(
|
||||
caption: Strings.Global.servers,
|
||||
caption: Strings.Global.Nouns.servers,
|
||||
values: $0
|
||||
))
|
||||
}
|
||||
|
||||
configuration.dnsDomain.map {
|
||||
rows.append(.copiableText(
|
||||
caption: Strings.Global.domain,
|
||||
caption: Strings.Global.Nouns.domain,
|
||||
value: $0
|
||||
))
|
||||
}
|
||||
@ -237,10 +237,10 @@ private extension OpenVPNView.ConfigurationView {
|
||||
rows.append(.longContentPreview(caption: Strings.Unlocalized.ca, value: $0.pem, preview: nil))
|
||||
}
|
||||
configuration.clientCertificate.map {
|
||||
rows.append(.longContentPreview(caption: Strings.Global.certificate, value: $0.pem, preview: nil))
|
||||
rows.append(.longContentPreview(caption: Strings.Global.Nouns.certificate, value: $0.pem, preview: nil))
|
||||
}
|
||||
configuration.clientKey.map {
|
||||
rows.append(.longContentPreview(caption: Strings.Global.key, value: $0.pem, preview: nil))
|
||||
rows.append(.longContentPreview(caption: Strings.Global.Nouns.key, value: $0.pem, preview: nil))
|
||||
}
|
||||
configuration.tlsWrap.map {
|
||||
rows.append(.longContentPreview(
|
||||
@ -256,7 +256,7 @@ private extension OpenVPNView.ConfigurationView {
|
||||
var otherRows: [ModuleRow]? {
|
||||
var rows: [ModuleRow] = []
|
||||
configuration.localizedDescription(optionalStyle: .keepAlive).map {
|
||||
rows.append(.text(caption: Strings.Global.keepAlive, value: $0))
|
||||
rows.append(.text(caption: Strings.Global.Nouns.keepAlive, value: $0))
|
||||
}
|
||||
configuration.localizedDescription(optionalStyle: .renegotiatesAfter).map {
|
||||
rows.append(.text(caption: Strings.Modules.Openvpn.renegotiation, value: $0))
|
||||
|
@ -129,7 +129,7 @@ private extension OpenVPNView {
|
||||
Button(Strings.Alerts.Import.Passphrase.ok) {
|
||||
importConfiguration(from: .success(url))
|
||||
}
|
||||
Button(Strings.Global.cancel, role: .cancel) {
|
||||
Button(Strings.Global.Actions.cancel, role: .cancel) {
|
||||
isImporting = false
|
||||
}
|
||||
},
|
||||
|
@ -43,12 +43,12 @@ extension WireGuardView {
|
||||
private extension WireGuardView.ConfigurationView {
|
||||
var interfaceRows: [ModuleRow]? {
|
||||
var rows: [ModuleRow] = []
|
||||
rows.append(.longContent(caption: Strings.Global.privateKey, value: configuration.interface.privateKey))
|
||||
rows.append(.longContent(caption: Strings.Global.Nouns.privateKey, value: configuration.interface.privateKey))
|
||||
configuration.interface.addresses
|
||||
.nilIfEmpty
|
||||
.map {
|
||||
rows.append(.textList(
|
||||
caption: Strings.Global.addresses,
|
||||
caption: Strings.Global.Nouns.addresses,
|
||||
values: $0
|
||||
))
|
||||
}
|
||||
@ -65,14 +65,14 @@ private extension WireGuardView.ConfigurationView {
|
||||
.nilIfEmpty
|
||||
.map {
|
||||
rows.append(.textList(
|
||||
caption: Strings.Global.servers,
|
||||
caption: Strings.Global.Nouns.servers,
|
||||
values: $0
|
||||
))
|
||||
}
|
||||
|
||||
configuration.interface.dns.domainName.map {
|
||||
rows.append(.text(
|
||||
caption: Strings.Global.domain,
|
||||
caption: Strings.Global.Nouns.domain,
|
||||
value: $0
|
||||
))
|
||||
}
|
||||
@ -91,12 +91,12 @@ private extension WireGuardView.ConfigurationView {
|
||||
|
||||
func peersRows(for peer: WireGuard.RemoteInterface.Builder) -> [ModuleRow]? {
|
||||
var rows: [ModuleRow] = []
|
||||
rows.append(.longContent(caption: Strings.Global.publicKey, value: peer.publicKey))
|
||||
rows.append(.longContent(caption: Strings.Global.Nouns.publicKey, value: peer.publicKey))
|
||||
peer.preSharedKey.map {
|
||||
rows.append(.longContent(caption: Strings.Modules.Wireguard.presharedKey, value: $0))
|
||||
}
|
||||
peer.endpoint.map {
|
||||
rows.append(.copiableText(caption: Strings.Global.endpoint, value: $0))
|
||||
rows.append(.copiableText(caption: Strings.Global.Nouns.endpoint, value: $0))
|
||||
}
|
||||
peer.allowedIPs
|
||||
.nilIfEmpty
|
||||
@ -107,7 +107,7 @@ private extension WireGuardView.ConfigurationView {
|
||||
))
|
||||
}
|
||||
peer.keepAlive.map {
|
||||
rows.append(.text(caption: Strings.Global.keepAlive, value: TimeInterval($0).localizedDescription(style: .timeString)))
|
||||
rows.append(.text(caption: Strings.Global.Nouns.keepAlive, value: TimeInterval($0).localizedDescription(style: .timeString)))
|
||||
}
|
||||
return rows.nilIfEmpty
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ private extension ModuleDetailView {
|
||||
}
|
||||
|
||||
var emptyView: some View {
|
||||
Text(Strings.Global.noSelection)
|
||||
Text(Strings.Global.Nouns.noSelection)
|
||||
.themeEmptyMessage()
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ private extension View {
|
||||
}
|
||||
} else {
|
||||
Text(caption)
|
||||
.themeTrailingValue(Strings.Global.empty)
|
||||
.themeTrailingValue(Strings.Global.Nouns.empty)
|
||||
}
|
||||
|
||||
case .copiableText(let caption, let value, let multiline):
|
||||
|
@ -35,11 +35,11 @@ struct NameSection: View {
|
||||
var body: some View {
|
||||
debugChanges()
|
||||
return Group {
|
||||
ThemeTextField(Strings.Global.name, text: $name, placeholder: placeholder)
|
||||
ThemeTextField(Strings.Global.Nouns.name, text: $name, placeholder: placeholder)
|
||||
.labelsHidden()
|
||||
.themeManualInput()
|
||||
}
|
||||
.themeSection(header: Strings.Global.name)
|
||||
.themeSection(header: Strings.Global.Nouns.name)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,11 +74,11 @@ struct ProfileCoordinator: View {
|
||||
contentView
|
||||
.modifier(PaywallModifier(reason: $paywallReason))
|
||||
.alert(Strings.Views.Profile.Alerts.Purchase.title, isPresented: $requiresPurchase) {
|
||||
Button(Strings.Global.purchase) {
|
||||
Button(Strings.Global.Actions.purchase) {
|
||||
paywallReason = .purchase(requiredFeatures, nil)
|
||||
}
|
||||
Button(Strings.Views.Profile.Alerts.Purchase.Buttons.ok, action: onDismiss)
|
||||
Button(Strings.Global.cancel, role: .cancel, action: {})
|
||||
Button(Strings.Global.Actions.cancel, role: .cancel, action: {})
|
||||
} message: {
|
||||
Text(purchaseMessage)
|
||||
}
|
||||
@ -142,7 +142,7 @@ private extension ProfileCoordinator {
|
||||
try await onCommitEditingRestricted()
|
||||
}
|
||||
} catch {
|
||||
errorHandler.handle(error, title: Strings.Global.save)
|
||||
errorHandler.handle(error, title: Strings.Global.Actions.save)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ private extension StorageSection {
|
||||
}
|
||||
|
||||
var tvToggle: some View {
|
||||
Toggle(Strings.Modules.General.Rows.appleTv(Strings.Unlocalized.appleTV), isOn: $profileEditor.isAvailableForTV)
|
||||
Toggle(Strings.Modules.General.Rows.appletv(Strings.Unlocalized.appleTV), isOn: $profileEditor.isAvailableForTV)
|
||||
.disabled(!iapManager.isEligible(for: .appleTV) || !profileEditor.isShared)
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ private extension StorageSection {
|
||||
var purchaseTVButton: some View {
|
||||
EmptyView()
|
||||
.modifier(PurchaseButtonModifier(
|
||||
Strings.Modules.General.Rows.AppleTv.purchase,
|
||||
Strings.Modules.General.Rows.Appletv.purchase,
|
||||
feature: .appleTV,
|
||||
suggesting: .Features.appleTV,
|
||||
showsIfRestricted: false,
|
||||
|
@ -63,7 +63,7 @@ struct ProfileEditView: View, Routable {
|
||||
UUIDSection(uuid: profileEditor.profile.id)
|
||||
}
|
||||
.toolbar(content: toolbarContent)
|
||||
.navigationTitle(Strings.Global.profile)
|
||||
.navigationTitle(Strings.Global.Nouns.profile)
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.navigationDestination(for: NavigationRoute.self, destination: pushDestination)
|
||||
}
|
||||
@ -77,14 +77,14 @@ private extension ProfileEditView {
|
||||
func toolbarContent() -> some ToolbarContent {
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
ProfileSaveButton(
|
||||
title: Strings.Global.save,
|
||||
title: Strings.Global.Actions.save,
|
||||
errorModuleIds: $errorModuleIds
|
||||
) {
|
||||
try await flow?.onCommitEditing()
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button(Strings.Global.cancel, role: .cancel) {
|
||||
Button(Strings.Global.Actions.cancel, role: .cancel) {
|
||||
flow?.onCancelEditing()
|
||||
}
|
||||
}
|
||||
@ -99,7 +99,7 @@ private extension ProfileEditView {
|
||||
addModuleButton
|
||||
}
|
||||
.themeSection(
|
||||
header: Strings.Global.modules,
|
||||
header: Strings.Global.Nouns.modules,
|
||||
footer: Strings.Views.Profile.ModuleList.Section.footer
|
||||
)
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ struct ModuleListView: View, Routable {
|
||||
var body: some View {
|
||||
List(selection: $selectedModuleId) {
|
||||
Section {
|
||||
NavigationLink(Strings.Global.general, value: ProfileSplitView.Detail.general)
|
||||
NavigationLink(Strings.Global.Nouns.general, value: ProfileSplitView.Detail.general)
|
||||
.tag(Self.generalModuleId)
|
||||
}
|
||||
Group {
|
||||
@ -61,7 +61,7 @@ struct ModuleListView: View, Routable {
|
||||
}
|
||||
.onMove(perform: moveModules)
|
||||
}
|
||||
.themeSection(header: !profileEditor.modules.isEmpty ? Strings.Global.modules : nil)
|
||||
.themeSection(header: !profileEditor.modules.isEmpty ? Strings.Global.Nouns.modules : nil)
|
||||
}
|
||||
.onDeleteCommand(perform: removeSelectedModule)
|
||||
.toolbar(content: toolbarContent)
|
||||
|
@ -84,13 +84,13 @@ extension ProfileSplitView {
|
||||
@ToolbarContentBuilder
|
||||
func toolbarContent() -> some ToolbarContent {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button(Strings.Global.cancel, role: .cancel) {
|
||||
Button(Strings.Global.Actions.cancel, role: .cancel) {
|
||||
flow?.onCancelEditing()
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
ProfileSaveButton(
|
||||
title: Strings.Global.save,
|
||||
title: Strings.Global.Actions.save,
|
||||
errorModuleIds: $errorModuleIds
|
||||
) {
|
||||
try await flow?.onCommitEditing()
|
||||
|
@ -82,7 +82,7 @@ private extension ProviderContentModifier {
|
||||
providerRows
|
||||
refreshButton {
|
||||
HStack {
|
||||
Text(Strings.Providers.refreshInfrastructure)
|
||||
Text(Strings.Views.Providers.refreshInfrastructure)
|
||||
if providerManager.isLoading {
|
||||
Spacer()
|
||||
ProgressView()
|
||||
@ -109,7 +109,7 @@ private extension ProviderContentModifier {
|
||||
}
|
||||
Spacer()
|
||||
refreshButton {
|
||||
Text(Strings.Providers.refreshInfrastructure)
|
||||
Text(Strings.Views.Providers.refreshInfrastructure)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,9 +148,9 @@ private extension ProviderContentModifier {
|
||||
|
||||
var lastUpdatedString: String? {
|
||||
guard let lastUpdate else {
|
||||
return providerManager.isLoading ? Strings.Providers.LastUpdated.loading : nil
|
||||
return providerManager.isLoading ? Strings.Views.Providers.LastUpdated.loading : nil
|
||||
}
|
||||
return Strings.Providers.lastUpdated(lastUpdate.localizedDescription(style: .timestamp))
|
||||
return Strings.Views.Providers.lastUpdated(lastUpdate.localizedDescription(style: .timestamp))
|
||||
}
|
||||
}
|
||||
|
@ -43,19 +43,19 @@ struct ProviderPicker: View {
|
||||
var body: some View {
|
||||
Picker(selection: $providerId) {
|
||||
if !providers.isEmpty {
|
||||
Text(isRequired ? Strings.Providers.selectProvider : Strings.Providers.noProvider)
|
||||
Text(isRequired ? Strings.Views.Providers.selectProvider : Strings.Views.Providers.noProvider)
|
||||
.tag(nil as ProviderID?)
|
||||
ForEach(providers, id: \.id) {
|
||||
Text($0.description)
|
||||
.tag($0.id as ProviderID?)
|
||||
}
|
||||
} else {
|
||||
Text(isLoading ? Strings.Global.loading : Strings.Global.none)
|
||||
Text(isLoading ? Strings.Global.Nouns.loading : Strings.Global.Nouns.none)
|
||||
.tag(providerId) // tag always exists
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Text(Strings.Global.provider)
|
||||
Text(Strings.Global.Nouns.provider)
|
||||
PurchaseRequiredButton(for: providerId, paywallReason: $paywallReason)
|
||||
}
|
||||
}
|
@ -66,8 +66,8 @@ private extension VPNFiltersView {
|
||||
}
|
||||
|
||||
var categoryPicker: some View {
|
||||
Picker(Strings.Global.category, selection: categoryNameBinding) {
|
||||
Text(Strings.Global.any)
|
||||
Picker(Strings.Global.Nouns.category, selection: categoryNameBinding) {
|
||||
Text(Strings.Global.Nouns.any)
|
||||
.tag(nil as String?)
|
||||
ForEach(model.categories, id: \.self) {
|
||||
Text($0.capitalized)
|
||||
@ -77,8 +77,8 @@ private extension VPNFiltersView {
|
||||
}
|
||||
|
||||
var countryPicker: some View {
|
||||
Picker(Strings.Global.country, selection: $model.filters.countryCode) {
|
||||
Text(Strings.Global.any)
|
||||
Picker(Strings.Global.Nouns.country, selection: $model.filters.countryCode) {
|
||||
Text(Strings.Global.Nouns.any)
|
||||
.tag(nil as String?)
|
||||
ForEach(model.countries, id: \.code) {
|
||||
ThemeCountryText($0.code, title: $0.description)
|
||||
@ -88,8 +88,8 @@ private extension VPNFiltersView {
|
||||
}
|
||||
|
||||
var presetPicker: some View {
|
||||
Picker(Strings.Providers.Vpn.preset, selection: $model.filters.presetId) {
|
||||
Text(Strings.Global.any)
|
||||
Picker(Strings.Views.Providers.Vpn.preset, selection: $model.filters.presetId) {
|
||||
Text(Strings.Global.Nouns.any)
|
||||
.tag(nil as String?)
|
||||
ForEach(model.presets, id: \.presetId) {
|
||||
Text($0.description)
|
||||
@ -99,11 +99,11 @@ private extension VPNFiltersView {
|
||||
}
|
||||
|
||||
var favoritesToggle: some View {
|
||||
Toggle(Strings.Providers.onlyFavorites, isOn: $model.onlyShowsFavorites)
|
||||
Toggle(Strings.Views.Providers.onlyFavorites, isOn: $model.onlyShowsFavorites)
|
||||
}
|
||||
|
||||
var clearFiltersButton: some View {
|
||||
Button(Strings.Providers.clearFilters, role: .destructive) {
|
||||
Button(Strings.Views.Providers.clearFilters, role: .destructive) {
|
||||
model.filters = VPNFilters()
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ private extension VPNProviderContentModifier {
|
||||
var providerEntityRow: some View {
|
||||
NavigationLink(value: entityDestination) {
|
||||
HStack {
|
||||
Text(Strings.Global.server)
|
||||
Text(Strings.Global.Nouns.server)
|
||||
if let selectedEntity {
|
||||
Spacer()
|
||||
Text(selectedEntity.server.hostname ?? selectedEntity.server.serverId)
|
@ -65,7 +65,7 @@ private extension VPNProviderServerCoordinator {
|
||||
try await onSelect(entity)
|
||||
} catch {
|
||||
pp_log(.app, .fault, "Unable to select server \(server.serverId) for provider \(server.provider.id): \(error)")
|
||||
errorHandler.handle(error, title: Strings.Providers.selectEntity)
|
||||
errorHandler.handle(error, title: Strings.Views.Providers.selectEntity)
|
||||
}
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ struct VPNProviderServerView<Configuration>: View where Configuration: ProviderC
|
||||
|
||||
let filtersWithSelection: Bool
|
||||
|
||||
var selectTitle = Strings.Providers.selectEntity
|
||||
var selectTitle = Strings.Views.Providers.selectEntity
|
||||
|
||||
let onSelect: (VPNServer, VPNPreset<Configuration>) -> Void
|
||||
|
||||
@ -163,7 +163,7 @@ extension VPNProviderServerView {
|
||||
await reloadServers(filters: filtersViewModel.filters)
|
||||
} catch {
|
||||
pp_log(.app, .error, "Unable to load VPN repository: \(error)")
|
||||
errorHandler.handle(error, title: Strings.Global.servers)
|
||||
errorHandler.handle(error, title: Strings.Global.Nouns.servers)
|
||||
}
|
||||
}
|
||||
.onReceive(filtersViewModel.$filters.dropFirst()) { newValue in
|
||||
@ -184,7 +184,7 @@ extension VPNProviderServerView {
|
||||
|
||||
private extension VPNProviderServerView.ServersView {
|
||||
var title: String {
|
||||
providerManager.provider(withId: providerId)?.description ?? Strings.Global.servers
|
||||
providerManager.provider(withId: providerId)?.description ?? Strings.Global.Nouns.servers
|
||||
}
|
||||
|
||||
var filteredServers: [VPNServer] {
|
@ -75,7 +75,7 @@ private extension VPNProviderServerView {
|
||||
func body(content: Content) -> some View {
|
||||
NavigationStack {
|
||||
content
|
||||
.navigationTitle(Strings.Global.filters)
|
||||
.navigationTitle(Strings.Global.Nouns.filters)
|
||||
.themeNavigationDetail()
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
@ -127,7 +127,7 @@ private extension VPNProviderServerView.ServersSubview {
|
||||
var listView: some View {
|
||||
List {
|
||||
Section {
|
||||
Toggle(Strings.Providers.onlyFavorites, isOn: $filtersViewModel.onlyShowsFavorites)
|
||||
Toggle(Strings.Views.Providers.onlyFavorites, isOn: $filtersViewModel.onlyShowsFavorites)
|
||||
}
|
||||
Group {
|
||||
if isFiltering || !servers.isEmpty {
|
||||
@ -142,7 +142,7 @@ private extension VPNProviderServerView.ServersSubview {
|
||||
}
|
||||
}
|
||||
.themeSection(
|
||||
header: filtersViewModel.filters.categoryName ?? Strings.Providers.Vpn.Category.any
|
||||
header: filtersViewModel.filters.categoryName ?? Strings.Views.Providers.Vpn.Category.any
|
||||
)
|
||||
.onLoad {
|
||||
if let selectedServer {
|
||||
@ -153,7 +153,7 @@ private extension VPNProviderServerView.ServersSubview {
|
||||
}
|
||||
|
||||
var emptyView: some View {
|
||||
Text(Strings.Providers.Vpn.noServers)
|
||||
Text(Strings.Views.Providers.Vpn.noServers)
|
||||
}
|
||||
}
|
||||
|
@ -77,13 +77,13 @@ extension VPNProviderServerView {
|
||||
}
|
||||
.width(10.0)
|
||||
|
||||
TableColumn(Strings.Global.region) { server in
|
||||
TableColumn(Strings.Global.Nouns.region) { server in
|
||||
ThemeCountryText(server.provider.countryCode, title: server.region)
|
||||
.help(server.region)
|
||||
.environmentObject(theme) // TODO: #873, Table loses environment
|
||||
}
|
||||
|
||||
TableColumn(Strings.Global.address, value: \.address)
|
||||
TableColumn(Strings.Global.Nouns.address, value: \.address)
|
||||
|
||||
TableColumn("") { server in
|
||||
FavoriteToggle(
|
@ -45,7 +45,7 @@ public struct AppCoordinator: View, AppCoordinatorConforming {
|
||||
return TabView {
|
||||
profileView
|
||||
.tabItem {
|
||||
Text(Strings.Global.profile)
|
||||
Text(Strings.Global.Nouns.profile)
|
||||
}
|
||||
|
||||
// searchView
|
||||
|
@ -83,7 +83,7 @@ struct ActiveProfileView: View {
|
||||
|
||||
private extension ActiveProfileView {
|
||||
var currentProfileView: some View {
|
||||
Text(profile?.name ?? Strings.Views.Profiles.Rows.notInstalled)
|
||||
Text(profile?.name ?? Strings.Views.App.Rows.notInstalled)
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@ -100,18 +100,18 @@ private extension ActiveProfileView {
|
||||
func detailView(for profile: Profile) -> some View {
|
||||
VStack(spacing: 10) {
|
||||
if let connectionType = profile.localizedDescription(optionalStyle: .connectionType) {
|
||||
DetailRowView(title: Strings.Global.protocol) {
|
||||
DetailRowView(title: Strings.Global.Nouns.protocol) {
|
||||
Text(connectionType)
|
||||
}
|
||||
}
|
||||
if let pair = profile.selectedProvider {
|
||||
if let metadata = providerManager.provider(withId: pair.selection.id) {
|
||||
DetailRowView(title: Strings.Global.provider) {
|
||||
DetailRowView(title: Strings.Global.Nouns.provider) {
|
||||
Text(metadata.description)
|
||||
}
|
||||
}
|
||||
if let entity = pair.selection.entity {
|
||||
DetailRowView(title: Strings.Global.country) {
|
||||
DetailRowView(title: Strings.Global.Nouns.country) {
|
||||
ThemeCountryText(entity.header.countryCode)
|
||||
}
|
||||
}
|
||||
@ -135,7 +135,7 @@ private extension ActiveProfileView {
|
||||
onProviderEntityRequired: onProviderEntityRequired,
|
||||
onPurchaseRequired: onPurchaseRequired,
|
||||
label: {
|
||||
Text($0 ? Strings.Global.connect : Strings.Global.disconnect)
|
||||
Text($0 ? Strings.Global.Actions.connect : Strings.Global.Actions.disconnect)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 10)
|
||||
}
|
||||
@ -159,7 +159,7 @@ private extension ActiveProfileView {
|
||||
Button {
|
||||
isSwitching.toggle()
|
||||
} label: {
|
||||
Text(Strings.Global.select)
|
||||
Text(Strings.Global.Actions.select)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 10)
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ struct ProfileListView: View {
|
||||
.listStyle(.grouped)
|
||||
.scrollClipDisabled()
|
||||
.themeProgress(if: false, isEmpty: !profileManager.hasProfiles) {
|
||||
Text(Strings.Views.Profiles.Folders.noProfiles)
|
||||
Text(Strings.Views.App.Folders.noProfiles)
|
||||
.themeEmptyMessage()
|
||||
}
|
||||
}
|
||||
@ -68,7 +68,7 @@ private extension ProfileListView {
|
||||
}
|
||||
|
||||
var headerView: some View {
|
||||
Text(Strings.Views.Profiles.Tv.header(Strings.Unlocalized.appName, Strings.Unlocalized.appleTV))
|
||||
Text(Strings.Views.App.Tv.header(Strings.Unlocalized.appName, Strings.Unlocalized.appleTV))
|
||||
.textCase(.none)
|
||||
.foregroundStyle(.primary)
|
||||
.font(.body)
|
||||
|
@ -126,8 +126,8 @@ private extension ProfileView {
|
||||
InteractiveCoordinator(style: .inline(withCancel: false), manager: interactiveManager) {
|
||||
errorHandler.handle(
|
||||
$0,
|
||||
title: Strings.Global.connection,
|
||||
message: Strings.Views.Profiles.Errors.tunnel
|
||||
title: Strings.Global.Nouns.connection,
|
||||
message: Strings.Views.App.Errors.tunnel
|
||||
)
|
||||
}
|
||||
.font(.body)
|
||||
|
@ -26,5 +26,5 @@
|
||||
import Foundation
|
||||
|
||||
extension AppProduct {
|
||||
static let providerPrefix = "providers."
|
||||
static let providerPrefix = "views.providers."
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ extension AppFeature: LocalizableEntity {
|
||||
let V = Strings.Features.self
|
||||
switch self {
|
||||
case .appleTV:
|
||||
return V.appleTV(Strings.Unlocalized.appleTV)
|
||||
return V.appletv(Strings.Unlocalized.appleTV)
|
||||
|
||||
case .dns:
|
||||
return V.dns(Strings.Unlocalized.dns)
|
||||
@ -50,7 +50,7 @@ extension AppFeature: LocalizableEntity {
|
||||
return V.providers
|
||||
|
||||
case .routing:
|
||||
return V.routing(Strings.Global.routing)
|
||||
return V.routing(Strings.Global.Nouns.routing)
|
||||
|
||||
case .sharing:
|
||||
return V.sharing(Strings.Unlocalized.iCloud)
|
||||
|
@ -32,7 +32,7 @@ extension ErrorHandler {
|
||||
public static func `default`() -> ErrorHandler {
|
||||
ErrorHandler(
|
||||
defaultTitle: Strings.Unlocalized.appName,
|
||||
dismissTitle: Strings.Global.ok,
|
||||
dismissTitle: Strings.Global.Nouns.ok,
|
||||
errorDescription: {
|
||||
AppError($0).localizedDescription
|
||||
},
|
||||
|
@ -37,7 +37,7 @@ extension TimeInterval: StyledLocalizableEntity {
|
||||
if self > 0 {
|
||||
return asTimeString
|
||||
} else {
|
||||
return Strings.Global.disabled
|
||||
return Strings.Global.Nouns.disabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,10 +44,10 @@ extension ModuleType: LocalizableEntity {
|
||||
return Strings.Unlocalized.httpProxy
|
||||
|
||||
case .ip:
|
||||
return Strings.Global.routing
|
||||
return Strings.Global.Nouns.routing
|
||||
|
||||
case .onDemand:
|
||||
return Strings.Global.onDemand
|
||||
return Strings.Global.Nouns.onDemand
|
||||
|
||||
default:
|
||||
assertionFailure("Missing localization for ModuleType: \(rawValue)")
|
||||
|
@ -31,7 +31,7 @@ extension OpenVPN.PullMask: LocalizableEntity {
|
||||
public var localizedDescription: String {
|
||||
switch self {
|
||||
case .routes:
|
||||
return Strings.Global.routes
|
||||
return Strings.Global.Nouns.routes
|
||||
|
||||
case .dns:
|
||||
return Strings.Unlocalized.dns
|
||||
@ -58,7 +58,7 @@ extension OpenVPN.CompressionFraming: LocalizableEntity {
|
||||
public var localizedDescription: String {
|
||||
switch self {
|
||||
case .disabled:
|
||||
return Strings.Global.disabled
|
||||
return Strings.Global.Nouns.disabled
|
||||
|
||||
case .compLZO:
|
||||
return Strings.Unlocalized.OpenVPN.compLZO
|
||||
@ -67,7 +67,7 @@ extension OpenVPN.CompressionFraming: LocalizableEntity {
|
||||
return Strings.Unlocalized.OpenVPN.compress
|
||||
|
||||
default:
|
||||
return Strings.Global.unknown
|
||||
return Strings.Global.Nouns.unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,7 +76,7 @@ extension OpenVPN.CompressionAlgorithm: LocalizableEntity {
|
||||
public var localizedDescription: String {
|
||||
switch self {
|
||||
case .disabled:
|
||||
return Strings.Global.disabled
|
||||
return Strings.Global.Nouns.disabled
|
||||
|
||||
case .LZO:
|
||||
return Strings.Unlocalized.OpenVPN.lzo
|
||||
@ -85,7 +85,7 @@ extension OpenVPN.CompressionAlgorithm: LocalizableEntity {
|
||||
return Strings.Entities.Openvpn.CompressionAlgorithm.other
|
||||
|
||||
default:
|
||||
return Strings.Global.unknown
|
||||
return Strings.Global.Nouns.unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -189,7 +189,7 @@ extension OpenVPN.Configuration.Builder: StyledOptionalLocalizableEntity {
|
||||
private extension Optional where Wrapped == OpenVPN.TLSWrap {
|
||||
var tlsWrapDescription: String {
|
||||
guard let strategy = self?.strategy else {
|
||||
return Strings.Global.disabled
|
||||
return Strings.Global.Nouns.disabled
|
||||
}
|
||||
switch strategy {
|
||||
case .auth:
|
||||
@ -203,19 +203,19 @@ private extension Optional where Wrapped == OpenVPN.TLSWrap {
|
||||
|
||||
private extension Optional where Wrapped == Bool {
|
||||
var ekuDescription: String {
|
||||
let V = Strings.Global.self
|
||||
let V = Strings.Global.Nouns.self
|
||||
return (self ?? false) ? V.enabled : V.disabled
|
||||
}
|
||||
}
|
||||
|
||||
private extension Bool {
|
||||
var randomizeEndpointDescription: String {
|
||||
let V = Strings.Global.self
|
||||
let V = Strings.Global.Nouns.self
|
||||
return self ? V.enabled : V.disabled
|
||||
}
|
||||
|
||||
var randomizeHostnamesDescription: String {
|
||||
let V = Strings.Global.self
|
||||
let V = Strings.Global.Nouns.self
|
||||
return self ? V.enabled : V.disabled
|
||||
}
|
||||
}
|
||||
|
@ -82,25 +82,6 @@ extension TunnelStatus: LocalizableEntity {
|
||||
}
|
||||
}
|
||||
|
||||
extension ConnectionStatus: LocalizableEntity {
|
||||
public var localizedDescription: String {
|
||||
let V = Strings.Entities.ConnectionStatus.self
|
||||
switch self {
|
||||
case .disconnected:
|
||||
return V.disconnected
|
||||
|
||||
case .connecting:
|
||||
return V.connecting
|
||||
|
||||
case .connected:
|
||||
return V.connected
|
||||
|
||||
case .disconnecting:
|
||||
return V.disconnecting
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension DataCount: LocalizableEntity {
|
||||
public var localizedDescription: String {
|
||||
let down = received.descriptionAsDataUnit
|
||||
|
@ -11,14 +11,6 @@ import Foundation
|
||||
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
|
||||
public enum Strings {
|
||||
public enum Alerts {
|
||||
public enum Iap {
|
||||
public enum Restricted {
|
||||
/// Some features are unavailable in this build.
|
||||
public static let message = Strings.tr("Localizable", "alerts.iap.restricted.message", fallback: "Some features are unavailable in this build.")
|
||||
/// Restricted
|
||||
public static let title = Strings.tr("Localizable", "alerts.iap.restricted.title", fallback: "Restricted")
|
||||
}
|
||||
}
|
||||
public enum Import {
|
||||
public enum Passphrase {
|
||||
/// Enter passphrase for '%@'.
|
||||
@ -30,25 +22,7 @@ public enum Strings {
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum AppMenu {
|
||||
public enum Items {
|
||||
/// Quit %@
|
||||
public static func quit(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "app_menu.items.quit", String(describing: p1), fallback: "Quit %@")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Entities {
|
||||
public enum ConnectionStatus {
|
||||
/// Connected
|
||||
public static let connected = Strings.tr("Localizable", "entities.connection_status.connected", fallback: "Connected")
|
||||
/// Connecting
|
||||
public static let connecting = Strings.tr("Localizable", "entities.connection_status.connecting", fallback: "Connecting")
|
||||
/// Disconnected
|
||||
public static let disconnected = Strings.tr("Localizable", "entities.connection_status.disconnected", fallback: "Disconnected")
|
||||
/// Disconnecting
|
||||
public static let disconnecting = Strings.tr("Localizable", "entities.connection_status.disconnecting", fallback: "Disconnecting")
|
||||
}
|
||||
public enum Dns {
|
||||
/// Search domains
|
||||
public static let searchDomains = Strings.tr("Localizable", "entities.dns.search_domains", fallback: "Search domains")
|
||||
@ -91,12 +65,6 @@ public enum Strings {
|
||||
public static let `none` = Strings.tr("Localizable", "entities.openvpn.otp_method.none", fallback: "None")
|
||||
}
|
||||
}
|
||||
public enum Profile {
|
||||
public enum Name {
|
||||
/// New profile
|
||||
public static let new = Strings.tr("Localizable", "entities.profile.name.new", fallback: "New profile")
|
||||
}
|
||||
}
|
||||
public enum TunnelStatus {
|
||||
/// Activating
|
||||
public static let activating = Strings.tr("Localizable", "entities.tunnel_status.activating", fallback: "Activating")
|
||||
@ -174,8 +142,8 @@ public enum Strings {
|
||||
}
|
||||
public enum Features {
|
||||
/// %@
|
||||
public static func appleTV(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "features.appleTV", String(describing: p1), fallback: "%@")
|
||||
public static func appletv(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "features.appletv", String(describing: p1), fallback: "%@")
|
||||
}
|
||||
/// %@ Settings
|
||||
public static func dns(_ p1: Any) -> String {
|
||||
@ -183,12 +151,12 @@ public enum Strings {
|
||||
}
|
||||
/// %@ Settings
|
||||
public static func httpProxy(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "features.httpProxy", String(describing: p1), fallback: "%@ Settings")
|
||||
return Strings.tr("Localizable", "features.http_proxy", String(describing: p1), fallback: "%@ Settings")
|
||||
}
|
||||
/// Interactive Login
|
||||
public static let interactiveLogin = Strings.tr("Localizable", "features.interactiveLogin", fallback: "Interactive Login")
|
||||
/// On-Demand Rules
|
||||
public static let onDemand = Strings.tr("Localizable", "features.onDemand", fallback: "On-Demand Rules")
|
||||
public static let onDemand = Strings.tr("Localizable", "features.on_demand", fallback: "On-Demand Rules")
|
||||
/// All Providers
|
||||
public static let providers = Strings.tr("Localizable", "features.providers", fallback: "All Providers")
|
||||
/// Custom %@
|
||||
@ -201,156 +169,160 @@ public enum Strings {
|
||||
}
|
||||
}
|
||||
public enum Global {
|
||||
/// About
|
||||
public static let about = Strings.tr("Localizable", "global.about", fallback: "About")
|
||||
/// Account
|
||||
public static let account = Strings.tr("Localizable", "global.account", fallback: "Account")
|
||||
/// Address
|
||||
public static let address = Strings.tr("Localizable", "global.address", fallback: "Address")
|
||||
/// Addresses
|
||||
public static let addresses = Strings.tr("Localizable", "global.addresses", fallback: "Addresses")
|
||||
/// Any
|
||||
public static let any = Strings.tr("Localizable", "global.any", fallback: "Any")
|
||||
/// Cancel
|
||||
public static let cancel = Strings.tr("Localizable", "global.cancel", fallback: "Cancel")
|
||||
/// Category
|
||||
public static let category = Strings.tr("Localizable", "global.category", fallback: "Category")
|
||||
/// Certificate
|
||||
public static let certificate = Strings.tr("Localizable", "global.certificate", fallback: "Certificate")
|
||||
/// Compression
|
||||
public static let compression = Strings.tr("Localizable", "global.compression", fallback: "Compression")
|
||||
/// Connect
|
||||
public static let connect = Strings.tr("Localizable", "global.connect", fallback: "Connect")
|
||||
/// Connection
|
||||
public static let connection = Strings.tr("Localizable", "global.connection", fallback: "Connection")
|
||||
/// Country
|
||||
public static let country = Strings.tr("Localizable", "global.country", fallback: "Country")
|
||||
/// Default
|
||||
public static let `default` = Strings.tr("Localizable", "global.default", fallback: "Default")
|
||||
/// Delete
|
||||
public static let delete = Strings.tr("Localizable", "global.delete", fallback: "Delete")
|
||||
/// Destination
|
||||
public static let destination = Strings.tr("Localizable", "global.destination", fallback: "Destination")
|
||||
/// Disable
|
||||
public static let disable = Strings.tr("Localizable", "global.disable", fallback: "Disable")
|
||||
/// Disabled
|
||||
public static let disabled = Strings.tr("Localizable", "global.disabled", fallback: "Disabled")
|
||||
/// Disconnect
|
||||
public static let disconnect = Strings.tr("Localizable", "global.disconnect", fallback: "Disconnect")
|
||||
/// Don't ask again
|
||||
public static let doNotAskAgain = Strings.tr("Localizable", "global.do_not_ask_again", fallback: "Don't ask again")
|
||||
/// Domain
|
||||
public static let domain = Strings.tr("Localizable", "global.domain", fallback: "Domain")
|
||||
/// Done
|
||||
public static let done = Strings.tr("Localizable", "global.done", fallback: "Done")
|
||||
/// Duplicate
|
||||
public static let duplicate = Strings.tr("Localizable", "global.duplicate", fallback: "Duplicate")
|
||||
/// Edit
|
||||
public static let edit = Strings.tr("Localizable", "global.edit", fallback: "Edit")
|
||||
/// Empty
|
||||
public static let empty = Strings.tr("Localizable", "global.empty", fallback: "Empty")
|
||||
/// Enable
|
||||
public static let enable = Strings.tr("Localizable", "global.enable", fallback: "Enable")
|
||||
/// Enabled
|
||||
public static let enabled = Strings.tr("Localizable", "global.enabled", fallback: "Enabled")
|
||||
/// Endpoint
|
||||
public static let endpoint = Strings.tr("Localizable", "global.endpoint", fallback: "Endpoint")
|
||||
/// Filters
|
||||
public static let filters = Strings.tr("Localizable", "global.filters", fallback: "Filters")
|
||||
/// Folder
|
||||
public static let folder = Strings.tr("Localizable", "global.folder", fallback: "Folder")
|
||||
/// Gateway
|
||||
public static let gateway = Strings.tr("Localizable", "global.gateway", fallback: "Gateway")
|
||||
/// General
|
||||
public static let general = Strings.tr("Localizable", "global.general", fallback: "General")
|
||||
/// Hide
|
||||
public static let hide = Strings.tr("Localizable", "global.hide", fallback: "Hide")
|
||||
/// Hostname
|
||||
public static let hostname = Strings.tr("Localizable", "global.hostname", fallback: "Hostname")
|
||||
/// Interface
|
||||
public static let interface = Strings.tr("Localizable", "global.interface", fallback: "Interface")
|
||||
/// Keep-alive
|
||||
public static let keepAlive = Strings.tr("Localizable", "global.keep_alive", fallback: "Keep-alive")
|
||||
/// Key
|
||||
public static let key = Strings.tr("Localizable", "global.key", fallback: "Key")
|
||||
/// Last update
|
||||
public static let lastUpdate = Strings.tr("Localizable", "global.last_update", fallback: "Last update")
|
||||
/// Loading
|
||||
public static let loading = Strings.tr("Localizable", "global.loading", fallback: "Loading")
|
||||
/// Method
|
||||
public static let method = Strings.tr("Localizable", "global.method", fallback: "Method")
|
||||
/// Modules
|
||||
public static let modules = Strings.tr("Localizable", "global.modules", fallback: "Modules")
|
||||
/// %d seconds
|
||||
public static func nSeconds(_ p1: Int) -> String {
|
||||
return Strings.tr("Localizable", "global.n_seconds", p1, fallback: "%d seconds")
|
||||
public enum Actions {
|
||||
/// Cancel
|
||||
public static let cancel = Strings.tr("Localizable", "global.actions.cancel", fallback: "Cancel")
|
||||
/// Connect
|
||||
public static let connect = Strings.tr("Localizable", "global.actions.connect", fallback: "Connect")
|
||||
/// Delete
|
||||
public static let delete = Strings.tr("Localizable", "global.actions.delete", fallback: "Delete")
|
||||
/// Disable
|
||||
public static let disable = Strings.tr("Localizable", "global.actions.disable", fallback: "Disable")
|
||||
/// Disconnect
|
||||
public static let disconnect = Strings.tr("Localizable", "global.actions.disconnect", fallback: "Disconnect")
|
||||
/// Duplicate
|
||||
public static let duplicate = Strings.tr("Localizable", "global.actions.duplicate", fallback: "Duplicate")
|
||||
/// Edit
|
||||
public static let edit = Strings.tr("Localizable", "global.actions.edit", fallback: "Edit")
|
||||
/// Enable
|
||||
public static let enable = Strings.tr("Localizable", "global.actions.enable", fallback: "Enable")
|
||||
/// Hide
|
||||
public static let hide = Strings.tr("Localizable", "global.actions.hide", fallback: "Hide")
|
||||
/// Purchase
|
||||
public static let purchase = Strings.tr("Localizable", "global.actions.purchase", fallback: "Purchase")
|
||||
/// Delete
|
||||
public static let remove = Strings.tr("Localizable", "global.actions.remove", fallback: "Delete")
|
||||
/// Restart
|
||||
public static let restart = Strings.tr("Localizable", "global.actions.restart", fallback: "Restart")
|
||||
/// Save
|
||||
public static let save = Strings.tr("Localizable", "global.actions.save", fallback: "Save")
|
||||
/// Select
|
||||
public static let select = Strings.tr("Localizable", "global.actions.select", fallback: "Select")
|
||||
/// Show
|
||||
public static let show = Strings.tr("Localizable", "global.actions.show", fallback: "Show")
|
||||
}
|
||||
public enum Nouns {
|
||||
/// About
|
||||
public static let about = Strings.tr("Localizable", "global.nouns.about", fallback: "About")
|
||||
/// Account
|
||||
public static let account = Strings.tr("Localizable", "global.nouns.account", fallback: "Account")
|
||||
/// Address
|
||||
public static let address = Strings.tr("Localizable", "global.nouns.address", fallback: "Address")
|
||||
/// Addresses
|
||||
public static let addresses = Strings.tr("Localizable", "global.nouns.addresses", fallback: "Addresses")
|
||||
/// Any
|
||||
public static let any = Strings.tr("Localizable", "global.nouns.any", fallback: "Any")
|
||||
/// Category
|
||||
public static let category = Strings.tr("Localizable", "global.nouns.category", fallback: "Category")
|
||||
/// Certificate
|
||||
public static let certificate = Strings.tr("Localizable", "global.nouns.certificate", fallback: "Certificate")
|
||||
/// Compression
|
||||
public static let compression = Strings.tr("Localizable", "global.nouns.compression", fallback: "Compression")
|
||||
/// Connection
|
||||
public static let connection = Strings.tr("Localizable", "global.nouns.connection", fallback: "Connection")
|
||||
/// Country
|
||||
public static let country = Strings.tr("Localizable", "global.nouns.country", fallback: "Country")
|
||||
/// Default
|
||||
public static let `default` = Strings.tr("Localizable", "global.nouns.default", fallback: "Default")
|
||||
/// Destination
|
||||
public static let destination = Strings.tr("Localizable", "global.nouns.destination", fallback: "Destination")
|
||||
/// Disabled
|
||||
public static let disabled = Strings.tr("Localizable", "global.nouns.disabled", fallback: "Disabled")
|
||||
/// Don't ask again
|
||||
public static let doNotAskAgain = Strings.tr("Localizable", "global.nouns.do_not_ask_again", fallback: "Don't ask again")
|
||||
/// Domain
|
||||
public static let domain = Strings.tr("Localizable", "global.nouns.domain", fallback: "Domain")
|
||||
/// Done
|
||||
public static let done = Strings.tr("Localizable", "global.nouns.done", fallback: "Done")
|
||||
/// Empty
|
||||
public static let empty = Strings.tr("Localizable", "global.nouns.empty", fallback: "Empty")
|
||||
/// Enabled
|
||||
public static let enabled = Strings.tr("Localizable", "global.nouns.enabled", fallback: "Enabled")
|
||||
/// Endpoint
|
||||
public static let endpoint = Strings.tr("Localizable", "global.nouns.endpoint", fallback: "Endpoint")
|
||||
/// Filters
|
||||
public static let filters = Strings.tr("Localizable", "global.nouns.filters", fallback: "Filters")
|
||||
/// Folder
|
||||
public static let folder = Strings.tr("Localizable", "global.nouns.folder", fallback: "Folder")
|
||||
/// Gateway
|
||||
public static let gateway = Strings.tr("Localizable", "global.nouns.gateway", fallback: "Gateway")
|
||||
/// General
|
||||
public static let general = Strings.tr("Localizable", "global.nouns.general", fallback: "General")
|
||||
/// Hostname
|
||||
public static let hostname = Strings.tr("Localizable", "global.nouns.hostname", fallback: "Hostname")
|
||||
/// Interface
|
||||
public static let interface = Strings.tr("Localizable", "global.nouns.interface", fallback: "Interface")
|
||||
/// Keep-alive
|
||||
public static let keepAlive = Strings.tr("Localizable", "global.nouns.keep_alive", fallback: "Keep-alive")
|
||||
/// Key
|
||||
public static let key = Strings.tr("Localizable", "global.nouns.key", fallback: "Key")
|
||||
/// Last update
|
||||
public static let lastUpdate = Strings.tr("Localizable", "global.nouns.last_update", fallback: "Last update")
|
||||
/// Loading
|
||||
public static let loading = Strings.tr("Localizable", "global.nouns.loading", fallback: "Loading")
|
||||
/// Method
|
||||
public static let method = Strings.tr("Localizable", "global.nouns.method", fallback: "Method")
|
||||
/// Modules
|
||||
public static let modules = Strings.tr("Localizable", "global.nouns.modules", fallback: "Modules")
|
||||
/// %d seconds
|
||||
public static func nSeconds(_ p1: Int) -> String {
|
||||
return Strings.tr("Localizable", "global.nouns.n_seconds", p1, fallback: "%d seconds")
|
||||
}
|
||||
/// Name
|
||||
public static let name = Strings.tr("Localizable", "global.nouns.name", fallback: "Name")
|
||||
/// Networks
|
||||
public static let networks = Strings.tr("Localizable", "global.nouns.networks", fallback: "Networks")
|
||||
/// No content
|
||||
public static let noContent = Strings.tr("Localizable", "global.nouns.no_content", fallback: "No content")
|
||||
/// No selection
|
||||
public static let noSelection = Strings.tr("Localizable", "global.nouns.no_selection", fallback: "No selection")
|
||||
/// None
|
||||
public static let `none` = Strings.tr("Localizable", "global.nouns.none", fallback: "None")
|
||||
/// OK
|
||||
public static let ok = Strings.tr("Localizable", "global.nouns.ok", fallback: "OK")
|
||||
/// On-demand
|
||||
public static let onDemand = Strings.tr("Localizable", "global.nouns.on_demand", fallback: "On-demand")
|
||||
/// Other
|
||||
public static let other = Strings.tr("Localizable", "global.nouns.other", fallback: "Other")
|
||||
/// Password
|
||||
public static let password = Strings.tr("Localizable", "global.nouns.password", fallback: "Password")
|
||||
/// Port
|
||||
public static let port = Strings.tr("Localizable", "global.nouns.port", fallback: "Port")
|
||||
/// Private key
|
||||
public static let privateKey = Strings.tr("Localizable", "global.nouns.private_key", fallback: "Private key")
|
||||
/// Profile
|
||||
public static let profile = Strings.tr("Localizable", "global.nouns.profile", fallback: "Profile")
|
||||
/// Protocol
|
||||
public static let `protocol` = Strings.tr("Localizable", "global.nouns.protocol", fallback: "Protocol")
|
||||
/// Provider
|
||||
public static let provider = Strings.tr("Localizable", "global.nouns.provider", fallback: "Provider")
|
||||
/// Public key
|
||||
public static let publicKey = Strings.tr("Localizable", "global.nouns.public_key", fallback: "Public key")
|
||||
/// Region
|
||||
public static let region = Strings.tr("Localizable", "global.nouns.region", fallback: "Region")
|
||||
/// Route
|
||||
public static let route = Strings.tr("Localizable", "global.nouns.route", fallback: "Route")
|
||||
/// Routes
|
||||
public static let routes = Strings.tr("Localizable", "global.nouns.routes", fallback: "Routes")
|
||||
/// Routing
|
||||
public static let routing = Strings.tr("Localizable", "global.nouns.routing", fallback: "Routing")
|
||||
/// Server
|
||||
public static let server = Strings.tr("Localizable", "global.nouns.server", fallback: "Server")
|
||||
/// Servers
|
||||
public static let servers = Strings.tr("Localizable", "global.nouns.servers", fallback: "Servers")
|
||||
/// Settings
|
||||
public static let settings = Strings.tr("Localizable", "global.nouns.settings", fallback: "Settings")
|
||||
/// Status
|
||||
public static let status = Strings.tr("Localizable", "global.nouns.status", fallback: "Status")
|
||||
/// Subnet
|
||||
public static let subnet = Strings.tr("Localizable", "global.nouns.subnet", fallback: "Subnet")
|
||||
/// Unknown
|
||||
public static let unknown = Strings.tr("Localizable", "global.nouns.unknown", fallback: "Unknown")
|
||||
/// Username
|
||||
public static let username = Strings.tr("Localizable", "global.nouns.username", fallback: "Username")
|
||||
/// Version
|
||||
public static let version = Strings.tr("Localizable", "global.nouns.version", fallback: "Version")
|
||||
}
|
||||
/// Name
|
||||
public static let name = Strings.tr("Localizable", "global.name", fallback: "Name")
|
||||
/// Networks
|
||||
public static let networks = Strings.tr("Localizable", "global.networks", fallback: "Networks")
|
||||
/// No content
|
||||
public static let noContent = Strings.tr("Localizable", "global.no_content", fallback: "No content")
|
||||
/// No selection
|
||||
public static let noSelection = Strings.tr("Localizable", "global.no_selection", fallback: "No selection")
|
||||
/// None
|
||||
public static let `none` = Strings.tr("Localizable", "global.none", fallback: "None")
|
||||
/// OK
|
||||
public static let ok = Strings.tr("Localizable", "global.ok", fallback: "OK")
|
||||
/// On-demand
|
||||
public static let onDemand = Strings.tr("Localizable", "global.on_demand", fallback: "On-demand")
|
||||
/// Other
|
||||
public static let other = Strings.tr("Localizable", "global.other", fallback: "Other")
|
||||
/// Password
|
||||
public static let password = Strings.tr("Localizable", "global.password", fallback: "Password")
|
||||
/// Port
|
||||
public static let port = Strings.tr("Localizable", "global.port", fallback: "Port")
|
||||
/// Private key
|
||||
public static let privateKey = Strings.tr("Localizable", "global.private_key", fallback: "Private key")
|
||||
/// Profile
|
||||
public static let profile = Strings.tr("Localizable", "global.profile", fallback: "Profile")
|
||||
/// Protocol
|
||||
public static let `protocol` = Strings.tr("Localizable", "global.protocol", fallback: "Protocol")
|
||||
/// Provider
|
||||
public static let provider = Strings.tr("Localizable", "global.provider", fallback: "Provider")
|
||||
/// Public key
|
||||
public static let publicKey = Strings.tr("Localizable", "global.public_key", fallback: "Public key")
|
||||
/// Purchase
|
||||
public static let purchase = Strings.tr("Localizable", "global.purchase", fallback: "Purchase")
|
||||
/// Region
|
||||
public static let region = Strings.tr("Localizable", "global.region", fallback: "Region")
|
||||
/// Delete
|
||||
public static let remove = Strings.tr("Localizable", "global.remove", fallback: "Delete")
|
||||
/// Restart
|
||||
public static let restart = Strings.tr("Localizable", "global.restart", fallback: "Restart")
|
||||
/// Route
|
||||
public static let route = Strings.tr("Localizable", "global.route", fallback: "Route")
|
||||
/// Routes
|
||||
public static let routes = Strings.tr("Localizable", "global.routes", fallback: "Routes")
|
||||
/// Routing
|
||||
public static let routing = Strings.tr("Localizable", "global.routing", fallback: "Routing")
|
||||
/// Save
|
||||
public static let save = Strings.tr("Localizable", "global.save", fallback: "Save")
|
||||
/// Select
|
||||
public static let select = Strings.tr("Localizable", "global.select", fallback: "Select")
|
||||
/// Server
|
||||
public static let server = Strings.tr("Localizable", "global.server", fallback: "Server")
|
||||
/// Servers
|
||||
public static let servers = Strings.tr("Localizable", "global.servers", fallback: "Servers")
|
||||
/// Settings
|
||||
public static let settings = Strings.tr("Localizable", "global.settings", fallback: "Settings")
|
||||
/// Show
|
||||
public static let show = Strings.tr("Localizable", "global.show", fallback: "Show")
|
||||
/// Status
|
||||
public static let status = Strings.tr("Localizable", "global.status", fallback: "Status")
|
||||
/// Subnet
|
||||
public static let subnet = Strings.tr("Localizable", "global.subnet", fallback: "Subnet")
|
||||
/// Unknown
|
||||
public static let unknown = Strings.tr("Localizable", "global.unknown", fallback: "Unknown")
|
||||
/// Username
|
||||
public static let username = Strings.tr("Localizable", "global.username", fallback: "Username")
|
||||
/// Version
|
||||
public static let version = Strings.tr("Localizable", "global.version", fallback: "Version")
|
||||
}
|
||||
public enum Modules {
|
||||
public enum Dns {
|
||||
@ -366,16 +338,16 @@ public enum Strings {
|
||||
public enum General {
|
||||
public enum Rows {
|
||||
/// %@
|
||||
public static func appleTv(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "modules.general.rows.apple_tv", String(describing: p1), fallback: "%@")
|
||||
public static func appletv(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "modules.general.rows.appletv", String(describing: p1), fallback: "%@")
|
||||
}
|
||||
/// Import from file...
|
||||
public static let importFromFile = Strings.tr("Localizable", "modules.general.rows.import_from_file", fallback: "Import from file...")
|
||||
/// Enabled
|
||||
public static let shared = Strings.tr("Localizable", "modules.general.rows.shared", fallback: "Enabled")
|
||||
public enum AppleTv {
|
||||
public enum Appletv {
|
||||
/// Drop TV restriction
|
||||
public static let purchase = Strings.tr("Localizable", "modules.general.rows.apple_tv.purchase", fallback: "Drop TV restriction")
|
||||
public static let purchase = Strings.tr("Localizable", "modules.general.rows.appletv.purchase", fallback: "Drop TV restriction")
|
||||
}
|
||||
public enum Shared {
|
||||
/// Share on iCloud
|
||||
@ -514,44 +486,6 @@ public enum Strings {
|
||||
public static let providerKey = Strings.tr("Localizable", "modules.wireguard.provider_key", fallback: "Private key")
|
||||
}
|
||||
}
|
||||
public enum Paywall {
|
||||
public enum Alerts {
|
||||
public enum Pending {
|
||||
/// The purchase is pending external confirmation. The feature will be credited upon approval.
|
||||
public static let message = Strings.tr("Localizable", "paywall.alerts.pending.message", fallback: "The purchase is pending external confirmation. The feature will be credited upon approval.")
|
||||
}
|
||||
}
|
||||
public enum Rows {
|
||||
/// Restore purchases
|
||||
public static let restorePurchases = Strings.tr("Localizable", "paywall.rows.restore_purchases", fallback: "Restore purchases")
|
||||
}
|
||||
public enum Sections {
|
||||
public enum Features {
|
||||
public enum Other {
|
||||
/// Also included
|
||||
public static let header = Strings.tr("Localizable", "paywall.sections.features.other.header", fallback: "Also included")
|
||||
}
|
||||
public enum Required {
|
||||
/// Required features
|
||||
public static let header = Strings.tr("Localizable", "paywall.sections.features.required.header", fallback: "Required features")
|
||||
}
|
||||
}
|
||||
public enum OneTime {
|
||||
/// One-time purchase
|
||||
public static let header = Strings.tr("Localizable", "paywall.sections.one_time.header", fallback: "One-time purchase")
|
||||
}
|
||||
public enum Recurring {
|
||||
/// All features
|
||||
public static let header = Strings.tr("Localizable", "paywall.sections.recurring.header", fallback: "All features")
|
||||
}
|
||||
public enum Restore {
|
||||
/// If you bought this app or feature in the past, you can restore your purchases.
|
||||
public static let footer = Strings.tr("Localizable", "paywall.sections.restore.footer", fallback: "If you bought this app or feature in the past, you can restore your purchases.")
|
||||
/// Restore
|
||||
public static let header = Strings.tr("Localizable", "paywall.sections.restore.header", fallback: "Restore")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Placeholders {
|
||||
/// secret
|
||||
public static let secret = Strings.tr("Localizable", "placeholders.secret", fallback: "secret")
|
||||
@ -566,38 +500,6 @@ public enum Strings {
|
||||
public static let name = Strings.tr("Localizable", "placeholders.profile.name", fallback: "My profile")
|
||||
}
|
||||
}
|
||||
public enum Providers {
|
||||
/// Clear filters
|
||||
public static let clearFilters = Strings.tr("Localizable", "providers.clear_filters", fallback: "Clear filters")
|
||||
/// Last updated on %@
|
||||
public static func lastUpdated(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "providers.last_updated", String(describing: p1), fallback: "Last updated on %@")
|
||||
}
|
||||
/// None
|
||||
public static let noProvider = Strings.tr("Localizable", "providers.no_provider", fallback: "None")
|
||||
/// Only favorites
|
||||
public static let onlyFavorites = Strings.tr("Localizable", "providers.only_favorites", fallback: "Only favorites")
|
||||
/// Refresh infrastructure
|
||||
public static let refreshInfrastructure = Strings.tr("Localizable", "providers.refresh_infrastructure", fallback: "Refresh infrastructure")
|
||||
/// Select
|
||||
public static let selectEntity = Strings.tr("Localizable", "providers.select_entity", fallback: "Select")
|
||||
/// Select a provider
|
||||
public static let selectProvider = Strings.tr("Localizable", "providers.select_provider", fallback: "Select a provider")
|
||||
public enum LastUpdated {
|
||||
/// Loading...
|
||||
public static let loading = Strings.tr("Localizable", "providers.last_updated.loading", fallback: "Loading...")
|
||||
}
|
||||
public enum Vpn {
|
||||
/// No servers
|
||||
public static let noServers = Strings.tr("Localizable", "providers.vpn.no_servers", fallback: "No servers")
|
||||
/// Preset
|
||||
public static let preset = Strings.tr("Localizable", "providers.vpn.preset", fallback: "Preset")
|
||||
public enum Category {
|
||||
/// All categories
|
||||
public static let any = Strings.tr("Localizable", "providers.vpn.category.any", fallback: "All categories")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Theme {
|
||||
public enum Confirmation {
|
||||
/// Cancel
|
||||
@ -614,26 +516,6 @@ public enum Strings {
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Ui {
|
||||
public enum ConnectionStatus {
|
||||
/// (on-demand)
|
||||
public static let onDemandSuffix = Strings.tr("Localizable", "ui.connection_status.on_demand_suffix", fallback: " (on-demand)")
|
||||
}
|
||||
public enum ProfileContext {
|
||||
/// Connect to...
|
||||
public static let connectTo = Strings.tr("Localizable", "ui.profile_context.connect_to", fallback: "Connect to...")
|
||||
}
|
||||
public enum PurchaseRequired {
|
||||
public enum Purchase {
|
||||
/// Purchase required
|
||||
public static let help = Strings.tr("Localizable", "ui.purchase_required.purchase.help", fallback: "Purchase required")
|
||||
}
|
||||
public enum Restricted {
|
||||
/// Feature is restricted
|
||||
public static let help = Strings.tr("Localizable", "ui.purchase_required.restricted.help", fallback: "Feature is restricted")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Views {
|
||||
public enum About {
|
||||
/// About
|
||||
@ -675,6 +557,64 @@ public enum Strings {
|
||||
public static let resources = Strings.tr("Localizable", "views.about.sections.resources", fallback: "Resources")
|
||||
}
|
||||
}
|
||||
public enum App {
|
||||
public enum Errors {
|
||||
/// Unable to duplicate profile '%@'.
|
||||
public static func duplicate(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "views.app.errors.duplicate", String(describing: p1), fallback: "Unable to duplicate profile '%@'.")
|
||||
}
|
||||
/// Unable to import profiles.
|
||||
public static let `import` = Strings.tr("Localizable", "views.app.errors.import", fallback: "Unable to import profiles.")
|
||||
/// Unable to execute tunnel operation.
|
||||
public static let tunnel = Strings.tr("Localizable", "views.app.errors.tunnel", fallback: "Unable to execute tunnel operation.")
|
||||
}
|
||||
public enum Folders {
|
||||
/// Installed profile
|
||||
public static let activeProfile = Strings.tr("Localizable", "views.app.folders.active_profile", fallback: "Installed profile")
|
||||
/// Add profile
|
||||
public static let addProfile = Strings.tr("Localizable", "views.app.folders.add_profile", fallback: "Add profile")
|
||||
/// My profiles
|
||||
public static let `default` = Strings.tr("Localizable", "views.app.folders.default", fallback: "My profiles")
|
||||
/// No profiles
|
||||
public static let noProfiles = Strings.tr("Localizable", "views.app.folders.no_profiles", fallback: "No profiles")
|
||||
public enum NoProfiles {
|
||||
/// Migrate old profiles...
|
||||
public static let migrate = Strings.tr("Localizable", "views.app.folders.no_profiles.migrate", fallback: "Migrate old profiles...")
|
||||
}
|
||||
}
|
||||
public enum ProfileContext {
|
||||
/// Connect to...
|
||||
public static let connectTo = Strings.tr("Localizable", "views.app.profile_context.connect_to", fallback: "Connect to...")
|
||||
}
|
||||
public enum Rows {
|
||||
/// No active modules
|
||||
public static let noModules = Strings.tr("Localizable", "views.app.rows.no_modules", fallback: "No active modules")
|
||||
/// Select a profile
|
||||
public static let notInstalled = Strings.tr("Localizable", "views.app.rows.not_installed", fallback: "Select a profile")
|
||||
}
|
||||
public enum Toolbar {
|
||||
/// Import profile
|
||||
public static let importProfile = Strings.tr("Localizable", "views.app.toolbar.import_profile", fallback: "Import profile")
|
||||
/// Migrate profiles
|
||||
public static let migrateProfiles = Strings.tr("Localizable", "views.app.toolbar.migrate_profiles", fallback: "Migrate profiles")
|
||||
/// New profile
|
||||
public static let newProfile = Strings.tr("Localizable", "views.app.toolbar.new_profile", fallback: "New profile")
|
||||
}
|
||||
public enum Tv {
|
||||
/// Open %@ on your iOS or macOS device and enable the "%@" toggle of a profile to make it appear here.
|
||||
public static func header(_ p1: Any, _ p2: Any) -> String {
|
||||
return Strings.tr("Localizable", "views.app.tv.header", String(describing: p1), String(describing: p2), fallback: "Open %@ on your iOS or macOS device and enable the \"%@\" toggle of a profile to make it appear here.")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum AppMenu {
|
||||
public enum Items {
|
||||
/// Quit %@
|
||||
public static func quit(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "views.app_menu.items.quit", String(describing: p1), fallback: "Quit %@")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Diagnostics {
|
||||
/// Diagnostics
|
||||
public static let title = Strings.tr("Localizable", "views.diagnostics.title", fallback: "Diagnostics")
|
||||
@ -729,36 +669,106 @@ public enum Strings {
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Migrate {
|
||||
public enum Migration {
|
||||
/// Nothing to migrate
|
||||
public static let noProfiles = Strings.tr("Localizable", "views.migrate.no_profiles", fallback: "Nothing to migrate")
|
||||
public static let noProfiles = Strings.tr("Localizable", "views.migration.no_profiles", fallback: "Nothing to migrate")
|
||||
/// Migrate
|
||||
public static let title = Strings.tr("Localizable", "views.migrate.title", fallback: "Migrate")
|
||||
public static let title = Strings.tr("Localizable", "views.migration.title", fallback: "Migrate")
|
||||
public enum Alerts {
|
||||
public enum Delete {
|
||||
/// Do you want to discard these profiles? You will not be able to recover them later.
|
||||
///
|
||||
/// %@
|
||||
public static func message(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "views.migrate.alerts.delete.message", String(describing: p1), fallback: "Do you want to discard these profiles? You will not be able to recover them later.\n\n%@")
|
||||
return Strings.tr("Localizable", "views.migration.alerts.delete.message", String(describing: p1), fallback: "Do you want to discard these profiles? You will not be able to recover them later.\n\n%@")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Items {
|
||||
/// Discard
|
||||
public static let discard = Strings.tr("Localizable", "views.migrate.items.discard", fallback: "Discard")
|
||||
public static let discard = Strings.tr("Localizable", "views.migration.items.discard", fallback: "Discard")
|
||||
/// Proceed
|
||||
public static let migrate = Strings.tr("Localizable", "views.migrate.items.migrate", fallback: "Proceed")
|
||||
public static let migrate = Strings.tr("Localizable", "views.migration.items.migrate", fallback: "Proceed")
|
||||
}
|
||||
public enum Sections {
|
||||
public enum Main {
|
||||
/// Select below the profiles from old versions of %@ that you want to import. In case your profiles are stored on iCloud, they may take a while to synchronize. If you do not see them now, please come back later.
|
||||
public static func header(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "views.migrate.sections.main.header", String(describing: p1), fallback: "Select below the profiles from old versions of %@ that you want to import. In case your profiles are stored on iCloud, they may take a while to synchronize. If you do not see them now, please come back later.")
|
||||
return Strings.tr("Localizable", "views.migration.sections.main.header", String(describing: p1), fallback: "Select below the profiles from old versions of %@ that you want to import. In case your profiles are stored on iCloud, they may take a while to synchronize. If you do not see them now, please come back later.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Paywall {
|
||||
public enum Alerts {
|
||||
public enum Pending {
|
||||
/// The purchase is pending external confirmation. The feature will be credited upon approval.
|
||||
public static let message = Strings.tr("Localizable", "views.paywall.alerts.pending.message", fallback: "The purchase is pending external confirmation. The feature will be credited upon approval.")
|
||||
}
|
||||
public enum Restricted {
|
||||
/// Some features are unavailable in this build.
|
||||
public static let message = Strings.tr("Localizable", "views.paywall.alerts.restricted.message", fallback: "Some features are unavailable in this build.")
|
||||
/// Restricted
|
||||
public static let title = Strings.tr("Localizable", "views.paywall.alerts.restricted.title", fallback: "Restricted")
|
||||
}
|
||||
}
|
||||
public enum Rows {
|
||||
/// Restore purchases
|
||||
public static let restorePurchases = Strings.tr("Localizable", "views.paywall.rows.restore_purchases", fallback: "Restore purchases")
|
||||
}
|
||||
public enum Sections {
|
||||
public enum Features {
|
||||
public enum Other {
|
||||
/// Also included
|
||||
public static let header = Strings.tr("Localizable", "views.paywall.sections.features.other.header", fallback: "Also included")
|
||||
}
|
||||
public enum Required {
|
||||
/// Required features
|
||||
public static let header = Strings.tr("Localizable", "views.paywall.sections.features.required.header", fallback: "Required features")
|
||||
}
|
||||
}
|
||||
public enum OneTime {
|
||||
/// One-time purchase
|
||||
public static let header = Strings.tr("Localizable", "views.paywall.sections.one_time.header", fallback: "One-time purchase")
|
||||
}
|
||||
public enum Recurring {
|
||||
/// All features
|
||||
public static let header = Strings.tr("Localizable", "views.paywall.sections.recurring.header", fallback: "All features")
|
||||
}
|
||||
public enum Restore {
|
||||
/// If you bought this app or feature in the past, you can restore your purchases.
|
||||
public static let footer = Strings.tr("Localizable", "views.paywall.sections.restore.footer", fallback: "If you bought this app or feature in the past, you can restore your purchases.")
|
||||
/// Restore
|
||||
public static let header = Strings.tr("Localizable", "views.paywall.sections.restore.header", fallback: "Restore")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Preferences {
|
||||
/// Erase iCloud store
|
||||
public static let eraseIcloud = Strings.tr("Localizable", "views.preferences.erase_icloud", fallback: "Erase iCloud store")
|
||||
/// Keep in menu bar
|
||||
public static let keepsInMenu = Strings.tr("Localizable", "views.preferences.keeps_in_menu", fallback: "Keep in menu bar")
|
||||
/// Launch on login
|
||||
public static let launchesOnLogin = Strings.tr("Localizable", "views.preferences.launches_on_login", fallback: "Launch on login")
|
||||
/// Lock in background
|
||||
public static let locksInBackground = Strings.tr("Localizable", "views.preferences.locks_in_background", fallback: "Lock in background")
|
||||
public enum EraseIcloud {
|
||||
/// To erase the iCloud store securely, do so on all your synced devices. This will not affect local profiles.
|
||||
public static let footer = Strings.tr("Localizable", "views.preferences.erase_icloud.footer", fallback: "To erase the iCloud store securely, do so on all your synced devices. This will not affect local profiles.")
|
||||
}
|
||||
public enum KeepsInMenu {
|
||||
/// Enable this to keep the app in the menu bar after closing it.
|
||||
public static let footer = Strings.tr("Localizable", "views.preferences.keeps_in_menu.footer", fallback: "Enable this to keep the app in the menu bar after closing it.")
|
||||
}
|
||||
public enum LaunchesOnLogin {
|
||||
/// Open the app in background after login.
|
||||
public static let footer = Strings.tr("Localizable", "views.preferences.launches_on_login.footer", fallback: "Open the app in background after login.")
|
||||
}
|
||||
public enum LocksInBackground {
|
||||
/// Lock the app with FaceID when sent to the background.
|
||||
public static let footer = Strings.tr("Localizable", "views.preferences.locks_in_background.footer", fallback: "Lock the app with FaceID when sent to the background.")
|
||||
}
|
||||
}
|
||||
public enum Profile {
|
||||
public enum Alerts {
|
||||
public enum Purchase {
|
||||
@ -783,76 +793,52 @@ public enum Strings {
|
||||
public static let addModule = Strings.tr("Localizable", "views.profile.rows.add_module", fallback: "Add module")
|
||||
}
|
||||
}
|
||||
public enum Profiles {
|
||||
public enum Errors {
|
||||
/// Unable to duplicate profile '%@'.
|
||||
public static func duplicate(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "views.profiles.errors.duplicate", String(describing: p1), fallback: "Unable to duplicate profile '%@'.")
|
||||
}
|
||||
/// Unable to import profiles.
|
||||
public static let `import` = Strings.tr("Localizable", "views.profiles.errors.import", fallback: "Unable to import profiles.")
|
||||
/// Unable to execute tunnel operation.
|
||||
public static let tunnel = Strings.tr("Localizable", "views.profiles.errors.tunnel", fallback: "Unable to execute tunnel operation.")
|
||||
public enum Providers {
|
||||
/// Clear filters
|
||||
public static let clearFilters = Strings.tr("Localizable", "views.providers.clear_filters", fallback: "Clear filters")
|
||||
/// Last updated on %@
|
||||
public static func lastUpdated(_ p1: Any) -> String {
|
||||
return Strings.tr("Localizable", "views.providers.last_updated", String(describing: p1), fallback: "Last updated on %@")
|
||||
}
|
||||
public enum Folders {
|
||||
/// Installed profile
|
||||
public static let activeProfile = Strings.tr("Localizable", "views.profiles.folders.active_profile", fallback: "Installed profile")
|
||||
/// Add profile
|
||||
public static let addProfile = Strings.tr("Localizable", "views.profiles.folders.add_profile", fallback: "Add profile")
|
||||
/// My profiles
|
||||
public static let `default` = Strings.tr("Localizable", "views.profiles.folders.default", fallback: "My profiles")
|
||||
/// No profiles
|
||||
public static let noProfiles = Strings.tr("Localizable", "views.profiles.folders.no_profiles", fallback: "No profiles")
|
||||
public enum NoProfiles {
|
||||
/// Migrate old profiles...
|
||||
public static let migrate = Strings.tr("Localizable", "views.profiles.folders.no_profiles.migrate", fallback: "Migrate old profiles...")
|
||||
}
|
||||
/// None
|
||||
public static let noProvider = Strings.tr("Localizable", "views.providers.no_provider", fallback: "None")
|
||||
/// Only favorites
|
||||
public static let onlyFavorites = Strings.tr("Localizable", "views.providers.only_favorites", fallback: "Only favorites")
|
||||
/// Refresh infrastructure
|
||||
public static let refreshInfrastructure = Strings.tr("Localizable", "views.providers.refresh_infrastructure", fallback: "Refresh infrastructure")
|
||||
/// Select
|
||||
public static let selectEntity = Strings.tr("Localizable", "views.providers.select_entity", fallback: "Select")
|
||||
/// Select a provider
|
||||
public static let selectProvider = Strings.tr("Localizable", "views.providers.select_provider", fallback: "Select a provider")
|
||||
public enum LastUpdated {
|
||||
/// Loading...
|
||||
public static let loading = Strings.tr("Localizable", "views.providers.last_updated.loading", fallback: "Loading...")
|
||||
}
|
||||
public enum Rows {
|
||||
/// No active modules
|
||||
public static let noModules = Strings.tr("Localizable", "views.profiles.rows.no_modules", fallback: "No active modules")
|
||||
/// Select a profile
|
||||
public static let notInstalled = Strings.tr("Localizable", "views.profiles.rows.not_installed", fallback: "Select a profile")
|
||||
}
|
||||
public enum Toolbar {
|
||||
/// Import profile
|
||||
public static let importProfile = Strings.tr("Localizable", "views.profiles.toolbar.import_profile", fallback: "Import profile")
|
||||
/// Migrate profiles
|
||||
public static let migrateProfiles = Strings.tr("Localizable", "views.profiles.toolbar.migrate_profiles", fallback: "Migrate profiles")
|
||||
/// New profile
|
||||
public static let newProfile = Strings.tr("Localizable", "views.profiles.toolbar.new_profile", fallback: "New profile")
|
||||
}
|
||||
public enum Tv {
|
||||
/// Open %@ on your iOS or macOS device and enable the "%@" toggle of a profile to make it appear here.
|
||||
public static func header(_ p1: Any, _ p2: Any) -> String {
|
||||
return Strings.tr("Localizable", "views.profiles.tv.header", String(describing: p1), String(describing: p2), fallback: "Open %@ on your iOS or macOS device and enable the \"%@\" toggle of a profile to make it appear here.")
|
||||
public enum Vpn {
|
||||
/// No servers
|
||||
public static let noServers = Strings.tr("Localizable", "views.providers.vpn.no_servers", fallback: "No servers")
|
||||
/// Preset
|
||||
public static let preset = Strings.tr("Localizable", "views.providers.vpn.preset", fallback: "Preset")
|
||||
public enum Category {
|
||||
/// All categories
|
||||
public static let any = Strings.tr("Localizable", "views.providers.vpn.category.any", fallback: "All categories")
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum Settings {
|
||||
/// Erase iCloud store
|
||||
public static let eraseIcloud = Strings.tr("Localizable", "views.settings.erase_icloud", fallback: "Erase iCloud store")
|
||||
/// Keep in menu bar
|
||||
public static let keepsInMenu = Strings.tr("Localizable", "views.settings.keeps_in_menu", fallback: "Keep in menu bar")
|
||||
/// Launch on login
|
||||
public static let launchesOnLogin = Strings.tr("Localizable", "views.settings.launches_on_login", fallback: "Launch on login")
|
||||
/// Lock in background
|
||||
public static let locksInBackground = Strings.tr("Localizable", "views.settings.locks_in_background", fallback: "Lock in background")
|
||||
public enum EraseIcloud {
|
||||
/// To erase the iCloud store securely, do so on all your synced devices. This will not affect local profiles.
|
||||
public static let footer = Strings.tr("Localizable", "views.settings.erase_icloud.footer", fallback: "To erase the iCloud store securely, do so on all your synced devices. This will not affect local profiles.")
|
||||
public enum Ui {
|
||||
public enum ConnectionStatus {
|
||||
/// (on-demand)
|
||||
public static let onDemandSuffix = Strings.tr("Localizable", "views.ui.connection_status.on_demand_suffix", fallback: " (on-demand)")
|
||||
}
|
||||
public enum KeepsInMenu {
|
||||
/// Enable this to keep the app in the menu bar after closing it.
|
||||
public static let footer = Strings.tr("Localizable", "views.settings.keeps_in_menu.footer", fallback: "Enable this to keep the app in the menu bar after closing it.")
|
||||
}
|
||||
public enum LaunchesOnLogin {
|
||||
/// Open the app in background after login.
|
||||
public static let footer = Strings.tr("Localizable", "views.settings.launches_on_login.footer", fallback: "Open the app in background after login.")
|
||||
}
|
||||
public enum LocksInBackground {
|
||||
/// Lock the app with FaceID when sent to the background.
|
||||
public static let footer = Strings.tr("Localizable", "views.settings.locks_in_background.footer", fallback: "Lock the app with FaceID when sent to the background.")
|
||||
public enum PurchaseRequired {
|
||||
public enum Purchase {
|
||||
/// Purchase required
|
||||
public static let help = Strings.tr("Localizable", "views.ui.purchase_required.purchase.help", fallback: "Purchase required")
|
||||
}
|
||||
public enum Restricted {
|
||||
/// Feature is restricted
|
||||
public static let help = Strings.tr("Localizable", "views.ui.purchase_required.restricted.help", fallback: "Feature is restricted")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,154 +1,7 @@
|
||||
// MARK: Global
|
||||
|
||||
"global.about" = "About";
|
||||
"global.account" = "Account";
|
||||
"global.address" = "Address";
|
||||
"global.addresses" = "Addresses";
|
||||
"global.any" = "Any";
|
||||
"global.cancel" = "Cancel";
|
||||
"global.category" = "Category";
|
||||
"global.certificate" = "Certificate";
|
||||
"global.compression" = "Compression";
|
||||
"global.connect" = "Connect";
|
||||
"global.connection" = "Connection";
|
||||
"global.country" = "Country";
|
||||
"global.default" = "Default";
|
||||
"global.delete" = "Delete";
|
||||
"global.destination" = "Destination";
|
||||
"global.disable" = "Disable";
|
||||
"global.disabled" = "Disabled";
|
||||
"global.disconnect" = "Disconnect";
|
||||
"global.domain" = "Domain";
|
||||
"global.done" = "Done";
|
||||
"global.do_not_ask_again" = "Don't ask again";
|
||||
"global.duplicate" = "Duplicate";
|
||||
"global.edit" = "Edit";
|
||||
"global.empty" = "Empty";
|
||||
"global.enable" = "Enable";
|
||||
"global.enabled" = "Enabled";
|
||||
"global.endpoint" = "Endpoint";
|
||||
"global.filters" = "Filters";
|
||||
"global.folder" = "Folder";
|
||||
"global.gateway" = "Gateway";
|
||||
"global.general" = "General";
|
||||
"global.hide" = "Hide";
|
||||
"global.hostname" = "Hostname";
|
||||
"global.interface" = "Interface";
|
||||
"global.keep_alive" = "Keep-alive";
|
||||
"global.key" = "Key";
|
||||
"global.last_update" = "Last update";
|
||||
"global.loading" = "Loading";
|
||||
"global.method" = "Method";
|
||||
"global.modules" = "Modules";
|
||||
"global.n_seconds" = "%d seconds";
|
||||
"global.name" = "Name";
|
||||
"global.networks" = "Networks";
|
||||
"global.no_content" = "No content";
|
||||
"global.no_selection" = "No selection";
|
||||
"global.none" = "None";
|
||||
"global.ok" = "OK";
|
||||
"global.on_demand" = "On-demand";
|
||||
"global.other" = "Other";
|
||||
"global.password" = "Password";
|
||||
"global.port" = "Port";
|
||||
"global.private_key" = "Private key";
|
||||
"global.profile" = "Profile";
|
||||
"global.protocol" = "Protocol";
|
||||
"global.provider" = "Provider";
|
||||
"global.public_key" = "Public key";
|
||||
"global.purchase" = "Purchase";
|
||||
"global.region" = "Region";
|
||||
"global.remove" = "Delete";
|
||||
"global.restart" = "Restart";
|
||||
"global.route" = "Route";
|
||||
"global.routes" = "Routes";
|
||||
"global.routing" = "Routing";
|
||||
"global.save" = "Save";
|
||||
"global.select" = "Select";
|
||||
"global.server" = "Server";
|
||||
"global.servers" = "Servers";
|
||||
"global.settings" = "Settings";
|
||||
"global.show" = "Show";
|
||||
"global.status" = "Status";
|
||||
"global.subnet" = "Subnet";
|
||||
"global.unknown" = "Unknown";
|
||||
"global.username" = "Username";
|
||||
"global.version" = "Version";
|
||||
|
||||
// MARK: - Entities
|
||||
|
||||
"entities.dns.servers" = "Servers";
|
||||
"entities.dns.search_domains" = "Search domains";
|
||||
|
||||
"entities.dns_protocol.cleartext" = "Cleartext";
|
||||
"entities.dns_protocol.https" = "Over HTTPS";
|
||||
"entities.dns_protocol.tls" = "Over TLS";
|
||||
|
||||
"entities.http_proxy.bypass_domains" = "Bypass domains";
|
||||
|
||||
"entities.on_demand.policy.any" = "All networks";
|
||||
"entities.on_demand.policy.excluding" = "Excluding";
|
||||
"entities.on_demand.policy.including" = "Including";
|
||||
|
||||
"entities.openvpn.compression_algorithm.other" = "Unsupported";
|
||||
"entities.openvpn.otp_method.none" = "None";
|
||||
"entities.openvpn.otp_method.append" = "Append";
|
||||
"entities.openvpn.otp_method.encode" = "Encode";
|
||||
|
||||
"entities.profile.name.new" = "New profile";
|
||||
|
||||
"entities.tunnel_status.inactive" = "Inactive";
|
||||
"entities.tunnel_status.activating" = "Activating";
|
||||
"entities.tunnel_status.active" = "Active";
|
||||
"entities.tunnel_status.deactivating" = "Deactivating";
|
||||
|
||||
"entities.connection_status.disconnected" = "Disconnected";
|
||||
"entities.connection_status.connecting" = "Connecting";
|
||||
"entities.connection_status.connected" = "Connected";
|
||||
"entities.connection_status.disconnecting" = "Disconnecting";
|
||||
|
||||
// MARK: - Entity placeholders
|
||||
|
||||
"placeholders.profile.name" = "My profile";
|
||||
"placeholders.on_demand.ssid" = "My SSID";
|
||||
"placeholders.username" = "username";
|
||||
"placeholders.secret" = "secret";
|
||||
|
||||
// MARK: - Views
|
||||
|
||||
"views.profiles.rows.not_installed" = "Select a profile";
|
||||
"views.profiles.rows.no_modules" = "No active modules";
|
||||
"views.profiles.folders.active_profile" = "Installed profile";
|
||||
"views.profiles.folders.default" = "My profiles";
|
||||
"views.profiles.folders.add_profile" = "Add profile";
|
||||
"views.profiles.folders.no_profiles" = "No profiles";
|
||||
"views.profiles.folders.no_profiles.migrate" = "Migrate old profiles...";
|
||||
"views.profiles.toolbar.new_profile" = "New profile";
|
||||
"views.profiles.toolbar.import_profile" = "Import profile";
|
||||
"views.profiles.toolbar.migrate_profiles" = "Migrate profiles";
|
||||
"views.profiles.tv.header" = "Open %@ on your iOS or macOS device and enable the \"%@\" toggle of a profile to make it appear here.";
|
||||
"views.profiles.errors.tunnel" = "Unable to execute tunnel operation.";
|
||||
"views.profiles.errors.duplicate" = "Unable to duplicate profile '%@'.";
|
||||
"views.profiles.errors.import" = "Unable to import profiles.";
|
||||
|
||||
"views.profile.rows.add_module" = "Add module";
|
||||
"views.profile.module_list.section.footer" = "Drag modules to rearrange them, as their order determines priority.";
|
||||
"views.profile.alerts.purchase.title" = "Purchase required";
|
||||
"views.profile.alerts.purchase.buttons.ok" = "Save anyway";
|
||||
"views.profile.alerts.purchase.message" = "This profile requires paid features to work.";
|
||||
|
||||
"views.settings.launches_on_login" = "Launch on login";
|
||||
"views.settings.launches_on_login.footer" = "Open the app in background after login.";
|
||||
"views.settings.keeps_in_menu" = "Keep in menu bar";
|
||||
"views.settings.keeps_in_menu.footer" = "Enable this to keep the app in the menu bar after closing it.";
|
||||
"views.settings.locks_in_background" = "Lock in background";
|
||||
"views.settings.locks_in_background.footer" = "Lock the app with FaceID when sent to the background.";
|
||||
"views.settings.erase_icloud" = "Erase iCloud store";
|
||||
"views.settings.erase_icloud.footer" = "To erase the iCloud store securely, do so on all your synced devices. This will not affect local profiles.";
|
||||
// MARK: Views
|
||||
|
||||
"views.about.title" = "About";
|
||||
"views.about.sections.resources" = "Resources";
|
||||
|
||||
"views.about.links.title" = "Links";
|
||||
"views.about.links.sections.support" = "Support";
|
||||
"views.about.links.sections.web" = "Web";
|
||||
@ -157,22 +10,29 @@
|
||||
"views.about.links.rows.home_page" = "Home page";
|
||||
"views.about.links.rows.disclaimer" = "Disclaimer";
|
||||
"views.about.links.rows.privacy_policy" = "Privacy policy";
|
||||
|
||||
"views.about.credits.title" = "Credits";
|
||||
"views.about.credits.licenses" = "Licenses";
|
||||
"views.about.credits.notices" = "Notices";
|
||||
"views.about.credits.translations" = "Translations";
|
||||
|
||||
"views.migrate.title" = "Migrate";
|
||||
"views.migrate.no_profiles" = "Nothing to migrate";
|
||||
"views.migrate.items.discard" = "Discard";
|
||||
"views.migrate.items.migrate" = "Proceed";
|
||||
"views.migrate.sections.main.header" = "Select below the profiles from old versions of %@ that you want to import. In case your profiles are stored on iCloud, they may take a while to synchronize. If you do not see them now, please come back later.";
|
||||
"views.migrate.alerts.delete.message" = "Do you want to discard these profiles? You will not be able to recover them later.\n\n%@";
|
||||
"views.app.rows.not_installed" = "Select a profile";
|
||||
"views.app.rows.no_modules" = "No active modules";
|
||||
"views.app.folders.active_profile" = "Installed profile";
|
||||
"views.app.folders.default" = "My profiles";
|
||||
"views.app.folders.add_profile" = "Add profile";
|
||||
"views.app.folders.no_profiles" = "No profiles";
|
||||
"views.app.folders.no_profiles.migrate" = "Migrate old profiles...";
|
||||
"views.app.toolbar.new_profile" = "New profile";
|
||||
"views.app.toolbar.import_profile" = "Import profile";
|
||||
"views.app.toolbar.migrate_profiles" = "Migrate profiles";
|
||||
"views.app.tv.header" = "Open %@ on your iOS or macOS device and enable the \"%@\" toggle of a profile to make it appear here.";
|
||||
"views.app.errors.tunnel" = "Unable to execute tunnel operation.";
|
||||
"views.app.errors.duplicate" = "Unable to duplicate profile '%@'.";
|
||||
"views.app.errors.import" = "Unable to import profiles.";
|
||||
|
||||
"views.donate.title" = "Make a donation";
|
||||
"views.donate.sections.main.footer" = "If you want to display gratitude for my work, here are a couple amounts you can donate instantly.\n\nYou will only be charged once per donation, and you can donate multiple times.";
|
||||
"views.donate.alerts.thank_you.message" = "This means a lot to me and I really hope you keep using and promoting this app.";
|
||||
"views.app.profile_context.connect_to" = "Connect to...";
|
||||
|
||||
"views.app_menu.items.quit" = "Quit %@";
|
||||
|
||||
"views.diagnostics.title" = "Diagnostics";
|
||||
"views.diagnostics.sections.live" = "Live log";
|
||||
@ -181,18 +41,73 @@
|
||||
"views.diagnostics.rows.tunnel" = "Tunnel";
|
||||
"views.diagnostics.rows.include_private_data" = "Include private data";
|
||||
"views.diagnostics.rows.remove_tunnel_logs" = "Delete all logs";
|
||||
|
||||
"views.diagnostics.openvpn.rows.server_configuration" = "Server configuration";
|
||||
|
||||
"views.diagnostics.report_issue.title" = "Report issue";
|
||||
"views.diagnostics.alerts.report_issue.email" = "The device is not configured to send e-mails.";
|
||||
|
||||
// MARK: - Module views
|
||||
"views.donate.title" = "Make a donation";
|
||||
"views.donate.sections.main.footer" = "If you want to display gratitude for my work, here are a couple amounts you can donate instantly.\n\nYou will only be charged once per donation, and you can donate multiple times.";
|
||||
"views.donate.alerts.thank_you.message" = "This means a lot to me and I really hope you keep using and promoting this app.";
|
||||
|
||||
"views.migration.title" = "Migrate";
|
||||
"views.migration.no_profiles" = "Nothing to migrate";
|
||||
"views.migration.items.discard" = "Discard";
|
||||
"views.migration.items.migrate" = "Proceed";
|
||||
"views.migration.sections.main.header" = "Select below the profiles from old versions of %@ that you want to import. In case your profiles are stored on iCloud, they may take a while to synchronize. If you do not see them now, please come back later.";
|
||||
"views.migration.alerts.delete.message" = "Do you want to discard these profiles? You will not be able to recover them later.\n\n%@";
|
||||
|
||||
"views.paywall.sections.recurring.header" = "All features";
|
||||
"views.paywall.sections.one_time.header" = "One-time purchase";
|
||||
"views.paywall.sections.features.required.header" = "Required features";
|
||||
"views.paywall.sections.features.other.header" = "Also included";
|
||||
"views.paywall.sections.restore.header" = "Restore";
|
||||
"views.paywall.sections.restore.footer" = "If you bought this app or feature in the past, you can restore your purchases.";
|
||||
"views.paywall.rows.restore_purchases" = "Restore purchases";
|
||||
"views.paywall.alerts.restricted.title" = "Restricted";
|
||||
"views.paywall.alerts.restricted.message" = "Some features are unavailable in this build.";
|
||||
"views.paywall.alerts.pending.message" = "The purchase is pending external confirmation. The feature will be credited upon approval.";
|
||||
|
||||
"views.preferences.launches_on_login" = "Launch on login";
|
||||
"views.preferences.launches_on_login.footer" = "Open the app in background after login.";
|
||||
"views.preferences.keeps_in_menu" = "Keep in menu bar";
|
||||
"views.preferences.keeps_in_menu.footer" = "Enable this to keep the app in the menu bar after closing it.";
|
||||
"views.preferences.locks_in_background" = "Lock in background";
|
||||
"views.preferences.locks_in_background.footer" = "Lock the app with FaceID when sent to the background.";
|
||||
"views.preferences.erase_icloud" = "Erase iCloud store";
|
||||
"views.preferences.erase_icloud.footer" = "To erase the iCloud store securely, do so on all your synced devices. This will not affect local profiles.";
|
||||
|
||||
"views.profile.rows.add_module" = "Add module";
|
||||
"views.profile.module_list.section.footer" = "Drag modules to rearrange them, as their order determines priority.";
|
||||
"views.profile.alerts.purchase.title" = "Purchase required";
|
||||
"views.profile.alerts.purchase.buttons.ok" = "Save anyway";
|
||||
"views.profile.alerts.purchase.message" = "This profile requires paid features to work.";
|
||||
|
||||
"views.providers.no_provider" = "None";
|
||||
"views.providers.select_provider" = "Select a provider";
|
||||
"views.providers.select_entity" = "Select";
|
||||
"views.providers.only_favorites" = "Only favorites";
|
||||
"views.providers.clear_filters" = "Clear filters";
|
||||
"views.providers.refresh_infrastructure" = "Refresh infrastructure";
|
||||
"views.providers.last_updated" = "Last updated on %@";
|
||||
"views.providers.last_updated.loading" = "Loading...";
|
||||
"views.providers.vpn.category.any" = "All categories";
|
||||
"views.providers.vpn.preset" = "Preset";
|
||||
"views.providers.vpn.no_servers" = "No servers";
|
||||
|
||||
"views.ui.connection_status.on_demand_suffix" = " (on-demand)";
|
||||
"views.ui.purchase_required.purchase.help" = "Purchase required";
|
||||
"views.ui.purchase_required.restricted.help" = "Feature is restricted";
|
||||
|
||||
// MARK: Views (Modules)
|
||||
|
||||
"modules.general.sections.storage.header" = "%@";
|
||||
"modules.general.sections.storage.footer" = "Profiles are stored to %@ encrypted.";
|
||||
"modules.general.sections.storage.footer.purchase.tv_beta" = "TV profiles do not work in beta builds.";
|
||||
"modules.general.sections.storage.footer.purchase.tv_release" = "TV profiles do not work without a purchase.";
|
||||
"modules.general.rows.shared" = "Enabled";
|
||||
"modules.general.rows.apple_tv" = "%@";
|
||||
"modules.general.rows.shared.purchase" = "Share on iCloud";
|
||||
"modules.general.rows.appletv" = "%@";
|
||||
"modules.general.rows.appletv.purchase" = "Drop TV restriction";
|
||||
"modules.general.rows.import_from_file" = "Import from file...";
|
||||
|
||||
"modules.dns.servers.add" = "Add address";
|
||||
@ -240,78 +155,148 @@
|
||||
"modules.wireguard.preshared_key" = "Pre-shared key";
|
||||
"modules.wireguard.allowed_ips" = "Allowed IPs";
|
||||
|
||||
// MARK: - Providers
|
||||
// MARK: - Entities
|
||||
|
||||
"providers.no_provider" = "None";
|
||||
"providers.select_provider" = "Select a provider";
|
||||
"providers.select_entity" = "Select";
|
||||
"providers.only_favorites" = "Only favorites";
|
||||
"providers.clear_filters" = "Clear filters";
|
||||
"providers.refresh_infrastructure" = "Refresh infrastructure";
|
||||
"providers.last_updated" = "Last updated on %@";
|
||||
"providers.last_updated.loading" = "Loading...";
|
||||
"providers.vpn.category.any" = "All categories";
|
||||
"providers.vpn.preset" = "Preset";
|
||||
"providers.vpn.no_servers" = "No servers";
|
||||
"entities.tunnel_status.inactive" = "Inactive";
|
||||
"entities.tunnel_status.activating" = "Activating";
|
||||
"entities.tunnel_status.active" = "Active";
|
||||
"entities.tunnel_status.deactivating" = "Deactivating";
|
||||
|
||||
// MARK: - App menu
|
||||
// MARK: Entities (Modules)
|
||||
|
||||
"app_menu.items.quit" = "Quit %@";
|
||||
"entities.dns.servers" = "Servers";
|
||||
"entities.dns.search_domains" = "Search domains";
|
||||
|
||||
// MARK: - Theme
|
||||
"entities.dns_protocol.cleartext" = "Cleartext";
|
||||
"entities.dns_protocol.https" = "Over HTTPS";
|
||||
"entities.dns_protocol.tls" = "Over TLS";
|
||||
|
||||
"theme.confirmation.ok" = "Confirm";
|
||||
"theme.confirmation.cancel" = "Cancel";
|
||||
"theme.confirmation.message" = "Are you sure you want to proceed with this operation?";
|
||||
"theme.lock_screen.reason" = "%@ is locked";
|
||||
"entities.http_proxy.bypass_domains" = "Bypass domains";
|
||||
|
||||
// MARK: - Components
|
||||
"entities.on_demand.policy.any" = "All networks";
|
||||
"entities.on_demand.policy.excluding" = "Excluding";
|
||||
"entities.on_demand.policy.including" = "Including";
|
||||
|
||||
"ui.connection_status.on_demand_suffix" = " (on-demand)";
|
||||
"ui.profile_context.connect_to" = "Connect to...";
|
||||
"ui.purchase_required.purchase.help" = "Purchase required";
|
||||
"ui.purchase_required.restricted.help" = "Feature is restricted";
|
||||
"entities.openvpn.compression_algorithm.other" = "Unsupported";
|
||||
"entities.openvpn.otp_method.none" = "None";
|
||||
"entities.openvpn.otp_method.append" = "Append";
|
||||
"entities.openvpn.otp_method.encode" = "Encode";
|
||||
|
||||
// MARK: - Paywall
|
||||
// MARK: - Features
|
||||
|
||||
"paywall.sections.recurring.header" = "All features";
|
||||
"paywall.sections.one_time.header" = "One-time purchase";
|
||||
"paywall.sections.features.required.header" = "Required features";
|
||||
"paywall.sections.features.other.header" = "Also included";
|
||||
"paywall.sections.restore.header" = "Restore";
|
||||
"paywall.sections.restore.footer" = "If you bought this app or feature in the past, you can restore your purchases.";
|
||||
"paywall.rows.restore_purchases" = "Restore purchases";
|
||||
"paywall.alerts.pending.message" = "The purchase is pending external confirmation. The feature will be credited upon approval.";
|
||||
|
||||
"features.appleTV" = "%@";
|
||||
"features.appletv" = "%@";
|
||||
"features.dns" = "%@ Settings";
|
||||
"features.httpProxy" = "%@ Settings";
|
||||
"features.http_proxy" = "%@ Settings";
|
||||
"features.interactiveLogin" = "Interactive Login";
|
||||
"features.onDemand" = "On-Demand Rules";
|
||||
"features.on_demand" = "On-Demand Rules";
|
||||
"features.providers" = "All Providers";
|
||||
"features.routing" = "Custom %@";
|
||||
"features.sharing" = "%@";
|
||||
|
||||
"modules.general.sections.storage.footer.purchase.tv_beta" = "TV profiles do not work in beta builds.";
|
||||
"modules.general.sections.storage.footer.purchase.tv_release" = "TV profiles do not work without a purchase.";
|
||||
"modules.general.rows.shared.purchase" = "Share on iCloud";
|
||||
"modules.general.rows.apple_tv.purchase" = "Drop TV restriction";
|
||||
// MARK: - Global
|
||||
|
||||
// MARK: - Alerts
|
||||
// MARK: Global (Actions)
|
||||
|
||||
"global.actions.cancel" = "Cancel";
|
||||
"global.actions.connect" = "Connect";
|
||||
"global.actions.delete" = "Delete";
|
||||
"global.actions.disable" = "Disable";
|
||||
"global.actions.disconnect" = "Disconnect";
|
||||
"global.actions.duplicate" = "Duplicate";
|
||||
"global.actions.edit" = "Edit";
|
||||
"global.actions.enable" = "Enable";
|
||||
"global.actions.hide" = "Hide";
|
||||
"global.actions.purchase" = "Purchase";
|
||||
"global.actions.remove" = "Delete";
|
||||
"global.actions.restart" = "Restart";
|
||||
"global.actions.save" = "Save";
|
||||
"global.actions.select" = "Select";
|
||||
"global.actions.show" = "Show";
|
||||
|
||||
// MARK: Global (Nouns)
|
||||
|
||||
"global.nouns.about" = "About";
|
||||
"global.nouns.account" = "Account";
|
||||
"global.nouns.address" = "Address";
|
||||
"global.nouns.addresses" = "Addresses";
|
||||
"global.nouns.any" = "Any";
|
||||
"global.nouns.category" = "Category";
|
||||
"global.nouns.certificate" = "Certificate";
|
||||
"global.nouns.compression" = "Compression";
|
||||
"global.nouns.connection" = "Connection";
|
||||
"global.nouns.country" = "Country";
|
||||
"global.nouns.default" = "Default";
|
||||
"global.nouns.destination" = "Destination";
|
||||
"global.nouns.disabled" = "Disabled";
|
||||
"global.nouns.domain" = "Domain";
|
||||
"global.nouns.done" = "Done";
|
||||
"global.nouns.do_not_ask_again" = "Don't ask again";
|
||||
"global.nouns.empty" = "Empty";
|
||||
"global.nouns.enabled" = "Enabled";
|
||||
"global.nouns.endpoint" = "Endpoint";
|
||||
"global.nouns.filters" = "Filters";
|
||||
"global.nouns.folder" = "Folder";
|
||||
"global.nouns.gateway" = "Gateway";
|
||||
"global.nouns.general" = "General";
|
||||
"global.nouns.hostname" = "Hostname";
|
||||
"global.nouns.interface" = "Interface";
|
||||
"global.nouns.keep_alive" = "Keep-alive";
|
||||
"global.nouns.key" = "Key";
|
||||
"global.nouns.last_update" = "Last update";
|
||||
"global.nouns.loading" = "Loading";
|
||||
"global.nouns.method" = "Method";
|
||||
"global.nouns.modules" = "Modules";
|
||||
"global.nouns.n_seconds" = "%d seconds";
|
||||
"global.nouns.name" = "Name";
|
||||
"global.nouns.networks" = "Networks";
|
||||
"global.nouns.no_content" = "No content";
|
||||
"global.nouns.no_selection" = "No selection";
|
||||
"global.nouns.none" = "None";
|
||||
"global.nouns.ok" = "OK";
|
||||
"global.nouns.on_demand" = "On-demand";
|
||||
"global.nouns.other" = "Other";
|
||||
"global.nouns.password" = "Password";
|
||||
"global.nouns.port" = "Port";
|
||||
"global.nouns.private_key" = "Private key";
|
||||
"global.nouns.profile" = "Profile";
|
||||
"global.nouns.protocol" = "Protocol";
|
||||
"global.nouns.provider" = "Provider";
|
||||
"global.nouns.public_key" = "Public key";
|
||||
"global.nouns.region" = "Region";
|
||||
"global.nouns.route" = "Route";
|
||||
"global.nouns.routes" = "Routes";
|
||||
"global.nouns.routing" = "Routing";
|
||||
"global.nouns.server" = "Server";
|
||||
"global.nouns.servers" = "Servers";
|
||||
"global.nouns.settings" = "Settings";
|
||||
"global.nouns.status" = "Status";
|
||||
"global.nouns.subnet" = "Subnet";
|
||||
"global.nouns.unknown" = "Unknown";
|
||||
"global.nouns.username" = "Username";
|
||||
"global.nouns.version" = "Version";
|
||||
|
||||
// MARK: Global (Placeholders)
|
||||
|
||||
"placeholders.profile.name" = "My profile";
|
||||
"placeholders.on_demand.ssid" = "My SSID";
|
||||
"placeholders.username" = "username";
|
||||
"placeholders.secret" = "secret";
|
||||
|
||||
// MARK: Global (Alerts)
|
||||
|
||||
"alerts.import.passphrase.message" = "Enter passphrase for '%@'.";
|
||||
"alerts.import.passphrase.ok" = "Decrypt";
|
||||
|
||||
"alerts.iap.restricted.title" = "Restricted";
|
||||
"alerts.iap.restricted.message" = "Some features are unavailable in this build.";
|
||||
|
||||
// MARK: - Errors
|
||||
// MARK: Global (App errors)
|
||||
|
||||
"errors.app.default" = "Unable to complete operation.";
|
||||
"errors.app.empty_products" = "Unable to fetch products, please retry later.";
|
||||
"errors.app.empty_profile_name" = "Profile name is empty.";
|
||||
"errors.app.malformed_module" = "Module %@ is malformed. %@";
|
||||
"errors.app.provider.required" = "No provider selected.";
|
||||
"errors.app.default" = "Unable to complete operation.";
|
||||
|
||||
// MARK: Global (PassepartoutKit errors)
|
||||
|
||||
"errors.app.passepartout.connection_module_required" = "Routing module can only be enabled together with a connection.";
|
||||
"errors.app.passepartout.corrupt_provider_module" = "Unable to connect to provider server (reason=%@).";
|
||||
"errors.app.passepartout.incompatible_modules" = "Some active modules are incompatible, try to only activate one of them.";
|
||||
@ -332,3 +317,10 @@
|
||||
"errors.tunnel.timeout" = "Timeout";
|
||||
"errors.tunnel.tls" = "TLS failed";
|
||||
"errors.tunnel.generic" = "Failed";
|
||||
|
||||
// MARK: Global (Theme)
|
||||
|
||||
"theme.confirmation.ok" = "Confirm";
|
||||
"theme.confirmation.cancel" = "Cancel";
|
||||
"theme.confirmation.message" = "Are you sure you want to proceed with this operation?";
|
||||
"theme.lock_screen.reason" = "%@ is locked";
|
||||
|
@ -99,7 +99,7 @@ public struct ThemeCloseLabel: View {
|
||||
#if os(iOS) || os(tvOS)
|
||||
ThemeImage(.close)
|
||||
#else
|
||||
Text(Strings.Global.cancel)
|
||||
Text(Strings.Global.Actions.cancel)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ private extension DonateView {
|
||||
}
|
||||
|
||||
func thankYouActions() -> some View {
|
||||
Button(Strings.Global.ok) {
|
||||
Button(Strings.Global.Nouns.ok) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public struct DebugLogView<Content>: View where Content: View {
|
||||
|
||||
public var body: some View {
|
||||
content(currentLines)
|
||||
.themeEmpty(if: currentLines.isEmpty, message: Strings.Global.noContent)
|
||||
.themeEmpty(if: currentLines.isEmpty, message: Strings.Global.Nouns.noContent)
|
||||
.toolbar(content: toolbarContent)
|
||||
.task {
|
||||
currentLines = await fetchLines()
|
||||
|
@ -172,13 +172,13 @@ private extension OpenVPNCredentialsView {
|
||||
}
|
||||
|
||||
var usernameField: some View {
|
||||
ThemeTextField(Strings.Global.username, text: $builder.username, placeholder: Strings.Placeholders.username)
|
||||
ThemeTextField(Strings.Global.Nouns.username, text: $builder.username, placeholder: Strings.Placeholders.username)
|
||||
.textContentType(.username)
|
||||
.focused($focusedField, equals: .username)
|
||||
}
|
||||
|
||||
var passwordField: some View {
|
||||
ThemeSecureField(title: Strings.Global.password, text: $builder.password, placeholder: Strings.Placeholders.secret)
|
||||
ThemeSecureField(title: Strings.Global.Nouns.password, text: $builder.password, placeholder: Strings.Placeholders.secret)
|
||||
.textContentType(.password)
|
||||
.focused($focusedField, equals: .password)
|
||||
.onSubmit {
|
||||
|
@ -63,7 +63,7 @@ struct PaywallView: View {
|
||||
.themeProgress(if: isFetchingProducts)
|
||||
.toolbar(content: toolbarContent)
|
||||
.alert(
|
||||
Strings.Global.purchase,
|
||||
Strings.Global.Actions.purchase,
|
||||
isPresented: $isPurchasePendingConfirmation,
|
||||
actions: pendingActions,
|
||||
message: pendingMessage
|
||||
@ -77,7 +77,7 @@ struct PaywallView: View {
|
||||
|
||||
private extension PaywallView {
|
||||
var title: String {
|
||||
Strings.Global.purchase
|
||||
Strings.Global.Actions.purchase
|
||||
}
|
||||
|
||||
var paywallView: some View {
|
||||
@ -108,7 +108,7 @@ private extension PaywallView {
|
||||
onComplete: onComplete,
|
||||
onError: onError
|
||||
)
|
||||
.themeSection(header: Strings.Paywall.Sections.OneTime.header)
|
||||
.themeSection(header: Strings.Views.Paywall.Sections.OneTime.header)
|
||||
}
|
||||
ForEach(recurringProducts, id: \.productIdentifier) {
|
||||
PaywallProductView(
|
||||
@ -120,13 +120,13 @@ private extension PaywallView {
|
||||
onError: onError
|
||||
)
|
||||
}
|
||||
.themeSection(header: Strings.Paywall.Sections.Recurring.header)
|
||||
.themeSection(header: Strings.Views.Paywall.Sections.Recurring.header)
|
||||
}
|
||||
|
||||
var requiredFeaturesView: some View {
|
||||
FeatureListView(
|
||||
style: .list,
|
||||
header: Strings.Paywall.Sections.Features.Required.header,
|
||||
header: Strings.Views.Paywall.Sections.Features.Required.header,
|
||||
features: Array(features)
|
||||
) {
|
||||
Text($0.localizedDescription)
|
||||
@ -137,7 +137,7 @@ private extension PaywallView {
|
||||
var otherFeaturesView: some View {
|
||||
FeatureListView(
|
||||
style: otherFeaturesStyle,
|
||||
header: Strings.Paywall.Sections.Features.Other.header,
|
||||
header: Strings.Views.Paywall.Sections.Features.Other.header,
|
||||
features: otherFeatures
|
||||
) {
|
||||
Text($0.localizedDescription)
|
||||
@ -155,8 +155,8 @@ private extension PaywallView {
|
||||
var restoreView: some View {
|
||||
RestorePurchasesButton(errorHandler: errorHandler)
|
||||
.themeSectionWithSingleRow(
|
||||
header: Strings.Paywall.Sections.Restore.header,
|
||||
footer: Strings.Paywall.Sections.Restore.footer,
|
||||
header: Strings.Views.Paywall.Sections.Restore.header,
|
||||
footer: Strings.Views.Paywall.Sections.Restore.footer,
|
||||
above: true
|
||||
)
|
||||
}
|
||||
@ -176,13 +176,13 @@ private extension PaywallView {
|
||||
}
|
||||
|
||||
func pendingActions() -> some View {
|
||||
Button(Strings.Global.ok) {
|
||||
Button(Strings.Global.Nouns.ok) {
|
||||
isPresented = false
|
||||
}
|
||||
}
|
||||
|
||||
func pendingMessage() -> some View {
|
||||
Text(Strings.Paywall.Alerts.Pending.message)
|
||||
Text(Strings.Views.Paywall.Alerts.Pending.message)
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,7 +245,7 @@ private extension PaywallView {
|
||||
}
|
||||
|
||||
func onError(_ error: Error, dismissing: Bool) {
|
||||
errorHandler.handle(error, title: Strings.Global.purchase) {
|
||||
errorHandler.handle(error, title: Strings.Global.Actions.purchase) {
|
||||
if dismissing {
|
||||
isPresented = false
|
||||
}
|
||||
|
@ -54,6 +54,6 @@ public struct RestorePurchasesButton: View {
|
||||
|
||||
private extension RestorePurchasesButton {
|
||||
var title: String {
|
||||
Strings.Paywall.Rows.restorePurchases
|
||||
Strings.Views.Paywall.Rows.restorePurchases
|
||||
}
|
||||
}
|
||||
|
@ -64,27 +64,27 @@ public struct PreferencesGroup: View {
|
||||
private extension PreferencesGroup {
|
||||
#if os(iOS)
|
||||
var lockInBackgroundToggle: some View {
|
||||
Toggle(Strings.Views.Settings.locksInBackground, isOn: $locksInBackground)
|
||||
.themeSectionWithSingleRow(footer: Strings.Views.Settings.LocksInBackground.footer)
|
||||
Toggle(Strings.Views.Preferences.locksInBackground, isOn: $locksInBackground)
|
||||
.themeSectionWithSingleRow(footer: Strings.Views.Preferences.LocksInBackground.footer)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
var launchesOnLoginToggle: some View {
|
||||
Toggle(Strings.Views.Settings.launchesOnLogin, isOn: $settings.launchesOnLogin)
|
||||
.themeSectionWithSingleRow(footer: Strings.Views.Settings.LaunchesOnLogin.footer)
|
||||
Toggle(Strings.Views.Preferences.launchesOnLogin, isOn: $settings.launchesOnLogin)
|
||||
.themeSectionWithSingleRow(footer: Strings.Views.Preferences.LaunchesOnLogin.footer)
|
||||
}
|
||||
|
||||
var keepsInMenuToggle: some View {
|
||||
Toggle(Strings.Views.Settings.keepsInMenu, isOn: $settings.keepsInMenu)
|
||||
.themeSectionWithSingleRow(footer: Strings.Views.Settings.KeepsInMenu.footer)
|
||||
Toggle(Strings.Views.Preferences.keepsInMenu, isOn: $settings.keepsInMenu)
|
||||
.themeSectionWithSingleRow(footer: Strings.Views.Preferences.KeepsInMenu.footer)
|
||||
}
|
||||
#endif
|
||||
var eraseCloudKitButton: some View {
|
||||
Button(Strings.Views.Settings.eraseIcloud, role: .destructive) {
|
||||
Button(Strings.Views.Preferences.eraseIcloud, role: .destructive) {
|
||||
isConfirmingEraseiCloud = true
|
||||
}
|
||||
.themeConfirmation(
|
||||
isPresented: $isConfirmingEraseiCloud,
|
||||
title: Strings.Views.Settings.eraseIcloud,
|
||||
title: Strings.Views.Preferences.eraseIcloud,
|
||||
isDestructive: true
|
||||
) {
|
||||
isErasingiCloud = true
|
||||
@ -100,7 +100,7 @@ private extension PreferencesGroup {
|
||||
}
|
||||
.themeSectionWithSingleRow(
|
||||
header: Strings.Unlocalized.iCloud,
|
||||
footer: Strings.Views.Settings.EraseIcloud.footer,
|
||||
footer: Strings.Views.Preferences.EraseIcloud.footer,
|
||||
above: true
|
||||
)
|
||||
.disabled(isErasingiCloud)
|
||||
|
@ -41,7 +41,7 @@ public struct PreferencesView: View {
|
||||
PreferencesGroup(profileManager: profileManager)
|
||||
}
|
||||
.themeForm()
|
||||
.navigationTitle(Strings.Global.settings)
|
||||
.navigationTitle(Strings.Global.Nouns.settings)
|
||||
#if os(iOS)
|
||||
.themeNavigationDetail()
|
||||
.themeNavigationStack(closable: true, path: $path)
|
||||
|
@ -63,7 +63,7 @@ private extension ConnectionStatusText {
|
||||
var desc = status.localizedDescription
|
||||
if let profile = tunnel.currentProfile {
|
||||
if profile.onDemand {
|
||||
desc += Strings.Ui.ConnectionStatus.onDemandSuffix
|
||||
desc += Strings.Views.Ui.ConnectionStatus.onDemandSuffix
|
||||
}
|
||||
}
|
||||
return desc
|
||||
|
@ -99,7 +99,7 @@ private extension InteractiveCoordinator {
|
||||
func modalToolbar() -> some ToolbarContent {
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button(action: confirm) {
|
||||
Text(Strings.Global.connect)
|
||||
Text(Strings.Global.Actions.connect)
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
@ -140,12 +140,12 @@ private extension InteractiveCoordinator {
|
||||
var toolbar: some View {
|
||||
VStack {
|
||||
Button(action: confirm) {
|
||||
Text(Strings.Global.connect)
|
||||
Text(Strings.Global.Actions.connect)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
if withCancel {
|
||||
Button(role: .cancel, action: cancel) {
|
||||
Text(Strings.Global.cancel)
|
||||
Text(Strings.Global.Actions.cancel)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
|
@ -47,10 +47,10 @@ public struct PaywallModifier: ViewModifier {
|
||||
public func body(content: Content) -> some View {
|
||||
content
|
||||
.alert(
|
||||
Strings.Alerts.Iap.Restricted.title,
|
||||
Strings.Views.Paywall.Alerts.Restricted.title,
|
||||
isPresented: $isPresentingRestricted,
|
||||
actions: {
|
||||
Button(Strings.Global.ok) {
|
||||
Button(Strings.Global.Nouns.ok) {
|
||||
reason = nil
|
||||
isPresentingRestricted = false
|
||||
}
|
||||
@ -102,7 +102,7 @@ private extension PaywallModifier {
|
||||
guard case .purchase(let features, _) = reason else {
|
||||
return ""
|
||||
}
|
||||
let msg = Strings.Alerts.Iap.Restricted.message
|
||||
let msg = Strings.Views.Paywall.Alerts.Restricted.message
|
||||
return msg + "\n\n" + iapManager
|
||||
.excludingEligible(from: features)
|
||||
.map(\.localizedDescription)
|
||||
|
@ -82,6 +82,6 @@ private extension PurchaseRequiredButton {
|
||||
}
|
||||
|
||||
var helpMessage: String {
|
||||
iapManager.isRestricted ? Strings.Ui.PurchaseRequired.Restricted.help : Strings.Ui.PurchaseRequired.Purchase.help
|
||||
iapManager.isRestricted ? Strings.Views.Ui.PurchaseRequired.Restricted.help : Strings.Views.Ui.PurchaseRequired.Purchase.help
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ private extension TunnelToggleButton {
|
||||
guard let provider = providerModule.provider else {
|
||||
errorHandler.handle(
|
||||
PassepartoutError(.providerRequired),
|
||||
title: Strings.Global.connection
|
||||
title: Strings.Global.Nouns.connection
|
||||
)
|
||||
return
|
||||
}
|
||||
@ -168,8 +168,8 @@ private extension TunnelToggleButton {
|
||||
} catch {
|
||||
errorHandler.handle(
|
||||
error,
|
||||
title: Strings.Global.connection,
|
||||
message: Strings.Views.Profiles.Errors.tunnel
|
||||
title: Strings.Global.Nouns.connection,
|
||||
message: Strings.Views.App.Errors.tunnel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user