diff --git a/LocalDevVPN.xcodeproj/xcshareddata/xcschemes/TunnelProv.xcscheme b/LocalDevVPN.xcodeproj/xcshareddata/xcschemes/TunnelProv.xcscheme index 8d51541..7c566e4 100644 --- a/LocalDevVPN.xcodeproj/xcshareddata/xcschemes/TunnelProv.xcscheme +++ b/LocalDevVPN.xcodeproj/xcshareddata/xcschemes/TunnelProv.xcscheme @@ -74,6 +74,7 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES" + askForAppToLaunch = "Yes" launchAutomaticallySubstyle = "2"> diff --git a/LocalDevVPN/ContentView.swift b/LocalDevVPN/ContentView.swift index 34a41ba..884691a 100644 --- a/LocalDevVPN/ContentView.swift +++ b/LocalDevVPN/ContentView.swift @@ -17,7 +17,6 @@ extension Bundle { } // MARK: - Logging Utility - class VPNLogger: ObservableObject { @Published var logs: [String] = [] @@ -103,11 +102,11 @@ class TunnelManager: ObservableObject { case .disconnected: return "disconnected" case .connecting: - return "connecting" + return "connecting_ellipsis" case .connected: return "connected" case .disconnecting: - return "disconnecting" + return "disconnecting_ellipsis" case .error: return "error" } @@ -790,7 +789,7 @@ struct StatusOverviewCard: View { Text("current_status") .font(.headline) - HStack(spacing: 18) { + VStack(spacing: 18) { StatusGlyphView() Text(tunnelManager.tunnelStatus.localizedTitle) @@ -798,6 +797,12 @@ struct StatusOverviewCard: View { .fontWeight(.semibold) .multilineTextAlignment(.center) .frame(maxWidth: .infinity, alignment: .center) + + Text(localizedCaption) + .font(.caption) + .fontWeight(.regular) + .multilineTextAlignment(.center) + .frame(maxWidth: .infinity, alignment: .center) } Divider() @@ -814,8 +819,16 @@ struct StatusOverviewCard: View { Spacer() HStack(spacing: 4) { - Text("connected_at") - Text(Date(), style: .time) + if TunnelManager.shared.tunnelStatus == .connected { + Image(systemName: "clock") + Text("connected_at") + Text(Date(), style: .time) + } + else { + Image(systemName: "clock.arrow.trianglehead.counterclockwise.rotate.90") + Text("last_connected_at") + Text(Date(), style: .time) + } } .font(.caption) .foregroundColor(.secondary) @@ -838,11 +851,27 @@ struct StatusOverviewCard: View { return NSLocalizedString("tap_connect_to_create_the_tunnel", comment: "") } } + + private var localizedCaption: String { + switch tunnelManager.tunnelStatus { + case .disconnected: + return NSLocalizedString("disconnectedCaption", comment: "") + case .connecting: + return String(format: NSLocalizedString("connectingCaption", comment: ""), deviceIP) + case .connected: + return String(format: NSLocalizedString("connectedCaption", comment: ""), deviceIP) + case .disconnecting: + return String(format: NSLocalizedString("disconnectingCaption", comment: ""), deviceIP) + case .error: + return NSLocalizedString("errorCaption", comment: "") + } + } } struct StatusGlyphView: View { @StateObject private var tunnelManager = TunnelManager.shared @State private var ringScale: CGFloat = 1.0 + @AppStorage("enableAnimations") var enableAnimations = true var body: some View { ZStack { @@ -854,9 +883,17 @@ struct StatusGlyphView: View { Circle() .fill(tunnelManager.tunnelStatus.color.opacity(0.15)) - Image(systemName: tunnelManager.tunnelStatus.systemImage) - .font(.title) - .foregroundColor(tunnelManager.tunnelStatus.color) + if #available(iOS 18.0, *), enableAnimations{ + Image(systemName: tunnelManager.tunnelStatus.systemImage) + .font(.title) + .foregroundColor(tunnelManager.tunnelStatus.color) + .contentTransition(.symbolEffect(.replace)) + } + else{ + Image(systemName: tunnelManager.tunnelStatus.systemImage) + .font(.title) + .foregroundColor(tunnelManager.tunnelStatus.color) + } } .frame(width: 92, height: 92) .onAppear(perform: startPulse) @@ -876,7 +913,7 @@ struct ConnectivityControlsCard: View { DashboardCard { VStack(alignment: .leading, spacing: 18) { VStack(alignment: .leading, spacing: 4) { - Text("connection") + Label("connection", systemImage: "network.badge.shield.half.filled") .font(.headline) Text("start_or_stop_the_secure_local_tunnel") .font(.footnote) @@ -987,7 +1024,7 @@ struct ConnectionStatsView: View { DashboardCard { VStack(alignment: .leading, spacing: 12) { VStack(alignment: .leading, spacing: 3) { - Text("session_details") + Label("session_details", systemImage: "wifi.badge.lock") .font(.headline) Text("live_stats_while_the_tunnel_is_connected") .font(.footnote) @@ -1091,6 +1128,7 @@ struct SettingsView: View { @AppStorage("shownTunnelAlert") private var shownTunnelAlert = false @StateObject private var tunnelManager = TunnelManager.shared @AppStorage("hasNotCompletedSetup") private var hasNotCompletedSetup = true + @AppStorage("enableAnimations") var enableAnimations = true @State private var showNetworkWarning = false @State private var showRestartPopUp = false @@ -1112,6 +1150,49 @@ struct SettingsView: View { networkConfigRow(label: "subnet_mask", text: $subnetMask) } } + + Section(header: Text("language")) { + HStack{ + Image(systemName: "globe") + .foregroundColor(.blue) + Picker("dropdown_language", selection: $selectedLanguage) { + Text("english").tag("en") + Text("spanish").tag("es") + Text("italian").tag("it") + Text("polish").tag("pl") + Text("korean").tag("ko") + Text("TChinese").tag("zh-Hant") + Text("french").tag("fr") + } + } + .onChange(of: selectedLanguage) { newValue in + let languageCode = newValue + LanguageManager.shared.updateLanguage(to: languageCode) + showRestartPopUp = true + } + .alert(isPresented: $showRestartPopUp) { + Alert( + title: Text("restart_title"), + message: Text("restart_message"), + dismissButton: .cancel(Text("understand_button")) { + showRestartPopUp = true + } + ) + } + + if #available(iOS 18.0, *){ + Toggle("enable_animation", isOn: $enableAnimations) + } + else{ + VStack{ + Toggle("enable_animation", isOn: $enableAnimations) + .disabled(true) + Text("not_supported") + .font(.footnote) + .frame(alignment: .center) + } + } + } Section(header: Text("app_information")) { Button { @@ -1123,39 +1204,13 @@ struct SettingsView: View { Label("data_collection_policy", systemImage: "hand.raised.slash") } HStack { - Text("app_version") + Label("app_version", systemImage: "info") Spacer() Text(Bundle.main.shortVersion) .foregroundColor(.secondary) } NavigationLink(destination: HelpView()) { - Text("help_and_support") - } - } - - Section(header: Text("language")) { - Picker("dropdown_language", selection: $selectedLanguage) { - Text("english").tag("en") - Text("spanish").tag("es") - Text("italian").tag("it") - Text("polish").tag("pl") - Text("korean").tag("ko") - Text("TChinese").tag("zh-Hant") - Text("french").tag("fr") - } - .onChange(of: selectedLanguage) { newValue in - let languageCode = newValue - LanguageManager.shared.updateLanguage(to: languageCode) - showRestartPopUp = true - } - .alert(isPresented: $showRestartPopUp) { - Alert( - title: Text("restart_title"), - message: Text("restart_message"), - dismissButton: .cancel(Text("understand_button")) { - showRestartPopUp = true - } - ) + Label("help_and_support", systemImage: "questionmark.circle") } } } @@ -1267,11 +1322,41 @@ struct ConnectionLogView: View { } struct HelpView: View { + @State var startImageTransition : Bool = false + @AppStorage("enableAnimations") var enableAnimations = true + var body: some View { List { Section(header: Text("faq_header")) { NavigationLink("faq_q1") { VStack(alignment: .leading, spacing: 15) { + if #available(iOS 18.0, *), enableAnimations{ + Image(systemName: startImageTransition ? "network.badge.shield.half.filled" : "network") + .resizable() + .scaledToFit() + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(width: 100, height: 100) + .frame(maxWidth: .infinity, maxHeight: 200, alignment: .center) + .contentTransition(.symbolEffect(.replace.magic(fallback: .offUp.wholeSymbol), options: .nonRepeating)) + .onAppear{ + Task{ + try? await Task.sleep(for: .seconds(1)) + withAnimation{ + startImageTransition = true + } + } + } + .onDisappear{ + startImageTransition = false + } + } else { + Image(systemName: "network") + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(maxWidth: .infinity, alignment: .center) + .frame(maxHeight: 200, alignment: .center) + } Text("faq_q1_a1") .padding(.bottom, 10) Text("faq_common_use_cases") @@ -1285,6 +1370,31 @@ struct HelpView: View { } NavigationLink("faq_q2") { VStack(alignment: .leading, spacing: 15) { + if #available(iOS 18.0, *), enableAnimations{ + Image(systemName: startImageTransition ? "antenna.radiowaves.left.and.right.slash" : "antenna.radiowaves.left.and.right") + .resizable() + .scaledToFit() + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(width: 100, height: 100) + .frame(maxWidth: .infinity, maxHeight: 200, alignment: .center) + .contentTransition(.symbolEffect(.replace.magic(fallback: .offUp.wholeSymbol), options: .nonRepeating)) + .onAppear{ + Task{ + try? await Task.sleep(for: .seconds(1)) + startImageTransition = true + } + } + .onDisappear{ + startImageTransition = false + } + } else { + Image(systemName: "antenna.radiowaves.left.and.right.slash") + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(maxWidth: .infinity, alignment: .center) + .frame(maxHeight: 200, alignment: .center) + } Text("faq_q2_a1") .padding(.bottom, 10) .font(.headline) @@ -1299,6 +1409,28 @@ struct HelpView: View { } NavigationLink("faq_q3") { VStack(alignment: .leading, spacing: 15) { + if #available(iOS 18.0, *), enableAnimations{ + Image(systemName: startImageTransition ? "wifi.exclamationmark" : "wifi") + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(maxWidth: .infinity, maxHeight: 200, alignment: .center) + .contentTransition(.symbolEffect(.replace.magic(fallback: .offUp.wholeSymbol), options: .nonRepeating)) + .onAppear{ + Task{ + try? await Task.sleep(for: .seconds(1)) + startImageTransition = true + } + } + .onDisappear{ + startImageTransition = false + } + } else { + Image(systemName: "wifi.exclamationmark") + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(maxWidth: .infinity, alignment: .center) + .frame(maxHeight: 200, alignment: .center) + } Text("faq_q3_a1") .padding(.bottom, 10) Text("faq_troubleshoot_header") @@ -1312,6 +1444,28 @@ struct HelpView: View { } NavigationLink("faq_q4") { VStack(alignment: .leading, spacing: 15) { + if #available(iOS 18.0, *), enableAnimations { + Image(systemName: startImageTransition ? "apple.terminal.fill" : "hammer.fill") + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(maxWidth: .infinity, maxHeight: 200, alignment: .center) + .contentTransition(.symbolEffect(.replace.magic(fallback: .offUp.wholeSymbol), options: .nonRepeating)) + .onAppear{ + Task{ + try? await Task.sleep(for: .seconds(1)) + startImageTransition = true + } + } + .onDisappear{ + startImageTransition = false + } + } else { + Image(systemName: "apple.terminal.fill") + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(maxWidth: .infinity, alignment: .center) + .frame(maxHeight: 200, alignment: .center) + } Text("faq_q4_intro") .font(.headline) .padding(.bottom, 10) @@ -1328,6 +1482,28 @@ struct HelpView: View { Section(header: Text("business_model_header")) { NavigationLink("biz_q1") { VStack(alignment: .leading, spacing: 15) { + if #available(iOS 18.0, *), enableAnimations { + Image(systemName: startImageTransition ? "person.badge.shield.checkmark.fill" : "person.badge.clock.fill") + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(maxWidth: .infinity, maxHeight: 200, alignment: .center) + .contentTransition(.symbolEffect(.replace.magic(fallback: .offUp.wholeSymbol), options: .nonRepeating)) + .onAppear{ + Task{ + try? await Task.sleep(for: .seconds(1)) + startImageTransition = true + } + } + .onDisappear{ + startImageTransition = false + } + } else { + Image(systemName: "person.badge.shield.checkmark.fill") + .font(.system(size: 80)) + .foregroundColor(.blue) + .frame(maxWidth: .infinity, alignment: .center) + .frame(maxHeight: 200, alignment: .center) + } Text("biz_q1_a1") .padding(.bottom, 10) Text("biz_key_points_header") @@ -1342,14 +1518,10 @@ struct HelpView: View { } } Section(header: Text("app_info_header")) { - HStack { - Image(systemName: "exclamationmark.shield") - Text("requires_ios") - } - HStack { - Image(systemName: "lock.shield") - Text("uses_network_extension") - } + Label("requires_ios", systemImage: "exclamationmark.shield") + .foregroundColor(.black) + Label("uses_network_extension", systemImage: "lock.shield") + .foregroundColor(.black) } } .navigationTitle(Text("help_and_support_nav")) @@ -1365,25 +1537,29 @@ struct SetupView: View { SetupPage( title: "setup_welcome_title", description: "setup_welcome_description", - imageName: "checkmark.shield.fill", + transitionImage: "shield.fill", + standardImage: "checkmark.shield.fill", details: "setup_welcome_details" ), SetupPage( title: "setup_why_title", description: "setup_why_description", - imageName: "person.2.fill", + transitionImage: "person.2.shield", + standardImage: "person.2.fill", details: "setup_why_details" ), SetupPage( title: "setup_easy_title", description: "setup_easy_description", - imageName: "hand.tap.fill", + transitionImage: "hand.tap.fill", + standardImage: "hand.tap.fill", details: "setup_easy_details" ), SetupPage( title: "setup_privacy_title", description: "setup_privacy_description", - imageName: "lock.shield.fill", + transitionImage: "lock.open.fill", + standardImage: "lock.fill", details: "setup_privacy_details" ), ] @@ -1449,19 +1625,42 @@ struct SetupView: View { struct SetupPage { let title: LocalizedStringKey let description: LocalizedStringKey - let imageName: String + let transitionImage: String + let standardImage : String let details: LocalizedStringKey } struct SetupPageView: View { + @State var startImageTransition : Bool = false + @AppStorage("enableAnimations") var enableAnimations = true let page: SetupPage var body: some View { VStack(spacing: tvOSSpacing) { - Image(systemName: page.imageName) - .font(.system(size: tvOSImageSize)) - .foregroundColor(.blue) - .padding(.top, tvOSTopPadding) + if #available(iOS 18.0, *), enableAnimations{ + Image(systemName: (startImageTransition) ? page.standardImage : page.transitionImage) + .font(.system(size: tvOSImageSize)) + .foregroundColor(.blue) + .padding(.top, tvOSTopPadding) + .contentTransition(.symbolEffect(.replace)) + .onAppear{ + Task{ + try? await Task.sleep(for: .seconds(1)) + withAnimation{ + startImageTransition = true + } + } + } + .onDisappear{ + startImageTransition = false + } + } + else{ + Image(systemName: page.standardImage) + .font(.system(size: tvOSImageSize)) + .foregroundColor(.blue) + .padding(.top, tvOSTopPadding) + } Text(page.title) .font(tvOSTitleFont) diff --git a/LocalDevVPN/Localization/en.lproj/Localizable.strings b/LocalDevVPN/Localization/en.lproj/Localizable.strings index b08c6c0..8146859 100644 --- a/LocalDevVPN/Localization/en.lproj/Localizable.strings +++ b/LocalDevVPN/Localization/en.lproj/Localizable.strings @@ -3,16 +3,22 @@ "current_status" = "Current status"; "disconnected" = "Disconnected"; +"disconnectedCaption" = "Disconnected from the Tunnel."; "connecting" = "Connecting"; +"connectingCaption" = "Connecting to %@..."; "connected" = "Connected"; +"connectedCaption" = "Connected to %@."; "disconnecting" = "Disconnecting"; +"disconnectingCaption" = "Disconnecting from %@..."; "error" = "Error"; +"errorCaption" = "An unknown error occurred."; "local_tunnel_active" = "Local Tunnel Active"; "local_tunnel_inactive" = "Local Tunnel Inactive"; "connected_to_ip" = "Connected to %@"; -"connected_at" = "Connected at"; +"connected_at" = "Connected: "; +"last_connected_at" = "Last connection: "; "ios_might_ask_you_to_allow_the_vpn" = "iOS might ask you to allow the VPN"; "disconnecting_safely" = "Disconnecting safely…"; "open_settings_to_review_details" = "Open Settings to review details"; @@ -65,7 +71,7 @@ "data_collection_policy" = "Data Collection Policy"; "app_version" = "App Version"; "help_and_support" = "Help and Support"; -"language" = "Set Language"; +"language" = "Graphic Settings"; "dropdown_language" = "Language"; "settings" = "Settings"; "done" = "Done"; @@ -144,9 +150,11 @@ "setup_get_started" = "Get Started"; "setup_next" = "Next"; "setup_skip" = "Skip"; +"enable_animation" = "Enable Icon Animations"; +"not_supported" = "\nNot supported for your version of iOS (18.0 or later)."; /*MARK: Restart pop-up*/ "restart_title" = "Restart"; "restart_message" = "To apply the changes, you need to restart the application."; "confirmYes" = "Yes"; -"confirmNo" = "No"; \ No newline at end of file +"confirmNo" = "No"; diff --git a/LocalDevVPN/Localization/es.lproj/Localizable.strings b/LocalDevVPN/Localization/es.lproj/Localizable.strings index 0bc2a62..dc56cf1 100644 --- a/LocalDevVPN/Localization/es.lproj/Localizable.strings +++ b/LocalDevVPN/Localization/es.lproj/Localizable.strings @@ -12,7 +12,8 @@ "local_tunnel_inactive" = "Túnel local inactivo"; "connected_to_ip" = "Conectado a %@"; -"connected_at" = "Conectado a"; +"connected_at" = "Conectado: "; +"last_connected_at" = "Última conexión:"; "ios_might_ask_you_to_allow_the_vpn" = "iOS podría pedirte que permitas la VPN"; "disconnecting_safely" = "Desconectando de forma segura…"; "open_settings_to_review_details" = "Abre Configuración para revisar los detalles"; @@ -149,4 +150,4 @@ "restart_title" = "Reiniciar"; "restart_message" = "Para aplicar los cambios, es necesario reiniciar la aplicación."; "confirmYes" = "Sí"; -"confirmNo" = "No"; \ No newline at end of file +"confirmNo" = "No"; diff --git a/LocalDevVPN/Localization/fr.lproj/Localizable.strings b/LocalDevVPN/Localization/fr.lproj/Localizable.strings index 5836c8b..bfcff5e 100644 --- a/LocalDevVPN/Localization/fr.lproj/Localizable.strings +++ b/LocalDevVPN/Localization/fr.lproj/Localizable.strings @@ -12,7 +12,8 @@ "local_tunnel_inactive" = "Tunnel local inactif"; "connected_to_ip" = "Connecté à %@"; -"connected_at" = "Connecté à"; +"connected_at" = "Connecté:"; +"last_connected_at" = "Dernière connexion:"; "ios_might_ask_you_to_allow_the_vpn" = "iOS peut vous demander d'autoriser le VPN"; "disconnecting_safely" = "Déconnexion sécurisée en cours…"; "open_settings_to_review_details" = "Ouvrir les paramètres pour voir les détails"; @@ -150,4 +151,4 @@ "restart_title" = "Redémarrer"; "restart_message" = "Pour appliquer les modifications, vous devez redémarrer l'application."; "confirmYes" = "Oui"; -"confirmNo" = "Non"; \ No newline at end of file +"confirmNo" = "Non"; diff --git a/LocalDevVPN/Localization/it.lproj/Localizable.strings b/LocalDevVPN/Localization/it.lproj/Localizable.strings index 01a8ebf..73d9b71 100644 --- a/LocalDevVPN/Localization/it.lproj/Localizable.strings +++ b/LocalDevVPN/Localization/it.lproj/Localizable.strings @@ -3,16 +3,22 @@ "current_status" = "Stato attuale"; "disconnected" = "Disconnesso"; +"disconnectedCaption" = "Disconnesso dal Tunnel."; "connecting" = "Connessione in corso"; +"connectingCaption" = "Connessione a %@..."; "connected" = "Connesso"; +"connectedCaption" = "Connesso a %@."; "disconnecting" = "Disconnessione in corso"; +"disconnectingCaption" = "Disconnessione da %@..."; "error" = "Errore"; +"errorCaption" = "Si è verificato un errore sconosciuto."; "local_tunnel_active" = "Tunnel locale attivo"; "local_tunnel_inactive" = "Tunnel locale inattivo"; "connected_to_ip" = "Connesso a %@"; -"connected_at" = "Connesso a"; +"connected_at" = "Connesso:"; +"last_connected_at" = "Ultima connessione:"; "ios_might_ask_you_to_allow_the_vpn" = "iOS potrebbe chiederti di consentire la VPN"; "disconnecting_safely" = "Disconnessione in modo sicuro…"; "open_settings_to_review_details" = "Apri Impostazioni per visualizzare i dettagli"; @@ -65,7 +71,7 @@ "data_collection_policy" = "Politica di Raccolta Dati"; "app_version" = "Versione"; "help_and_support" = "Guida e Supporto"; -"language" = "Impostazioni Lingua"; +"language" = "Impostazioni Grafica"; "dropdown_language" = "Lingua"; "settings" = "Impostazioni"; "done" = "Fine"; @@ -127,7 +133,7 @@ "app_info_header" = "Informazioni App"; "requires_ios" = "Richiede iOS 14.0 o superiore"; "uses_network_extension" = "Usa le Network Extension API di Apple"; -"help_and_support_nav" = "Guida e Supporto"; +"help_and_support_nav" = "Guida & Supporto"; "setup_welcome_title" = "Benvenuto in LocalDevVPN"; "setup_welcome_description" = "Un semplice tunnel di rete locale per sviluppatori"; "setup_welcome_details" = "LocalDevVPN crea un'interfaccia di rete locale per sviluppo, test e accesso a server locali. Questa app NON raccoglie dati utente né instrada il traffico attraverso server esterni."; @@ -144,9 +150,11 @@ "setup_get_started" = "Inizia"; "setup_next" = "Avanti"; "setup_skip" = "Salta"; +"enable_animation" = "Attiva Animazioni Icone"; +"not_supported" = "\nNon supportate per la tua versione di iOS (18.0 o successivi)."; /*MARK: Restart pop-up*/ "restart_title" = "Riavvia"; "restart_message" = "Per applicare le modifiche, è necessario riavviare l'applicazione."; "confirmYes" = "Si"; -"confirmNo" = "No"; \ No newline at end of file +"confirmNo" = "No"; diff --git a/LocalDevVPN/Localization/ko.lproj/Localizable.strings b/LocalDevVPN/Localization/ko.lproj/Localizable.strings index be731a1..598ffba 100644 --- a/LocalDevVPN/Localization/ko.lproj/Localizable.strings +++ b/LocalDevVPN/Localization/ko.lproj/Localizable.strings @@ -12,7 +12,8 @@ "local_tunnel_inactive" = "로컬 터널 비활성화됨"; "connected_to_ip" = "%@에 연결됨"; -"connected_at" = "연결 시간 "; +"connected_at" = "연결됨:"; +"last_connected_at" = "마지막 접속:"; "ios_might_ask_you_to_allow_the_vpn" = "iOS에서 VPN 허용 요청이 나타날 수 있습니다"; "disconnecting_safely" = "안전하게 연결 해제 중…"; "open_settings_to_review_details" = "자세한 내용을 보려면 설정을 여세요"; @@ -150,4 +151,4 @@ "restart_title" = "재시작"; "restart_message" = "변경사항을 적용할려면 앱을 재시작해야 합니다."; "confirmYes" = "네"; -"confirmNo" = "아니요"; \ No newline at end of file +"confirmNo" = "아니요"; diff --git a/LocalDevVPN/Localization/pl.lproj/Localizable.strings b/LocalDevVPN/Localization/pl.lproj/Localizable.strings index f1b7f59..c04bb6b 100644 --- a/LocalDevVPN/Localization/pl.lproj/Localizable.strings +++ b/LocalDevVPN/Localization/pl.lproj/Localizable.strings @@ -12,7 +12,8 @@ "local_tunnel_inactive" = "Lokalny tunel nieaktywny"; "connected_to_ip" = "Połączono z %@"; -"connected_at" = "Połączono z "; +"connected_at" = "Powiązane:"; +"last_connected_at" = "Ostatnie połączenie:"; "ios_might_ask_you_to_allow_the_vpn" = "iOS może poprosić Cię o pozwolenie na VPN"; "disconnecting_safely" = "Bezpieczne rozłączanie…"; "open_settings_to_review_details" = "Otwórz Ustawienia, aby zobaczyć szczegóły"; @@ -150,4 +151,4 @@ "restart_title" = "Restartuj"; "restart_message" = "Aby zastosować zmiany, należy ponownie uruchomić aplikację."; "confirmYes" = "Tak"; -"confirmNo" = "Nie"; \ No newline at end of file +"confirmNo" = "Nie"; diff --git a/LocalDevVPN/Localization/zh-Hant.lproj/Localizable.strings b/LocalDevVPN/Localization/zh-Hant.lproj/Localizable.strings index 832dd82..a569c00 100644 --- a/LocalDevVPN/Localization/zh-Hant.lproj/Localizable.strings +++ b/LocalDevVPN/Localization/zh-Hant.lproj/Localizable.strings @@ -12,7 +12,8 @@ "local_tunnel_inactive" = "本地通道未啟動"; "connected_to_ip" = "已連接至 %@"; -"connected_at" = "連接於"; +"connected_at" = "相關:"; +"last_connected_at" = "最後一次連線:"; "ios_might_ask_you_to_allow_the_vpn" = "iOS可能會要求您允許VPN"; "disconnecting_safely" = "安全地中斷連線中…"; "open_settings_to_review_details" = "開啟設定以查看詳細資訊"; @@ -150,4 +151,4 @@ "restart_title" = "重新啟動"; "restart_message" = "要套用變更,必須重新啟動應用程式。"; "confirmYes" = "是"; -"confirmNo" = "不"; \ No newline at end of file +"confirmNo" = "不";