Files
simplex-chat/apps/ios/SimpleXChat/ErrorAlert.swift
T
+16 fb3357c638 ui: translations (#7275)
* ui: what's new in 7.0 (#7265)

* docs: add Hosting your own Chat Relay guide  (#7263)

* docs: add Hosting your own Chat Relay guide

* cli: run headless relay without a terminal

--headless (no -e) now runs via simplexChatCore instead of the terminal
UI, so the relay runs as a systemd service without a TTY (withTerminal
requires one). Drains the event queue logging only errors, and sets
stdout to line-buffering so logs reach the journal.

* docs/chat-relay: debounce service

* Apply suggestions from code review

Co-authored-by: Evgeny <evgeny@poberezkin.com>

---------

Co-authored-by: Evgeny <evgeny@poberezkin.com>

* Translated using Weblate (German)

Currently translated at 100.0% (2868 of 2868 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (Russian)

Currently translated at 96.5% (2381 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Russian)

Currently translated at 96.5% (2381 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (Russian)

Currently translated at 96.5% (2381 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/

* Translated using Weblate (French)

Currently translated at 93.6% (2309 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2868 of 2868 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.9% (2867 of 2868 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.6% (2431 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2868 of 2868 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* Translated using Weblate (Dutch)

Currently translated at 82.5% (2035 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/

* Translated using Weblate (Arabic)

Currently translated at 29.8% (735 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ar/

* Translated using Weblate (Ukrainian)

Currently translated at 87.0% (2145 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/

* Translated using Weblate (Polish)

Currently translated at 87.6% (2161 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/

* Translated using Weblate (Turkish)

Currently translated at 86.8% (2140 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/

* Translated using Weblate (Turkish)

Currently translated at 86.8% (2140 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (2868 of 2868 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (2868 of 2868 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2868 of 2868 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Indonesian)

Currently translated at 94.8% (2719 of 2868 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/id/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2867 of 2867 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (2867 of 2867 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/

* Translated using Weblate (German)

Currently translated at 100.0% (2880 of 2880 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2880 of 2880 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2880 of 2880 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (German)

Currently translated at 100.0% (2885 of 2885 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2885 of 2885 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.3% (2450 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/zh_Hans/

* Translated using Weblate (German)

Currently translated at 100.0% (2885 of 2885 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2885 of 2885 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.9% (2884 of 2885 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2885 of 2885 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2885 of 2885 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2885 of 2885 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2886 of 2886 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.9% (2885 of 2886 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2886 of 2886 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Italian)

Currently translated at 100.0% (2890 of 2890 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.9% (2889 of 2890 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (2890 of 2890 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/

* Translated using Weblate (Arabic)

Currently translated at 100.0% (2890 of 2890 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/

* Translated using Weblate (German)

Currently translated at 100.0% (2890 of 2890 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2890 of 2890 strings)

Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (2465 of 2465 strings)

Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/

* process translations

* restore and fix

* process xliff

* ui: fix translation typos and mistranslations (de, es, it, tr, hu, id, ar, zh-CN)

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Evgeny <evgeny@poberezkin.com>
Co-authored-by: mlanp <github@lang.xyz>
Co-authored-by: Pixelcode <pixelcode@dismail.de>
Co-authored-by: J R <jr@simplex.chat>
Co-authored-by: Evgeny Poberezkin <e.poberezkin@me.com>
Co-authored-by: Evgeny <ep@simplex.chat>
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Hosted Weblate user 54392 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: re me <jisizhang001@gmail.com>
Co-authored-by: No name <usir.alerts@onionmail.org>
Co-authored-by: M1K4 <oomikaoo@gmail.com>
Co-authored-by: Muhammad <muhammad.aem@outlook.com>
Co-authored-by: Max <worklmaksim@gmail.com>
Co-authored-by: B.O.S.S <BxOxSxS@protonmail.com>
Co-authored-by: Abdullah Koyuncu <wisewebworks@outlook.com>
Co-authored-by: Omer <abulomer2001@gmail.com>
Co-authored-by: echoloji <mehmetksm@tuta.io>
Co-authored-by: summoner001 <summoner@disroot.org>
Co-authored-by: Rafi <rafimuhmad90@protonmail.com>
Co-authored-by: BlacAmDK <BD1079259369@gmail.com>
Co-authored-by: jonnysemon <jonnysemon@users.noreply.hosted.weblate.org>
Co-authored-by: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com>
2026-07-18 20:33:10 +01:00

198 lines
8.9 KiB
Swift

//
// ErrorAlert.swift
// SimpleXChat
//
// Created by Levitating Pineapple on 20/07/2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
public struct ErrorAlert: Error {
public let title: LocalizedStringKey
public let message: LocalizedStringKey?
public init(
title: LocalizedStringKey,
message: LocalizedStringKey? = nil
) {
self.title = title
self.message = message
}
public init<A: View>(
title: LocalizedStringKey,
message: LocalizedStringKey? = nil,
@ViewBuilder actions: @escaping () -> A
) {
self.title = title
self.message = message
}
public init(_ title: LocalizedStringKey) {
self = ErrorAlert(title: title)
}
public init(_ error: any Error) {
self = if let chatError = error as? ChatError {
if let a = getNetworkErrorAlert(chatError) {
ErrorAlert(title: "\(a.title)", message: a.message.map { "\($0)" })
} else {
ErrorAlert("\(chatErrorString(chatError))")
}
} else {
ErrorAlert("\(error.localizedDescription)")
}
}
}
extension LocalizedStringKey: @unchecked Sendable { }
extension View {
/// Bridges ``ErrorAlert`` to the generic alert API.
/// - Parameters:
/// - errorAlert: Binding to the Error, which is rendered in the alert
/// - actions: View Builder containing action buttons.
/// System defaults to `Ok` dismiss error action, when no actions are provided.
/// System implicitly adds `Cancel` action, if a destructive action is present
///
/// - Returns: View, which displays ErrorAlert?, when set.
@ViewBuilder public func alert<A: View>(
_ errorAlert: Binding<ErrorAlert?>,
@ViewBuilder actions: (ErrorAlert) -> A = { _ in EmptyView() }
) -> some View {
alert(
errorAlert.wrappedValue?.title ?? "",
isPresented: Binding<Bool>(
get: { errorAlert.wrappedValue != nil },
set: { if !$0 { errorAlert.wrappedValue = nil } }
),
actions: {
if let alert = errorAlert.wrappedValue { actions(alert) }
},
message: {
if let message = errorAlert.wrappedValue?.message {
Text(message)
}
}
)
}
}
public func getNetworkErrorAlert(_ e: ChatError) -> (title: String, message: String?)? {
switch e {
case let .errorAgent(.BROKER(addr, .TIMEOUT)):
(
title: NSLocalizedString("Connection timeout", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Please check your network connection with %@ and try again.", comment: ""), serverHostname(addr))
)
case let .errorAgent(.BROKER(addr, .NETWORK(.unknownCAError))):
(
title: NSLocalizedString("Connection error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Fingerprint in server address does not match certificate: %@.", comment: ""), serverHostname(addr))
)
case let .errorAgent(.BROKER(addr, .NETWORK)):
(
title: NSLocalizedString("Connection error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Please check your network connection with %@ and try again.", comment: ""), serverHostname(addr))
)
case let .errorAgent(.BROKER(addr, .HOST)):
(
title: NSLocalizedString("Connection error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Server address is incompatible with network settings: %@.", comment: ""), serverHostname(addr))
)
case let .errorAgent(.BROKER(addr, .TRANSPORT(.version))):
(
title: NSLocalizedString("Connection error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Server version is incompatible with your app: %@.", comment: ""), serverHostname(addr))
)
case let .errorAgent(.SMP(serverAddress, .PROXY(proxyErr))):
smpProxyErrorAlert(proxyErr, serverAddress)
case let .errorAgent(.PROXY(proxyServer, relayServer, .protocolError(.PROXY(proxyErr)))):
proxyDestinationErrorAlert(proxyErr, proxyServer, relayServer)
default: nil
}
}
private func smpProxyErrorAlert(_ proxyErr: ProxyError, _ srvAddr: String) -> (title: String, message: String?)? {
switch proxyErr {
case .BROKER(brokerErr: .TIMEOUT):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Error connecting to forwarding server %@. Please try later.", comment: ""), serverHostname(srvAddr))
)
case .BROKER(brokerErr: .NETWORK(.unknownCAError)):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Fingerprint in forwarding server address does not match certificate: %@.", comment: ""), serverHostname(srvAddr))
)
case .BROKER(brokerErr: .NETWORK):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Error connecting to forwarding server %@. Please try later.", comment: ""), serverHostname(srvAddr))
)
case .BROKER(brokerErr: .HOST):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server address is incompatible with network settings: %@.", comment: ""), serverHostname(srvAddr))
)
case .BROKER(brokerErr: .TRANSPORT(.version)):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server version is incompatible with network settings: %@.", comment: ""), serverHostname(srvAddr))
)
default:
nil
}
}
private func proxyDestinationErrorAlert(_ proxyErr: ProxyError, _ proxyServer: String, _ relayServer: String) -> (title: String, message: String?)? {
switch proxyErr {
case .BROKER(brokerErr: .TIMEOUT):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server %@ failed to connect to destination server %@. Please try later.", comment: ""), serverHostname(proxyServer), serverHostname(relayServer))
)
case .BROKER(brokerErr: .NETWORK(.unknownCAError)):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Fingerprint in destination server address does not match certificate: %@.", comment: ""), serverHostname(relayServer))
)
case .BROKER(brokerErr: .NETWORK):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server %@ failed to connect to destination server %@. Please try later.", comment: ""), serverHostname(proxyServer), serverHostname(relayServer))
)
case .NO_SESSION:
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Forwarding server %@ failed to connect to destination server %@. Please try later.", comment: ""), serverHostname(proxyServer), serverHostname(relayServer))
)
case .BROKER(brokerErr: .HOST):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Destination server address of %1$@ is incompatible with forwarding server %2$@ settings.", comment: ""), serverHostname(relayServer), serverHostname(proxyServer))
)
case .BROKER(brokerErr: .TRANSPORT(.version)):
(
title: NSLocalizedString("Private routing error", comment: ""),
message: String.localizedStringWithFormat(NSLocalizedString("Destination server version of %1$@ is incompatible with forwarding server %2$@.", comment: ""), serverHostname(relayServer), serverHostname(proxyServer))
)
default:
nil
}
}
public func serverHostname(_ srv: String) -> String {
parseServerAddress(srv)?.hostnames.first ?? srv
}
public func mtrErrorDescription(_ err: MTRError) -> LocalizedStringKey {
switch err {
case let .noDown(dbMigrations):
"database version is newer than the app, but no down migration for: \(dbMigrations.joined(separator: ", "))"
case let .different(appMigration, dbMigration):
"different migration in the app/database: \(appMigration) / \(dbMigration)"
}
}