diff --git a/NodePass.xcodeproj/project.pbxproj b/NodePass.xcodeproj/project.pbxproj index 87b52b8..b57122d 100644 --- a/NodePass.xcodeproj/project.pbxproj +++ b/NodePass.xcodeproj/project.pbxproj @@ -21,8 +21,6 @@ CB1E98012E226C1E00A175FD /* DirectForwardDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1E98002E226C0F00A175FD /* DirectForwardDetailView.swift */; }; CB1E98032E226C2D00A175FD /* TunnelForwardDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1E98022E226C2300A175FD /* TunnelForwardDetailView.swift */; }; CB1E98052E2273E500A175FD /* CopiableModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1E98042E2273DE00A175FD /* CopiableModifier.swift */; }; - CB1F97C42F1F3DB30003E714 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = CB1F97C32F1F3DB30003E714 /* Localizable.xcstrings */; }; - CB1F97C52F1F3DB30003E714 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = CB1F97C32F1F3DB30003E714 /* Localizable.xcstrings */; }; CB5E133F2E7BF81300870962 /* SingleMatrixGaugeStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB5E133E2E7BF80C00870962 /* SingleMatrixGaugeStyle.swift */; }; CB5E13412E7C007100870962 /* DoubleMatrixGaugeStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB5E13402E7C006D00870962 /* DoubleMatrixGaugeStyle.swift */; }; CB5E13492E7D42DB00870962 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB5E13482E7D42DB00870962 /* WidgetKit.framework */; }; @@ -174,7 +172,6 @@ CB1E98002E226C0F00A175FD /* DirectForwardDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectForwardDetailView.swift; sourceTree = ""; }; CB1E98022E226C2300A175FD /* TunnelForwardDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelForwardDetailView.swift; sourceTree = ""; }; CB1E98042E2273DE00A175FD /* CopiableModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopiableModifier.swift; sourceTree = ""; }; - CB1F97C32F1F3DB30003E714 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; CB5E133E2E7BF80C00870962 /* SingleMatrixGaugeStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleMatrixGaugeStyle.swift; sourceTree = ""; }; CB5E13402E7C006D00870962 /* DoubleMatrixGaugeStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoubleMatrixGaugeStyle.swift; sourceTree = ""; }; CB5E13462E7D42DB00870962 /* Widget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Widget.appex; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -523,7 +520,6 @@ CBD4336B2E111155002B153F /* Shared */ = { isa = PBXGroup; children = ( - CB1F97C32F1F3DB30003E714 /* Localizable.xcstrings */, CBD433712E111527002B153F /* NPCore.swift */, CBD433722E11157B002B153F /* NPState.swift */, CB62C0802E2B90B800919507 /* NPUI.swift */, @@ -653,7 +649,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - CB1F97C42F1F3DB30003E714 /* Localizable.xcstrings in Resources */, CB5E13542E7D42DC00870962 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -664,7 +659,6 @@ files = ( CB6682CA2E1899A100A27696 /* AppIcon.icon in Resources */, CBD433632E10FA4D002B153F /* Assets.xcassets in Resources */, - CB1F97C52F1F3DB30003E714 /* Localizable.xcstrings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/NodePass/Components/LabeledTextField.swift b/NodePass/Components/LabeledTextField.swift index cc127aa..55a1cb1 100644 --- a/NodePass/Components/LabeledTextField.swift +++ b/NodePass/Components/LabeledTextField.swift @@ -8,19 +8,19 @@ import SwiftUI struct LabeledTextField: View { - let title: LocalizedStringKey + let title: String let prompt: String var text: Binding let isNumberOnly: Bool - init(_ title: LocalizedStringKey, prompt: String, text: Binding) { + init(_ title: String, prompt: String, text: Binding) { self.title = title self.prompt = prompt self.text = text self.isNumberOnly = false } - init(_ title: LocalizedStringKey, prompt: String, text: Binding, isNumberOnly: Bool) { + init(_ title: String, prompt: String, text: Binding, isNumberOnly: Bool) { self.title = title self.prompt = prompt self.text = text diff --git a/NodePass/ContentView.swift b/NodePass/ContentView.swift index e21032a..d217ddc 100644 --- a/NodePass/ContentView.swift +++ b/NodePass/ContentView.swift @@ -22,9 +22,9 @@ enum MainTab: String, CaseIterable { var title: String { switch self { - case .services: String(localized: "Services") - case .servers: String(localized: "Servers") - case .settings: String(localized: "Settings") + case .services: "Services" + case .servers: "Servers" + case .settings: "Settings" } } } diff --git a/NodePass/Server/Instance/InstanceFormView.swift b/NodePass/Server/Instance/InstanceFormView.swift index 7e2cf97..0430424 100644 --- a/NodePass/Server/Instance/InstanceFormView.swift +++ b/NodePass/Server/Instance/InstanceFormView.swift @@ -31,6 +31,7 @@ struct InstanceFormView: View { @State private var crtPath: String = "" @State private var keyPath: String = "" @State private var sni: String = "" + @State private var password: String = "" @State private var connectionMode: ConnectionMode = .auto @State private var connectionType: Instance.Transport = .tcp @State private var minConnections: String = "" @@ -86,8 +87,8 @@ struct InstanceFormView: View { } enum InputMode: String, CaseIterable { - case form = "Form" - case url = "URL" + case form = "Details" + case url = "Command" } enum InstanceType: String, CaseIterable { @@ -117,25 +118,6 @@ struct InstanceFormView: View { .foregroundStyle(.secondary) } - Section { - Picker("Input Mode", selection: $inputMode) { - ForEach(InputMode.allCases, id: \.self) { mode in - Text(mode.rawValue).tag(mode) - } - } - .pickerStyle(.segmented) - } header: { - Text("Input Method") - } footer: { - if inputMode == .form { - Text("Configure instance using form fields.") - .foregroundStyle(.secondary) - } else { - Text("Enter instance URL directly.") - .foregroundStyle(.secondary) - } - } - if inputMode == .form { formModeContent } else { @@ -158,6 +140,16 @@ struct InstanceFormView: View { #endif .navigationTitle(title) .toolbar { + ToolbarItem(placement: .principal) { + Picker("Input Mode", selection: $inputMode) { + ForEach(InputMode.allCases, id: \.self) { mode in + Text(mode.rawValue).tag(mode) + } + } + .pickerStyle(.segmented) + .labelsHidden() + } + ToolbarItem(placement: .cancellationAction) { if #available(iOS 26.0, macOS 26.0, *) { Button(role: .cancel) { @@ -354,6 +346,12 @@ struct InstanceFormView: View { } Section { + LabeledTextField("Password", prompt: "Optional", text: $password) + .autocorrectionDisabled() +#if os(iOS) + .textInputAutocapitalization(.never) +#endif + if instanceType == .server { Picker("TLS Mode", selection: $tlsMode) { ForEach(TLSMode.allCases, id: \.self) { mode in @@ -577,6 +575,7 @@ struct InstanceFormView: View { instanceType = url.hasPrefix("server://") ? .server : .client + password = urlComponents.user ?? "" tunnelAddress = urlComponents.host ?? "" tunnelPort = urlComponents.port.map { String($0) } ?? "" @@ -727,10 +726,12 @@ struct InstanceFormView: View { } var url: String + let passwordPrefix = password.isEmpty ? "" : "\(password)@" + if instanceType == .server { - url = "server://\(tunnelAddr):\(tunnelPt)/\(targetPath)" + url = "server://\(passwordPrefix)\(tunnelAddr):\(tunnelPt)/\(targetPath)" } else { - url = "client://\(tunnelAddr):\(tunnelPt)/\(targetPath)" + url = "client://\(passwordPrefix)\(tunnelAddr):\(tunnelPt)/\(targetPath)" } var queryParams: [String] = [] diff --git a/NodePass/Server/ServerListView.swift b/NodePass/Server/ServerListView.swift index bef6b02..5e9a375 100644 --- a/NodePass/Server/ServerListView.swift +++ b/NodePass/Server/ServerListView.swift @@ -16,9 +16,9 @@ fileprivate enum SortIndicator: String, CaseIterable { var title: String { switch(self) { case .name: - return String(localized: "Name") + return "Name" case .date: - return String(localized: "Date") + return "Date" } } } @@ -30,9 +30,9 @@ fileprivate enum SortOrder: String, CaseIterable { var title: String { switch(self) { case .ascending: - return String(localized: "Ascending") + return "Ascending" case .descending: - return String(localized: "Descending") + return "Descending" } } @@ -41,16 +41,16 @@ fileprivate enum SortOrder: String, CaseIterable { case .name: switch(self) { case .ascending: - return String(localized: "Ascending") + return "Ascending" case .descending: - return String(localized: "Descending") + return "Descending" } case .date: switch(self) { case .ascending: - return String(localized: "Oldest to Newest") + return "Oldest to Newest" case .descending: - return String(localized: "Newest to Oldest") + return "Newest to Oldest" } } } diff --git a/NodePass/Service/Add Service/AddDirectForwardServiceView.swift b/NodePass/Service/Add Service/AddDirectForwardServiceView.swift index 26483be..11bf5f7 100644 --- a/NodePass/Service/Add Service/AddDirectForwardServiceView.swift +++ b/NodePass/Service/Add Service/AddDirectForwardServiceView.swift @@ -170,7 +170,7 @@ struct AddDirectForwardServiceView: View { type: .directForward, implementations: [ Implementation( - name: String(localized: "\(name) Relay"), + name: "\(name) Relay", type: .directForwardClient, position: 0, serverID: client?.id ?? "", @@ -282,7 +282,7 @@ struct AddDirectForwardServiceView: View { type: .directForward, implementations: [ Implementation( - name: String(localized: "\(name) Relay"), + name: "\(name) Relay", type: .directForwardClient, position: 0, serverID: client.id, @@ -300,7 +300,7 @@ struct AddDirectForwardServiceView: View { baseURLString: client.url, apiKey: client.key, id: clientInstance.id, - serviceAlias: String(localized: "\(name)"), + serviceAlias: "\(name)", serviceId: serviceId.uuidString, serviceType: "0" ) diff --git a/NodePass/Service/Add Service/AddNATPassthroughServiceView.swift b/NodePass/Service/Add Service/AddNATPassthroughServiceView.swift index 345ec3e..8938e94 100644 --- a/NodePass/Service/Add Service/AddNATPassthroughServiceView.swift +++ b/NodePass/Service/Add Service/AddNATPassthroughServiceView.swift @@ -252,7 +252,7 @@ struct AddNATPassthroughServiceView: View { type: .natPassthrough, implementations: [ Implementation( - name: String(localized: "\(name) Remote"), + name: "\(name) Remote", type: .natPassthroughServer, position: 0, serverID: remoteServer?.id ?? "", @@ -261,7 +261,7 @@ struct AddNATPassthroughServiceView: View { fullCommand: serverCommand ), Implementation( - name: String(localized: "\(name) Local"), + name: "\(name) Local", type: .natPassthroughClient, position: 1, serverID: localServer?.id ?? "", @@ -416,7 +416,7 @@ struct AddNATPassthroughServiceView: View { type: .natPassthrough, implementations: [ Implementation( - name: String(localized: "\(name) Remote"), + name: "\(name) Remote", type: .natPassthroughServer, position: 0, serverID: remoteServer.id, @@ -425,7 +425,7 @@ struct AddNATPassthroughServiceView: View { fullCommand: serverFullCommand ), Implementation( - name: String(localized: "\(name) Local"), + name: "\(name) Local", type: .natPassthroughClient, position: 1, serverID: localServer.id, @@ -444,7 +444,7 @@ struct AddNATPassthroughServiceView: View { baseURLString: remoteServer.url, apiKey: remoteServer.key, id: serverInstance.id, - serviceAlias: String(localized: "\(name)"), + serviceAlias: "\(name)", serviceId: serviceId.uuidString, serviceType: isExternalTarget ? "3" : "1" ) @@ -452,7 +452,7 @@ struct AddNATPassthroughServiceView: View { baseURLString: localServer.url, apiKey: localServer.key, id: clientInstance.id, - serviceAlias: String(localized: "\(name)"), + serviceAlias: "\(name)", serviceId: serviceId.uuidString, serviceType: isExternalTarget ? "3" : "1" ) diff --git a/NodePass/Service/Add Service/AddTunnelForwardServiceView.swift b/NodePass/Service/Add Service/AddTunnelForwardServiceView.swift index 255ac3b..034df1c 100644 --- a/NodePass/Service/Add Service/AddTunnelForwardServiceView.swift +++ b/NodePass/Service/Add Service/AddTunnelForwardServiceView.swift @@ -282,7 +282,7 @@ struct AddTunnelForwardServiceView: View { type: .tunnelForward, implementations: [ Implementation( - name: String(localized: "\(name) Relay"), + name: "\(name) Relay", type: .tunnelForwardRelay, position: 0, serverID: relayServer?.id ?? "", @@ -291,7 +291,7 @@ struct AddTunnelForwardServiceView: View { fullCommand: relayServerCommand ), Implementation( - name: String(localized: "\(name) Destination"), + name: "\(name) Destination", type: .tunnelForwardDestination, position: 1, serverID: destinationServer?.id ?? "", @@ -447,7 +447,7 @@ struct AddTunnelForwardServiceView: View { type: .tunnelForward, implementations: [ Implementation( - name: String(localized: "\(name) Relay"), + name: "\(name) Relay", type: .tunnelForwardRelay, position: 0, serverID: relayServer.id, @@ -456,7 +456,7 @@ struct AddTunnelForwardServiceView: View { fullCommand: relayServerFullCommand ), Implementation( - name: String(localized: "\(name) Destination"), + name: "\(name) Destination", type: .tunnelForwardDestination, position: 1, serverID: destinationServer.id, @@ -475,7 +475,7 @@ struct AddTunnelForwardServiceView: View { baseURLString: relayServer.url, apiKey: relayServer.key, id: relayServerInstance.id, - serviceAlias: String(localized: "\(name)"), + serviceAlias: "\(name)", serviceId: serviceId.uuidString, serviceType: isExternalTarget ? "4" : "2" ) @@ -483,7 +483,7 @@ struct AddTunnelForwardServiceView: View { baseURLString: destinationServer.url, apiKey: destinationServer.key, id: destinationServerInstance.id, - serviceAlias: String(localized: "\(name)"), + serviceAlias: "\(name)", serviceId: serviceId.uuidString, serviceType: isExternalTarget ? "4" : "2" ) diff --git a/NodePass/Service/Card/DirectForwardCardView.swift b/NodePass/Service/Card/DirectForwardCardView.swift index 94d5edf..df7e9a0 100644 --- a/NodePass/Service/Card/DirectForwardCardView.swift +++ b/NodePass/Service/Card/DirectForwardCardView.swift @@ -55,7 +55,7 @@ struct DirectForwardCardView: View { HStack(alignment: .imageAlignment) { let implementation = service.implementations!.first(where: { $0.position == 0 })! - let serverName = servers.first(where: { $0.id == implementation.serverID })?.name ?? String(localized: isPreview ? "Select" : "Unknown") + let serverName = servers.first(where: { $0.id == implementation.serverID })?.name ?? (isPreview ? "Select" : "Unknown") let addressesAndPorts = NPCore.parseAddressesAndPorts(urlString: implementation.command) Image(systemName: "laptopcomputer.and.iphone") .font(.title) diff --git a/NodePass/Service/Card/NATPassthroughCardView.swift b/NodePass/Service/Card/NATPassthroughCardView.swift index 8cf1006..85cd019 100644 --- a/NodePass/Service/Card/NATPassthroughCardView.swift +++ b/NodePass/Service/Card/NATPassthroughCardView.swift @@ -65,7 +65,7 @@ struct NATPassthroughCardView: View { .alignmentGuide(.imageAlignment) { d in d[VerticalAlignment.center] } Spacer() VStack(spacing: 3) { - let serverName = servers.first(where: { $0.id == implementation0.serverID })?.name ?? String(localized: isPreview ? "Select" : "Unknown") + let serverName = servers.first(where: { $0.id == implementation0.serverID })?.name ?? (isPreview ? "Select" : "Unknown") let addressesAndPorts = NPCore.parseAddressesAndPorts(urlString: implementation0.command) Text(serverName) .lineLimit(1) @@ -95,7 +95,7 @@ struct NATPassthroughCardView: View { let addressesAndPorts = NPCore.parseAddressesAndPorts(urlString: implementation1.command) if addressesAndPorts.destination.address == "127.0.0.1" { VStack(spacing: 3) { - let serverName = servers.first(where: { $0.id == implementation1.serverID })?.name ?? String(localized: isPreview ? "Select" : "Unknown") + let serverName = servers.first(where: { $0.id == implementation1.serverID })?.name ?? (isPreview ? "Select" : "Unknown") let addressesAndPorts = NPCore.parseAddressesAndPorts(urlString: implementation1.command) Text(serverName) .lineLimit(1) @@ -113,7 +113,7 @@ struct NATPassthroughCardView: View { } else { VStack(spacing: 3) { - let serverName = servers.first(where: { $0.id == implementation1.serverID })?.name ?? String(localized: isPreview ? "Select" : "Unknown") + let serverName = servers.first(where: { $0.id == implementation1.serverID })?.name ?? (isPreview ? "Select" : "Unknown") Text(serverName) .lineLimit(1) .minimumScaleFactor(0.5) diff --git a/NodePass/Service/Card/TunnelForwardCardView.swift b/NodePass/Service/Card/TunnelForwardCardView.swift index 5510044..a491691 100644 --- a/NodePass/Service/Card/TunnelForwardCardView.swift +++ b/NodePass/Service/Card/TunnelForwardCardView.swift @@ -76,7 +76,7 @@ struct TunnelForwardCardView: View { .alignmentGuide(.imageAlignment) { d in d[VerticalAlignment.center] } Spacer() VStack(spacing: 3) { - let serverName = servers.first(where: { $0.id == implementation0.serverID })?.name ?? String(localized: isPreview ? "Select" : "Unknown") + let serverName = servers.first(where: { $0.id == implementation0.serverID })?.name ?? (isPreview ? "Select" : "Unknown") let addressesAndPorts = NPCore.parseAddressesAndPorts(urlString: implementation0.command) Text(serverName) .lineLimit(1) @@ -106,7 +106,7 @@ struct TunnelForwardCardView: View { let addressesAndPorts = NPCore.parseAddressesAndPorts(urlString: implementation1.command) if addressesAndPorts.destination.address == "127.0.0.1" { VStack(spacing: 3) { - let serverName = servers.first(where: { $0.id == implementation1.serverID })?.name ?? String(localized: isPreview ? "Select" : "Unknown") + let serverName = servers.first(where: { $0.id == implementation1.serverID })?.name ?? (isPreview ? "Select" : "Unknown") let addressesAndPorts = NPCore.parseAddressesAndPorts(urlString: implementation1.command) Text(serverName) .lineLimit(1) @@ -124,7 +124,7 @@ struct TunnelForwardCardView: View { } else { VStack(spacing: 3) { - let serverName = servers.first(where: { $0.id == implementation1.serverID })?.name ?? String(localized: isPreview ? "Select" : "Unknown") + let serverName = servers.first(where: { $0.id == implementation1.serverID })?.name ?? (isPreview ? "Select" : "Unknown") Text(serverName) .lineLimit(1) .minimumScaleFactor(0.5) diff --git a/NodePass/Service/ServiceListView.swift b/NodePass/Service/ServiceListView.swift index 42b6dd6..ac1e995 100644 --- a/NodePass/Service/ServiceListView.swift +++ b/NodePass/Service/ServiceListView.swift @@ -16,9 +16,9 @@ fileprivate enum SortIndicator: String, CaseIterable { var title: String { switch(self) { case .name: - return String(localized: "Name") + return "Name" case .date: - return String(localized: "Date") + return "Date" } } } @@ -30,9 +30,9 @@ fileprivate enum SortOrder: String, CaseIterable { var title: String { switch(self) { case .ascending: - return String(localized: "Ascending") + return "Ascending" case .descending: - return String(localized: "Descending") + return "Descending" } } @@ -41,16 +41,16 @@ fileprivate enum SortOrder: String, CaseIterable { case .name: switch(self) { case .ascending: - return String(localized: "Ascending") + return "Ascending" case .descending: - return String(localized: "Descending") + return "Descending" } case .date: switch(self) { case .ascending: - return String(localized: "Oldest to Newest") + return "Oldest to Newest" case .descending: - return String(localized: "Newest to Oldest") + return "Newest to Oldest" } } } @@ -361,7 +361,7 @@ struct ServiceListView: View { private func deleteService(service: Service, isForce: Bool = false) { func showGeneralizedErrorMessage(error: Error, instanceID: String) { - errorMessage = String(localized: "Error Deleting Instance \(instanceID):\(error.localizedDescription)") + errorMessage = "Error Deleting Instance \(instanceID):\(error.localizedDescription)" isShowErrorAlert = true } @@ -399,7 +399,7 @@ struct ServiceListView: View { context.delete(service) } else { - errorMessage = String(localized: "Error Deleting Instance \(serverInstanceID): Server not found.") + errorMessage = "Error Deleting Instance \(serverInstanceID): Server not found." isShowErrorAlert = true } return @@ -410,7 +410,7 @@ struct ServiceListView: View { try? context.save() } else { - errorMessage = String(localized: "Error Deleting Instance \(clientInstanceID): Server not found.") + errorMessage = "Error Deleting Instance \(clientInstanceID): Server not found." isShowErrorAlert = true } return @@ -450,7 +450,7 @@ struct ServiceListView: View { try? context.save() } else { - errorMessage = String(localized: "Error Deleting Instance \(clientInstanceID): Server not found.") + errorMessage = "Error Deleting Instance \(clientInstanceID): Server not found." isShowErrorAlert = true } return @@ -522,7 +522,7 @@ struct ServiceListView: View { if let existingService = services.first(where: { $0.id.uuidString == serviceId }) { // Update existing service - existingService.name = instance.metadata?.peer.alias ?? String(localized: "Untitled") + existingService.name = instance.metadata?.peer.alias ?? "Untitled" existingService.isConfigurationInvalid = !isValidConfiguration if let implementation = existingService.implementations?.first { implementation.name = clientInstance.metadata!.peer.alias @@ -534,7 +534,7 @@ struct ServiceListView: View { // Create new service let service = Service( id: UUID(uuidString: serviceId) ?? UUID(), - name: instance.metadata?.peer.alias ?? String(localized: "Untitled"), + name: instance.metadata?.peer.alias ?? "Untitled", type: .directForward, implementations: [ Implementation( @@ -571,7 +571,7 @@ struct ServiceListView: View { if let existingService = services.first(where: { $0.id.uuidString == serviceId }) { // Update existing service - existingService.name = instance.metadata?.peer.alias ?? String(localized: "Untitled") + existingService.name = instance.metadata?.peer.alias ?? "Untitled" existingService.isConfigurationInvalid = !isValidConfiguration if let implementations = existingService.implementations { // Update by instanceID @@ -594,7 +594,7 @@ struct ServiceListView: View { let service = Service( id: UUID(uuidString: serviceId) ?? UUID(), - name: instance.metadata?.peer.alias ?? String(localized: "Untitled"), + name: instance.metadata?.peer.alias ?? "Untitled", type: .natPassthrough, implementations: [ Implementation( @@ -632,7 +632,7 @@ struct ServiceListView: View { if let existingService = services.first(where: { $0.id.uuidString == serviceId }) { // Update existing service - existingService.name = instance.metadata?.peer.alias ?? String(localized: "Untitled") + existingService.name = instance.metadata?.peer.alias ?? "Untitled" existingService.isConfigurationInvalid = !isValidConfiguration if let implementations = existingService.implementations { // Update by instanceID @@ -656,7 +656,7 @@ struct ServiceListView: View { let service = Service( id: UUID(uuidString: serviceId) ?? UUID(), - name: instance.metadata?.peer.alias ?? String(localized: "Untitled"), + name: instance.metadata?.peer.alias ?? "Untitled", type: .tunnelForward, implementations: [ Implementation( diff --git a/NodePass/SettingsView.swift b/NodePass/SettingsView.swift index 883b1f1..c973c16 100644 --- a/NodePass/SettingsView.swift +++ b/NodePass/SettingsView.swift @@ -31,7 +31,7 @@ struct SettingsView: View { } Section { - Picker(String(localized: "Theme"), selection: $selectedTheme) { + Picker("Theme", selection: $selectedTheme) { ForEach(NPCore.AppTheme.allCases, id: \.self) { theme in Text(theme.displayName).tag(theme) } diff --git a/Shared/Handlers/NetworkService/NetworkError.swift b/Shared/Handlers/NetworkService/NetworkError.swift index ea06acf..3a6487d 100644 --- a/Shared/Handlers/NetworkService/NetworkError.swift +++ b/Shared/Handlers/NetworkService/NetworkError.swift @@ -18,13 +18,13 @@ enum NetworkError: Error, LocalizedError { var errorDescription: String? { switch self { - case .invalidURL: return String(localized: "Invalid URL") - case .requestFailed(let error): return String(localized: "Request Failed: \(error.localizedDescription)") - case .invalidResponse: return String(localized: "Invalid Response") - case .unauthorized: return String(localized: "Unauthorized") - case .decodingFailed(let error): return String(localized: "Decoding Failed: \(error.localizedDescription)") + case .invalidURL: return "Invalid URL" + case .requestFailed(let error): return "Request Failed: \(error.localizedDescription)" + case .invalidResponse: return "Invalid Response" + case .unauthorized: return "Unauthorized" + case .decodingFailed(let error): return "Decoding Failed: \(error.localizedDescription)" case .serverError(let code, let message): - return String(localized: "Server Error(\(code)): \(message ?? "Unknown Error")") + return "Server Error(\(code)): \(message ?? "Unknown Error")" case .custom(let message): return message } } diff --git a/Shared/Localizable.xcstrings b/Shared/Localizable.xcstrings deleted file mode 100644 index 09d7296..0000000 --- a/Shared/Localizable.xcstrings +++ /dev/null @@ -1,840 +0,0 @@ -{ - "sourceLanguage" : "en", - "strings" : { - "%.0f%%" : { - - }, - "%@" : { - - }, - "%@ Destination" : { - - }, - "%@ Local" : { - - }, - "%@ New Server" : { - - }, - "%@ Relay" : { - - }, - "%@ Remote" : { - - }, - "%@: %@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "%1$@: %2$@" - } - } - } - }, - "%lld error(s)" : { - "localizations" : { - "en" : { - "variations" : { - "plural" : { - "one" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld error" - } - }, - "other" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld errors" - } - } - } - } - } - } - }, - "%lld target(s)" : { - "localizations" : { - "en" : { - "variations" : { - "plural" : { - "one" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld target" - } - }, - "other" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld targets" - } - } - } - } - } - } - }, - "%lld%@" : { - "comment" : "Short format: 5d", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "%1$lld%2$@" - } - } - } - }, - "%lld%@%lld%@" : { - "comment" : "Long format: 5d 3h", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "%1$lld%2$@ %3$lld%4$@" - } - } - } - }, - "↑" : { - - }, - "↑ %@" : { - - }, - "↓" : { - - }, - "↓ %@" : { - - }, - "=" : { - - }, - "Add" : { - - }, - "Add custom URL query parameters not covered above." : { - - }, - "Add Direct Forward" : { - - }, - "Add Instance" : { - - }, - "Add NAT Passthrough" : { - - }, - "Add Parameter" : { - - }, - "Add Server" : { - - }, - "Add Service" : { - - }, - "Add Tunnel Forward" : { - - }, - "Additional Parameters" : { - - }, - "Address" : { - - }, - "Address %lld" : { - - }, - "Address: Domain/IP of the destination server." : { - - }, - "Adjust the updating rate of server metadata." : { - - }, - "Advanced Mode" : { - - }, - "Advanced Settings" : { - - }, - "An error occurred" : { - - }, - "An optional friendly name for this instance." : { - - }, - "Ascending" : { - - }, - "Automatic" : { - - }, - "Block certain traffic from being tunneled." : { - - }, - "Block HTTP" : { - - }, - "Block SOCKS" : { - - }, - "Block TLS" : { - - }, - "Cancel" : { - - }, - "Certificate Path" : { - - }, - "Configuration Invalid" : { - - }, - "Configure advanced settings and tuning parameters." : { - - }, - "Configure connection pool behavior and limits." : { - - }, - "Configure instance using form fields." : { - - }, - "Configure multiple target addresses for load balancing." : { - - }, - "Configure Server Detail Widget" : { - - }, - "Configure Widget" : { - - }, - "Connect to tunnel address and forward from/to target." : { - - }, - "Connection Mode" : { - - }, - "Connection Pool" : { - - }, - "Connection Type" : { - - }, - "Control protocol availability and PROXY v1 support." : { - - }, - "Copy" : { - - }, - "CPU" : { - - }, - "Dark" : { - - }, - "Date" : { - - }, - "Decoding Failed: %@" : { - - }, - "Delete" : { - - }, - "Delete Instance" : { - - }, - "Delete Server" : { - - }, - "Delete Service" : { - - }, - "Descending" : { - - }, - "Destination Server" : { - - }, - "Destination Server: Server you want your traffic to relay to." : { - - }, - "Dial Address" : { - - }, - "Dial: Specific source IP or 'auto' by OS." : { - - }, - "Direct Forward" : { - - }, - "Disable TCP" : { - - }, - "Disable UDP" : { - - }, - "DNS Cache Duration" : { - - }, - "DNS: Cache TTL duration in '30s, 5m, 1h'." : { - - }, - "Domain" : { - - }, - "Done" : { - - }, - "Edit" : { - - }, - "Edit Instance" : { - - }, - "Edit Server" : { - - }, - "Enable PROXY Protocol" : { - - }, - "Enter a new name for the service." : { - - }, - "Enter instance URL directly." : { - - }, - "Error" : { - - }, - "Error Deleting Instance %@: Server not found." : { - - }, - "Error Deleting Instance %@:%@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Error Deleting Instance %1$@:%2$@" - } - } - } - }, - "External Target" : { - - }, - "Force Delete" : { - - }, - "Force Delete Service" : { - - }, - "Get up-to-date information in your Widget." : { - - }, - "Input Method" : { - - }, - "Input Mode" : { - - }, - "Instance Alias" : { - - }, - "Instance Type" : { - - }, - "Instance URL" : { - - }, - "Invalid Response" : { - - }, - "Invalid URL" : { - - }, - "IP" : { - - }, - "IP %lld" : { - - }, - "key" : { - - }, - "Key" : { - - }, - "Key Example: da101e32c7b8c296c8b0d08fca480edc" : { - - }, - "Key Path" : { - - }, - "Key: API Key of your master API." : { - - }, - "Light" : { - - }, - "Listen on tunnel address and forward to/from target." : { - - }, - "Listen Port" : { - - }, - "Listen Port: Port you use to connect to the relay server." : { - - }, - "Listen Port: Port you use to connect to the remote server." : { - - }, - "Load Balancing Strategy" : { - - }, - "Loading..." : { - - }, - "Local Server" : { - - }, - "Local Server: Server without a public IP." : { - - }, - "Log Level" : { - - }, - "Logging Level" : { - - }, - "Matrix Unavailable" : { - - }, - "Max Connections" : { - - }, - "Maximum Connections" : { - - }, - "Maximum Pool Connection" : { - - }, - "Memory" : { - - }, - "Metadata Unavailable" : { - - }, - "Minimum Connections" : { - - }, - "Minimum Pool Connection" : { - - }, - "More" : { - - }, - "Multiple Target Addresses" : { - - }, - "Name" : { - - }, - "NAT Passthrough" : { - - }, - "Network" : { - - }, - "Network Tuning" : { - - }, - "Newest to Oldest" : { - - }, - "No Server" : { - - }, - "No Service" : { - - }, - "NodePass Supporter" : { - - }, - "None" : { - - }, - "Not on this device" : { - - }, - "OK" : { - - }, - "Optional" : { - - }, - "Oldest to Newest" : { - - }, - "Pool" : { - - }, - "Port" : { - - }, - "Port %lld" : { - - }, - "Port: Port on which your service like Socks5(1080) is running." : { - - }, - "Preview" : { - - }, - "Protocol" : { - - }, - "Protocol Control" : { - - }, - "Rate Limit (Mbps)" : { - - }, - "Rate: Bandwidth limit or 0 for unlimited." : { - - }, - "Read Timeout" : { - - }, - "Read: Timeout duration or 0 to disable." : { - - }, - "Refresh Widget" : { - - }, - "Relay Server" : { - - }, - "Relay Server: Server you want to use as a relay." : { - - }, - "Reload" : { - - }, - "Remote Server" : { - - }, - "Remote Server: Server with a public IP." : { - - }, - "Rename" : { - - }, - "Rename Service" : { - - }, - "Request Failed: %@" : { - - }, - "Restart" : { - - }, - "Retry" : { - - }, - "Scan QR Code" : { - - }, - "Security & Encryption" : { - - }, - "Select" : { - - }, - "Self-signed Certificates" : { - "comment" : "TLS Level: Self-signed Certificates" - }, - "Server" : { - - }, - "Server address to connect or Client address to bind." : { - - }, - "Server Details" : { - - }, - "Server Error(%lld): %@" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Server Error(%1$lld): %2$@" - } - } - } - }, - "Server Metadata Updating Rate" : { - - }, - "Servers" : { - - }, - "Service Port" : { - - }, - "Service Port: Port on which your service like Socks5(1080) is running." : { - - }, - "Service Port: Port on which your service like SSH(22) is running." : { - - }, - "Services" : { - - }, - "Settings" : { - - }, - "Share" : { - - }, - "Single target address to connect or to bind." : { - - }, - "Slot: Max concurrent connections allowed." : { - - }, - "SNI Hostname" : { - - }, - "SNI hostname for TLS connections." : { - - }, - "Sort" : { - - }, - "Start" : { - - }, - "Stop" : { - - }, - "Support Us" : { - - }, - "Swap" : { - - }, - "Sync" : { - - }, - "Sync completed" : { - - }, - "Sync Error Report" : { - - }, - "Syncing" : { - - }, - "Target Address" : { - - }, - "Target Address %lld" : { - - }, - "Target Address: Address of your external target like devices in your home." : { - - }, - "Target Address: Address of your external target server." : { - - }, - "Target Port" : { - - }, - "Target Port %lld" : { - - }, - "Target Port: Port on which your service like Socks5(1080) is running on your external target server." : { - - }, - "Target Port: Port on which your service like SSH(22) is running on your external target." : { - - }, - "TCP" : { - - }, - "Theme" : { - - }, - "timeUnitShortened.d" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "d" - } - } - } - }, - "timeUnitShortened.h" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "h" - } - } - } - }, - "timeUnitShortened.m" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "m" - } - } - } - }, - "timeUnitShortened.s" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "s" - } - } - } - }, - "TLS" : { - - }, - "TLS encryption settings." : { - - }, - "TLS Mode" : { - - }, - "To add a server, tap the add server icon in the toolbar." : { - "localizations" : { - "en" : { - "variations" : { - "device" : { - "mac" : { - "stringUnit" : { - "state" : "translated", - "value" : "To add a server, click the add server icon in the toolbar." - } - }, - "other" : { - "stringUnit" : { - "state" : "new", - "value" : "To add a server, tap the add server icon in the toolbar." - } - } - } - } - } - } - }, - "To add a service, tap the add service icon in the toolbar." : { - "localizations" : { - "en" : { - "variations" : { - "device" : { - "mac" : { - "stringUnit" : { - "state" : "translated", - "value" : "To add a service, click the add service icon in the toolbar." - } - }, - "other" : { - "stringUnit" : { - "state" : "new", - "value" : "To add a service, tap the add service icon in the toolbar." - } - } - } - } - } - } - }, - "Traffic Blocking" : { - - }, - "Transport" : { - - }, - "Trusted Certificates" : { - "comment" : "TLS Level: Trusted Certificates" - }, - "Tunnel %@ Address" : { - - }, - "Tunnel address to bind, empty IP for all interfaces." : { - - }, - "Tunnel Forward" : { - - }, - "Tunnel Port" : { - - }, - "Tunnel Port: Any available port." : { - - }, - "Tunnel Through CDN" : { - - }, - "UDP" : { - - }, - "Unauthorized" : { - - }, - "Unencrypted" : { - "comment" : "TLS Level: Unencrypted" - }, - "Unknown" : { - - }, - "Unsupported family" : { - - }, - "Untitled" : { - - }, - "URL" : { - - }, - "URL Example: https://17.253.144.10:1000/api/v1" : { - - }, - "URL: URL of your master API." : { - - }, - "value" : { - - }, - "View details of your servers at a glance." : { - - }, - "Visit https://github.com/NodePassProject for documentation on instance URL parameters." : { - - }, - "You are about to delete this server. Are you sure?" : { - - }, - "You are about to delete this service. This action is irreversible. Are you sure?" : { - - }, - "You are about to force delete this service. This action is irreversible and any error will be ignored. Are you sure?" : { - - } - }, - "version" : "1.1" -} \ No newline at end of file diff --git a/Shared/Models/enums/TLSMode.swift b/Shared/Models/enums/TLSMode.swift index c953750..4aa48c8 100644 --- a/Shared/Models/enums/TLSMode.swift +++ b/Shared/Models/enums/TLSMode.swift @@ -17,7 +17,7 @@ enum TLSMode: String, CaseIterable { case .selfSigned: return "Self-signed Certificate" case .custom: - return "Custom Certificate" + return "Trusted Certificate" } } } diff --git a/Shared/NPCore.swift b/Shared/NPCore.swift index 28b9c83..1e090fb 100644 --- a/Shared/NPCore.swift +++ b/Shared/NPCore.swift @@ -53,9 +53,9 @@ class NPCore { var displayName: String { switch self { - case .automatic: return String(localized: "Automatic") - case .light: return String(localized: "Light") - case .dark: return String(localized: "Dark") + case .automatic: return "Automatic" + case .light: return "Light" + case .dark: return "Dark" } } } @@ -160,7 +160,7 @@ class NPCore { // MARK: - Utilities static func noEmptyName(_ name: String) -> String { - return name == "" ? String(localized: "Untitled") : name + return name == "" ? "Untitled" : name } static func formatBytes(_ bytes: Int64, decimals: Int = 2) -> String { @@ -191,36 +191,36 @@ class NPCore { let days = hours / 24 func formatShort(_ unit: String, _ value: Int64) -> String { - return String(format: NSLocalizedString("%lld%@", comment: "Short format: 5d"), value, NSLocalizedString(unit, comment: "Time unit")) + return String(format: "%lld%@", value, unit) } func formatLong(_ unit1: String, _ value1: Int64, _ unit2: String, _ value2: Int64) -> String { - return String(format: NSLocalizedString("%lld%@%lld%@", comment: "Long format: 5d 3h"), value1, NSLocalizedString(unit1, comment: "Time unit 1"), value2, NSLocalizedString(unit2, comment: "Time unit 2")) + return String(format: "%lld%@ %lld%@", value1, unit1, value2, unit2) } if days >= 10 { - return formatShort(String(localized: "timeUnitShortened.d"), days) + return formatShort("d", days) } else if days > 0 { - return shortened ? formatShort(String(localized: "timeUnitShortened.d"), days) : formatLong(String(localized: "timeUnitShortened.d"), days, String(localized: "timeUnitShortened.h"), hours % 24) + return shortened ? formatShort("d", days) : formatLong("d", days, "h", hours % 24) } else if hours > 0 { - return shortened ? formatShort(String(localized: "timeUnitShortened.h"), hours) : formatLong(String(localized: "timeUnitShortened.h"), hours, String(localized: "timeUnitShortened.m"), minutes % 60) + return shortened ? formatShort("h", hours) : formatLong("h", hours, "m", minutes % 60) } else if minutes > 0 { - return shortened ? formatShort(String(localized: "timeUnitShortened.m"), minutes) : formatLong(String(localized: "timeUnitShortened.m"), minutes, String(localized: "timeUnitShortened.s"), seconds % 60) + return shortened ? formatShort("m", minutes) : formatLong("m", minutes, "s", seconds % 60) } else { - return formatShort(String(localized: "timeUnitShortened.s"), seconds) + return formatShort("s", seconds) } } static func localizedTLSLevel(tlsLevel: String) -> String { switch(tlsLevel) { case "0": - return String(localized: "Unencrypted", comment: "TLS Level: Unencrypted") + return "No TLS Encryption" case "1": - return String(localized: "Self-signed Certificates", comment: "TLS Level: Self-signed Certificates") + return "Self-signed Certificate" case "2": - return String(localized: "Trusted Certificates", comment: "TLS Level: Trusted Certificates") + return "Trusted Certificate" default: - return String(localized: "Unknown") + return "Unknown" } } } diff --git a/Shared/UI/Components/OutlinedBadge.swift b/Shared/UI/Components/OutlinedBadge.swift index f7a9356..4fc87cb 100644 --- a/Shared/UI/Components/OutlinedBadge.swift +++ b/Shared/UI/Components/OutlinedBadge.swift @@ -8,12 +8,12 @@ import SwiftUI struct OutlinedBadge: View { - let text: LocalizedStringKey + let text: String let borderColor: Color let textColor: Color let lineWidth: CGFloat - init(_ text: LocalizedStringKey, + init(_ text: String, borderColor: Color = .blue, textColor: Color = .blue, lineWidth: CGFloat = 1.0) { diff --git a/Shared/UI/Styles/DoubleMatrixGaugeStyle.swift b/Shared/UI/Styles/DoubleMatrixGaugeStyle.swift index e623bd8..5641865 100644 --- a/Shared/UI/Styles/DoubleMatrixGaugeStyle.swift +++ b/Shared/UI/Styles/DoubleMatrixGaugeStyle.swift @@ -8,8 +8,8 @@ import SwiftUI struct DoubleMatrixGaugeStyle: GaugeStyle { - let text1: LocalizedStringKey - let text2: LocalizedStringKey + let text1: String + let text2: String let color1: Color let color2: Color let size: CGFloat