diff --git a/README.md b/README.md index 7e6e5d975d..40d552b84d 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ It is possible to donate via: - ETH: 0xD9ee7Db0AD0dc1Dfa7eD53290199ED06beA04692 - USDT (Ethereum): 0xD9ee7Db0AD0dc1Dfa7eD53290199ED06beA04692 - ZEC: t1fwjQW5gpFhDqXNhxqDWyF9j9WeKvVS5Jg +- ZEC shielded: u16rnvkflumf5uw9frngc2lymvmzgdr2mmc9unyu0l44unwfmdcpfm0axujd2w34ct3ye709azxsqge45705lpvvqu264ltzvfay55ygyq - DOGE: D99pV4n9TrPxBPCkQGx4w4SMSa6QjRBxPf - SOL: 7JCf5m3TiHmYKZVr6jCu1KeZVtb9Y1jRMQDU69p5ARnu - please ask if you want to donate any other coins. diff --git a/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/Contents.json b/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/Contents.json new file mode 100644 index 0000000000..cb29f09fe1 --- /dev/null +++ b/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "vertical_logo_x1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "vertical_logo_x2.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "vertical_logo_x3.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x1.png b/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x1.png new file mode 100644 index 0000000000..f916e43ea9 Binary files /dev/null and b/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x1.png differ diff --git a/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x2.png b/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x2.png new file mode 100644 index 0000000000..bb35878f0c Binary files /dev/null and b/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x2.png differ diff --git a/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x3.png b/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x3.png new file mode 100644 index 0000000000..c55f481b36 Binary files /dev/null and b/apps/ios/Shared/Assets.xcassets/vertical_logo.imageset/vertical_logo_x3.png differ diff --git a/apps/ios/Shared/ContentView.swift b/apps/ios/Shared/ContentView.swift index e8b494724a..2ad8d546f2 100644 --- a/apps/ios/Shared/ContentView.swift +++ b/apps/ios/Shared/ContentView.swift @@ -74,7 +74,7 @@ struct ContentView: View { } } - @ViewBuilder func allViews() -> some View { + func allViews() -> some View { ZStack { let showCallArea = chatModel.activeCall != nil && chatModel.activeCall?.callState != .waitCapabilities && chatModel.activeCall?.callState != .invitationAccepted // contentView() has to be in a single branch, so that enabling authentication doesn't trigger re-rendering and close settings. @@ -209,7 +209,7 @@ struct ContentView: View { } } - @ViewBuilder private func activeCallInteractiveArea(_ call: Call) -> some View { + private func activeCallInteractiveArea(_ call: Call) -> some View { HStack { Text(call.contact.displayName).font(.body).foregroundColor(.white) Spacer() diff --git a/apps/ios/Shared/Model/AppAPITypes.swift b/apps/ios/Shared/Model/AppAPITypes.swift index fd89026cfe..3bf4cb7b56 100644 --- a/apps/ios/Shared/Model/AppAPITypes.swift +++ b/apps/ios/Shared/Model/AppAPITypes.swift @@ -1413,22 +1413,6 @@ enum NotificationsMode: String, Decodable, SelectableItem { static var values: [NotificationsMode] = [.instant, .periodic, .off] } -enum PrivacyChatListOpenLinksMode: String, CaseIterable, Codable, RawRepresentable, Identifiable { - case yes - case no - case ask - - var id: Self { self } - - var text: LocalizedStringKey { - switch self { - case .yes: return "Yes" - case .no: return "No" - case .ask: return "Ask" - } - } -} - struct RemoteCtrlInfo: Decodable { var remoteCtrlId: Int64 var ctrlDeviceName: String @@ -1941,7 +1925,6 @@ struct AppSettings: Codable, Equatable { var privacyAskToApproveRelays: Bool? = nil var privacyAcceptImages: Bool? = nil var privacyLinkPreviews: Bool? = nil - var privacyChatListOpenLinks: PrivacyChatListOpenLinksMode? = nil var privacyShowChatPreviews: Bool? = nil var privacySaveLastDraft: Bool? = nil var privacyProtectScreen: Bool? = nil @@ -1977,7 +1960,6 @@ struct AppSettings: Codable, Equatable { if privacyAskToApproveRelays != def.privacyAskToApproveRelays { empty.privacyAskToApproveRelays = privacyAskToApproveRelays } if privacyAcceptImages != def.privacyAcceptImages { empty.privacyAcceptImages = privacyAcceptImages } if privacyLinkPreviews != def.privacyLinkPreviews { empty.privacyLinkPreviews = privacyLinkPreviews } - if privacyChatListOpenLinks != def.privacyChatListOpenLinks { empty.privacyChatListOpenLinks = privacyChatListOpenLinks } if privacyShowChatPreviews != def.privacyShowChatPreviews { empty.privacyShowChatPreviews = privacyShowChatPreviews } if privacySaveLastDraft != def.privacySaveLastDraft { empty.privacySaveLastDraft = privacySaveLastDraft } if privacyProtectScreen != def.privacyProtectScreen { empty.privacyProtectScreen = privacyProtectScreen } @@ -2014,7 +1996,6 @@ struct AppSettings: Codable, Equatable { privacyAskToApproveRelays: true, privacyAcceptImages: true, privacyLinkPreviews: true, - privacyChatListOpenLinks: .ask, privacyShowChatPreviews: true, privacySaveLastDraft: true, privacyProtectScreen: false, diff --git a/apps/ios/Shared/Views/Call/ActiveCallView.swift b/apps/ios/Shared/Views/Call/ActiveCallView.swift index 7c8996a99b..ab7a47b944 100644 --- a/apps/ios/Shared/Views/Call/ActiveCallView.swift +++ b/apps/ios/Shared/Views/Call/ActiveCallView.swift @@ -467,7 +467,7 @@ struct ActiveCallOverlay: View { .disabled(call.initialCallType == .audio && client.activeCall?.peerHasOldVersion == true) } - @ViewBuilder private func flipCameraButton() -> some View { + private func flipCameraButton() -> some View { controlButton(call, "arrow.triangle.2.circlepath", padding: 12) { Task { if await WebRTCClient.isAuthorized(for: .video) { @@ -477,11 +477,11 @@ struct ActiveCallOverlay: View { } } - @ViewBuilder private func controlButton(_ call: Call, _ imageName: String, padding: CGFloat, _ perform: @escaping () -> Void) -> some View { + private func controlButton(_ call: Call, _ imageName: String, padding: CGFloat, _ perform: @escaping () -> Void) -> some View { callButton(imageName, call.peerMediaSources.hasVideo ? Color.black.opacity(0.2) : Color.white.opacity(0.2), padding: padding, perform) } - @ViewBuilder private func audioDevicePickerButton() -> some View { + private func audioDevicePickerButton() -> some View { AudioDevicePicker() .opacity(0.8) .scaleEffect(2) diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CICallItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CICallItemView.swift index 3b3e1b3899..0283e9c07e 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CICallItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CICallItemView.swift @@ -50,7 +50,7 @@ struct CICallItemView: View { Image(systemName: "phone.connection").foregroundColor(.green) } - @ViewBuilder private func endedCallIcon(_ sent: Bool) -> some View { + private func endedCallIcon(_ sent: Bool) -> some View { HStack { Image(systemName: "phone.down") Text(durationText(duration)).foregroundColor(theme.colors.secondary) @@ -60,16 +60,16 @@ struct CICallItemView: View { @ViewBuilder private func acceptCallButton() -> some View { if case let .direct(contact) = chat.chatInfo { - Button { - if let invitation = m.callInvitations[contact.id] { - CallController.shared.answerCall(invitation: invitation) - logger.debug("acceptCallButton call answered") - } else { - AlertManager.shared.showAlertMsg(title: "Call already ended!") - } - } label: { - Label("Answer call", systemImage: "phone.arrow.down.left") - } + Label("Answer call", systemImage: "phone.arrow.down.left") + .foregroundColor(theme.colors.primary) + .simultaneousGesture(TapGesture().onEnded { + if let invitation = m.callInvitations[contact.id] { + CallController.shared.answerCall(invitation: invitation) + logger.debug("acceptCallButton call answered") + } else { + AlertManager.shared.showAlertMsg(title: "Call already ended!") + } + }) } else { Image(systemName: "phone.arrow.down.left").foregroundColor(theme.colors.secondary) } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIFeaturePreferenceView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIFeaturePreferenceView.swift index 2c9c261536..67f7b69e2c 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIFeaturePreferenceView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIFeaturePreferenceView.swift @@ -26,9 +26,9 @@ struct CIFeaturePreferenceView: View { allowed != .no && ct.allowsFeature(feature) && !ct.userAllowsFeature(feature) { let setParam = feature == .timedMessages && ct.mergedPreferences.timedMessages.userPreference.preference.ttl == nil featurePreferenceView(acceptText: setParam ? "Set 1 day" : "Accept") - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { allowFeatureToContact(ct, feature, param: setParam ? 86400 : nil) - } + }) } else { featurePreferenceView() } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift index bc44afdd7f..b0b404d8b5 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift @@ -19,42 +19,42 @@ struct CIFileView: View { var body: some View { if smallViewSize != nil { fileIndicator() - .onTapGesture(perform: fileAction) + .simultaneousGesture(TapGesture().onEnded(fileAction)) } else { let metaReserve = edited ? " " : " " - Button(action: fileAction) { - HStack(alignment: .bottom, spacing: 6) { - fileIndicator() - .padding(.top, 5) - .padding(.bottom, 3) - if let file = file { - let prettyFileSize = ByteCountFormatter.string(fromByteCount: file.fileSize, countStyle: .binary) - VStack(alignment: .leading, spacing: 2) { - Text(file.fileName) - .lineLimit(1) - .multilineTextAlignment(.leading) - .foregroundColor(theme.colors.onBackground) - Text(prettyFileSize + metaReserve) - .font(.caption) - .lineLimit(1) - .multilineTextAlignment(.leading) - .foregroundColor(theme.colors.secondary) - } - } else { - Text(metaReserve) + HStack(alignment: .bottom, spacing: 6) { + fileIndicator() + .padding(.top, 5) + .padding(.bottom, 3) + if let file = file { + let prettyFileSize = ByteCountFormatter.string(fromByteCount: file.fileSize, countStyle: .binary) + VStack(alignment: .leading, spacing: 2) { + Text(file.fileName) + .lineLimit(1) + .multilineTextAlignment(.leading) + .foregroundColor(theme.colors.onBackground) + Text(prettyFileSize + metaReserve) + .font(.caption) + .lineLimit(1) + .multilineTextAlignment(.leading) + .foregroundColor(theme.colors.secondary) } + } else { + Text(metaReserve) } - .padding(.top, 4) - .padding(.bottom, 6) - .padding(.leading, 10) - .padding(.trailing, 12) } + .padding(.top, 4) + .padding(.bottom, 6) + .padding(.leading, 10) + .padding(.trailing, 12) + .simultaneousGesture(TapGesture().onEnded(fileAction)) .disabled(!itemInteractive) } } + @inline(__always) private var itemInteractive: Bool { if let file = file { switch (file.fileStatus) { diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift index 107208a033..3fcf578875 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift @@ -84,12 +84,12 @@ struct CIGroupInvitationView: View { } if action { - v.onTapGesture { + v.simultaneousGesture(TapGesture().onEnded { inProgress = true joinGroup(groupInvitation.groupId) { await MainActor.run { inProgress = false } } - } + }) .disabled(inProgress) } else { v diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift index 4c8221d887..d30369339d 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift @@ -31,7 +31,9 @@ struct CIImageView: View { .if(!smallView) { view in view.modifier(PrivacyBlur(blurred: $blurred)) } - .onTapGesture { showFullScreenImage = true } + .if(!blurred) { v in + v.simultaneousGesture(TapGesture().onEnded { showFullScreenImage = true }) + } .onChange(of: m.activeCallViewIsCollapsed) { _ in showFullScreenImage = false } @@ -43,7 +45,7 @@ struct CIImageView: View { imageView(preview).modifier(PrivacyBlur(blurred: $blurred)) } } - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { if let file = file { switch file.fileStatus { case .rcvInvitation, .rcvAborted: @@ -80,7 +82,7 @@ struct CIImageView: View { default: () } } - } + }) } } .onDisappear { diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIInvalidJSONView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIInvalidJSONView.swift index 918d8f9449..5e9fa691de 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIInvalidJSONView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIInvalidJSONView.swift @@ -24,7 +24,7 @@ struct CIInvalidJSONView: View { .padding(.vertical, 6) .background(Color(uiColor: .tertiarySystemGroupedBackground)) .textSelection(.disabled) - .onTapGesture { showJSON = true } + .simultaneousGesture(TapGesture().onEnded { showJSON = true }) .appSheet(isPresented: $showJSON) { invalidJSONView(dataToString(json)) } @@ -33,7 +33,7 @@ struct CIInvalidJSONView: View { func invalidJSONView(_ json: String) -> some View { VStack(alignment: .leading, spacing: 16) { - Button { + Button { // this is used in the sheet, Button works here showShareSheet(items: [json]) } label: { Image(systemName: "square.and.arrow.up") diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift index 692e6bb8a6..f9dbaede63 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CILinkView.swift @@ -21,15 +21,15 @@ struct CILinkView: View { .resizable() .scaledToFit() .modifier(PrivacyBlur(blurred: $blurred)) + .if(!blurred) { v in + v.simultaneousGesture(TapGesture().onEnded { + openBrowserAlert(uri: linkPreview.uri) + }) + } } VStack(alignment: .leading, spacing: 6) { Text(linkPreview.title) .lineLimit(3) -// if linkPreview.description != "" { -// Text(linkPreview.description) -// .font(.subheadline) -// .lineLimit(12) -// } Text(linkPreview.uri.absoluteString) .font(.caption) .lineLimit(1) @@ -37,10 +37,32 @@ struct CILinkView: View { } .padding(.horizontal, 12) .frame(maxWidth: .infinity, alignment: .leading) + .simultaneousGesture(TapGesture().onEnded { + openBrowserAlert(uri: linkPreview.uri) + }) } } } +func openBrowserAlert(uri: URL) { + showAlert( + NSLocalizedString("Open link?", comment: "alert title"), + message: uri.absoluteString, + actions: {[ + UIAlertAction( + title: NSLocalizedString("Cancel", comment: "alert action"), + style: .default, + handler: { _ in } + ), + UIAlertAction( + title: NSLocalizedString("Open", comment: "alert action"), + style: .default, + handler: { _ in UIApplication.shared.open(uri) } + ) + ]} + ) +} + struct LargeLinkPreview_Previews: PreviewProvider { static var previews: some View { let preview = LinkPreview( diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIMemberCreatedContactView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIMemberCreatedContactView.swift index e49e99c77e..2898a318a9 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIMemberCreatedContactView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIMemberCreatedContactView.swift @@ -20,11 +20,11 @@ struct CIMemberCreatedContactView: View { case let .groupRcv(groupMember): if let contactId = groupMember.memberContactId { memberCreatedContactView(openText: "Open") - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { ItemsModel.shared.loadOpenChat("@\(contactId)") { dismissAllSheets(animated: true) } - } + }) } else { memberCreatedContactView() } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift index e58ad0f74e..fc73778239 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIMetaView.swift @@ -15,7 +15,7 @@ struct CIMetaView: View { @Environment(\.showTimestamp) var showTimestamp: Bool var chatItem: ChatItem var metaColor: Color - var paleMetaColor = Color(UIColor.tertiaryLabel) + var paleMetaColor = Color(uiColor: .tertiaryLabel) var showStatus = true var showEdited = true var invertedMaterial = false @@ -152,11 +152,13 @@ func ciMetaText( return r.font(.caption) } +@inline(__always) private func statusIconText(_ icon: String, _ color: Color?) -> Text { colored(Text(Image(systemName: icon)), color) } // Applying `foregroundColor(nil)` breaks `.invertedForegroundStyle` modifier +@inline(__always) private func colored(_ t: Text, _ color: Color?) -> Text { if let color { t.foregroundColor(color) diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIRcvDecryptionError.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIRcvDecryptionError.swift index 6920ab999b..4e5713c263 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIRcvDecryptionError.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIRcvDecryptionError.swift @@ -68,7 +68,7 @@ struct CIRcvDecryptionError: View { } } - @ViewBuilder private func viewBody() -> some View { + private func viewBody() -> some View { Group { if case let .direct(contact) = chat.chatInfo, let contactStats = contact.activeConn?.connectionStats { @@ -133,7 +133,7 @@ struct CIRcvDecryptionError: View { CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary) .padding(.horizontal, 12) } - .onTapGesture(perform: { onClick() }) + .simultaneousGesture(TapGesture().onEnded(onClick)) .padding(.vertical, 6) .textSelection(.disabled) } @@ -151,7 +151,7 @@ struct CIRcvDecryptionError: View { CIMetaView(chat: chat, chatItem: chatItem, metaColor: theme.colors.secondary) .padding(.horizontal, 12) } - .onTapGesture(perform: { onClick() }) + .simultaneousGesture(TapGesture().onEnded(onClick)) .padding(.vertical, 6) .textSelection(.disabled) } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift index f774299ad3..eacbe9360a 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIVideoView.swift @@ -47,57 +47,57 @@ struct CIVideoView: View { let file = chatItem.file ZStack(alignment: smallView ? .topLeading : .center) { ZStack(alignment: .topLeading) { - if let file = file, let preview = preview, let decrypted = urlDecrypted, smallView { - smallVideoView(decrypted, file, preview) - } else if let file = file, let preview = preview, let player = player, let decrypted = urlDecrypted { - videoView(player, decrypted, file, preview, duration) - } else if let file = file, let defaultPreview = preview, file.loaded && urlDecrypted == nil, smallView { - smallVideoViewEncrypted(file, defaultPreview) - } else if let file = file, let defaultPreview = preview, file.loaded && urlDecrypted == nil { - videoViewEncrypted(file, defaultPreview, duration) - } else if let preview, let file { - Group { if smallView { smallViewImageView(preview, file) } else { imageView(preview) } } - .onTapGesture { - switch file.fileStatus { - case .rcvInvitation, .rcvAborted: - receiveFileIfValidSize(file: file, receiveFile: receiveFile) - case .rcvAccepted: - switch file.fileProtocol { - case .xftp: - AlertManager.shared.showAlertMsg( - title: "Waiting for video", - message: "Video will be received when your contact completes uploading it." - ) - case .smp: - AlertManager.shared.showAlertMsg( - title: "Waiting for video", - message: "Video will be received when your contact is online, please wait or check later!" - ) - case .local: () - } - case .rcvTransfer: () // ? - case .rcvComplete: () // ? - case .rcvCancelled: () // TODO - default: () - } + if let file, let preview { + if let urlDecrypted { + if smallView { + smallVideoView(urlDecrypted, file, preview) + } else if let player { + videoView(player, urlDecrypted, file, preview, duration) } + } else if file.loaded { + if smallView { + smallVideoViewEncrypted(file, preview) + } else { + videoViewEncrypted(file, preview, duration) + } + } else { + Group { if smallView { smallViewImageView(preview, file) } else { imageView(preview) } } + .simultaneousGesture(TapGesture().onEnded { + switch file.fileStatus { + case .rcvInvitation, .rcvAborted: + receiveFileIfValidSize(file: file, receiveFile: receiveFile) + case .rcvAccepted: + switch file.fileProtocol { + case .xftp: + AlertManager.shared.showAlertMsg( + title: "Waiting for video", + message: "Video will be received when your contact completes uploading it." + ) + case .smp: + AlertManager.shared.showAlertMsg( + title: "Waiting for video", + message: "Video will be received when your contact is online, please wait or check later!" + ) + case .local: () + } + case .rcvTransfer: () // ? + case .rcvComplete: () // ? + case .rcvCancelled: () // TODO + default: () + } + }) + } } if !smallView { durationProgress() } } if !blurred, let file, showDownloadButton(file.fileStatus) { - if !smallView { - Button { - receiveFileIfValidSize(file: file, receiveFile: receiveFile) - } label: { - playPauseIcon("play.fill") - } - } else if !file.showStatusIconInSmallView { + if !smallView || !file.showStatusIconInSmallView { playPauseIcon("play.fill") - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { receiveFileIfValidSize(file: file, receiveFile: receiveFile) - } + }) } } } @@ -151,27 +151,26 @@ struct CIVideoView: View { ZStack(alignment: .center) { let canBePlayed = !chatItem.chatDir.sent || file.fileStatus == CIFileStatus.sndComplete || (file.fileStatus == .sndStored && file.fileProtocol == .local) imageView(defaultPreview) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { decrypt(file: file) { showFullScreenPlayer = urlDecrypted != nil } - } + }) .onChange(of: m.activeCallViewIsCollapsed) { _ in showFullScreenPlayer = false } if !blurred { if !decryptionInProgress { - Button { - decrypt(file: file) { - if urlDecrypted != nil { - videoPlaying = true - player?.play() + playPauseIcon(canBePlayed ? "play.fill" : "play.slash") + .simultaneousGesture(TapGesture().onEnded { + decrypt(file: file) { + if urlDecrypted != nil { + videoPlaying = true + player?.play() + } } - } - } label: { - playPauseIcon(canBePlayed ? "play.fill" : "play.slash") - } - .disabled(!canBePlayed) + }) + .disabled(!canBePlayed) } else { videoDecryptionProgress() } @@ -194,29 +193,30 @@ struct CIVideoView: View { } } .modifier(PrivacyBlur(enabled: !videoPlaying, blurred: $blurred)) - .onTapGesture { - switch player.timeControlStatus { - case .playing: - player.pause() - videoPlaying = false - case .paused: - if canBePlayed { - showFullScreenPlayer = true + .if(!blurred) { v in + v.simultaneousGesture(TapGesture().onEnded { + switch player.timeControlStatus { + case .playing: + player.pause() + videoPlaying = false + case .paused: + if canBePlayed { + showFullScreenPlayer = true + } + default: () } - default: () - } + }) } .onChange(of: m.activeCallViewIsCollapsed) { _ in showFullScreenPlayer = false } if !videoPlaying && !blurred { - Button { - m.stopPreviousRecPlay = url - player.play() - } label: { - playPauseIcon(canBePlayed ? "play.fill" : "play.slash") - } - .disabled(!canBePlayed) + playPauseIcon(canBePlayed ? "play.fill" : "play.slash") + .simultaneousGesture(TapGesture().onEnded { + m.stopPreviousRecPlay = url + player.play() + }) + .disabled(!canBePlayed) } } fileStatusIcon() @@ -235,7 +235,7 @@ struct CIVideoView: View { return ZStack(alignment: .topLeading) { let canBePlayed = !chatItem.chatDir.sent || file.fileStatus == CIFileStatus.sndComplete || (file.fileStatus == .sndStored && file.fileProtocol == .local) smallViewImageView(preview, file) - .onTapGesture { + .onTapGesture { // this is shown in chat list, where onTapGesture works decrypt(file: file) { showFullScreenPlayer = urlDecrypted != nil } @@ -256,7 +256,7 @@ struct CIVideoView: View { private func smallVideoView(_ url: URL, _ file: CIFile, _ preview: UIImage) -> some View { return ZStack(alignment: .topLeading) { smallViewImageView(preview, file) - .onTapGesture { + .onTapGesture { // this is shown in chat list, where onTapGesture works showFullScreenPlayer = true } .onChange(of: m.activeCallViewIsCollapsed) { _ in @@ -354,14 +354,14 @@ struct CIVideoView: View { case .sndCancelled: fileIcon("xmark", 10, 13) case let .sndError(sndFileError): fileIcon("xmark", 10, 13) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { showFileErrorAlert(sndFileError) - } + }) case let .sndWarning(sndFileError): fileIcon("exclamationmark.triangle.fill", 10, 13) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { showFileErrorAlert(sndFileError, temporary: true) - } + }) case .rcvInvitation: fileIcon("arrow.down", 10, 13) case .rcvAccepted: fileIcon("ellipsis", 14, 11) case let .rcvTransfer(rcvProgress, rcvTotal): @@ -375,14 +375,14 @@ struct CIVideoView: View { case .rcvCancelled: fileIcon("xmark", 10, 13) case let .rcvError(rcvFileError): fileIcon("xmark", 10, 13) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { showFileErrorAlert(rcvFileError) - } + }) case let .rcvWarning(rcvFileError): fileIcon("exclamationmark.triangle.fill", 10, 13) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { showFileErrorAlert(rcvFileError, temporary: true) - } + }) case .invalid: fileIcon("questionmark", 10, 13) } } @@ -429,7 +429,7 @@ struct CIVideoView: View { Color.black.edgesIgnoringSafeArea(.all) VideoPlayer(player: fullPlayer) .overlay(alignment: .topLeading, content: { - Button(action: { showFullScreenPlayer = false }, + Button(action: { showFullScreenPlayer = false }, // this is used in full screen player, Button works here label: { Image(systemName: "multiply") .resizable() diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIVoiceView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIVoiceView.swift index e2fec02ba1..715e606a74 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIVoiceView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIVoiceView.swift @@ -168,14 +168,14 @@ struct VoiceMessagePlayer: View { case .sndCancelled: playbackButton() case let .sndError(sndFileError): fileStatusIcon("multiply", 14) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { showFileErrorAlert(sndFileError) - } + }) case let .sndWarning(sndFileError): fileStatusIcon("exclamationmark.triangle.fill", 16) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { showFileErrorAlert(sndFileError, temporary: true) - } + }) case .rcvInvitation: downloadButton(recordingFile, "play.fill") case .rcvAccepted: loadingIcon() case .rcvTransfer: loadingIcon() @@ -184,14 +184,14 @@ struct VoiceMessagePlayer: View { case .rcvCancelled: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel)) case let .rcvError(rcvFileError): fileStatusIcon("multiply", 14) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { showFileErrorAlert(rcvFileError) - } + }) case let .rcvWarning(rcvFileError): fileStatusIcon("exclamationmark.triangle.fill", 16) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { showFileErrorAlert(rcvFileError, temporary: true) - } + }) case .invalid: playPauseIcon("play.fill", Color(uiColor: .tertiaryLabel)) } } else { @@ -255,59 +255,29 @@ struct VoiceMessagePlayer: View { } } - @ViewBuilder private func playbackButton() -> some View { - if sizeMultiplier != 1 { - switch playbackState { - case .noPlayback: - playPauseIcon("play.fill", theme.colors.primary) - .onTapGesture { - if let recordingSource = getLoadedFileSource(recordingFile) { - startPlayback(recordingSource) - } - } - case .playing: - playPauseIcon("pause.fill", theme.colors.primary) - .onTapGesture { - audioPlayer?.pause() - playbackState = .paused - notifyStateChange() - } - case .paused: - playPauseIcon("play.fill", theme.colors.primary) - .onTapGesture { - audioPlayer?.play() - playbackState = .playing - notifyStateChange() - } - } - } else { - switch playbackState { - case .noPlayback: - Button { + private func playbackButton() -> some View { + let icon = switch playbackState { + case .noPlayback: "play.fill" + case .playing: "pause.fill" + case .paused: "play.fill" + } + return playPauseIcon(icon, theme.colors.primary) + .simultaneousGesture(TapGesture().onEnded { _ in + switch playbackState { + case .noPlayback: if let recordingSource = getLoadedFileSource(recordingFile) { startPlayback(recordingSource) } - } label: { - playPauseIcon("play.fill", theme.colors.primary) - } - case .playing: - Button { + case .playing: audioPlayer?.pause() playbackState = .paused notifyStateChange() - } label: { - playPauseIcon("pause.fill", theme.colors.primary) - } - case .paused: - Button { + case .paused: audioPlayer?.play() playbackState = .playing notifyStateChange() - } label: { - playPauseIcon("play.fill", theme.colors.primary) } - } - } + }) } private func playPauseIcon(_ image: String, _ color: Color/* = .accentColor*/) -> some View { @@ -329,28 +299,14 @@ struct VoiceMessagePlayer: View { } private func downloadButton(_ recordingFile: CIFile, _ icon: String) -> some View { - Group { - if sizeMultiplier != 1 { - playPauseIcon(icon, theme.colors.primary) - .onTapGesture { - Task { - if let user = chatModel.currentUser { - await receiveFile(user: user, fileId: recordingFile.fileId) - } - } + playPauseIcon(icon, theme.colors.primary) + .simultaneousGesture(TapGesture().onEnded { + Task { + if let user = chatModel.currentUser { + await receiveFile(user: user, fileId: recordingFile.fileId) } - } else { - Button { - Task { - if let user = chatModel.currentUser { - await receiveFile(user: user, fileId: recordingFile.fileId) - } - } - } label: { - playPauseIcon(icon, theme.colors.primary) } - } - } + }) } func notifyStateChange() { @@ -430,6 +386,7 @@ struct VoiceMessagePlayer: View { } } +@inline(__always) func voiceMessageSizeBasedOnSquareSize(_ squareSize: CGFloat) -> CGFloat { let squareToCircleRatio = 0.935 return squareSize + squareSize * (1 - squareToCircleRatio) @@ -446,10 +403,12 @@ class VoiceItemState { self.playbackTime = playbackTime } + @inline(__always) static func id(_ chat: Chat, _ chatItem: ChatItem) -> String { "\(chat.id) \(chatItem.id)" } + @inline(__always) static func id(_ chatInfo: ChatInfo, _ chatItem: ChatItem) -> String { "\(chatInfo.id) \(chatItem.id)" } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift index e411befbfa..b27d266d8a 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift @@ -23,8 +23,6 @@ struct FramedItemView: View { @State private var useWhiteMetaColor: Bool = false @State var showFullScreenImage = false @Binding var allowMenu: Bool - @State private var showSecrets = false - @State private var showQuoteSecrets = false @State private var showFullscreenGallery: Bool = false var body: some View { @@ -57,7 +55,7 @@ struct FramedItemView: View { if let qi = chatItem.quotedItem { ciQuoteView(qi) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { if let ci = ItemsModel.shared.reversedChatItems.first(where: { $0.id == qi.itemId }) { withAnimation { scrollToItemId(ci.id) @@ -67,7 +65,7 @@ struct FramedItemView: View { } else { showQuotedItemDoesNotExistAlert() } - } + }) } else if let itemForwarded = chatItem.meta.itemForwarded { framedItemHeader(icon: "arrowshape.turn.up.forward", caption: Text(itemForwarded.text(chat.chatInfo.chatType)).italic(), pad: true) } @@ -89,19 +87,19 @@ struct FramedItemView: View { .overlay(DetermineWidth()) .accessibilityLabel("") } - } + } .background { chatItemFrameColorMaybeImageOrVideo(chatItem, theme).modifier(ChatTailPadding()) } .onPreferenceChange(DetermineWidth.Key.self) { msgWidth = $0 } if let (title, text) = chatItem.meta.itemStatus.statusInfo { - v.onTapGesture { + v.simultaneousGesture(TapGesture().onEnded { AlertManager.shared.showAlert( Alert( title: Text(title), message: Text(text) ) ) - } + }) } else { v } @@ -159,7 +157,7 @@ struct FramedItemView: View { case let .file(text): ciFileView(chatItem, text) case let .report(text, reason): - ciMsgContentView(chatItem, Text(text.isEmpty ? reason.text : "\(reason.text): ").italic().foregroundColor(.red)) + ciMsgContentView(chatItem, txtPrefix: reason.attrString) case let .link(_, preview): CILinkView(linkPreview: preview) ciMsgContentView(chatItem) @@ -203,6 +201,7 @@ struct FramedItemView: View { } @ViewBuilder private func ciQuoteView(_ qi: CIQuote) -> some View { + let backgroundColor = chatItemFrameContextColor(chatItem, theme) let v = ZStack(alignment: .topTrailing) { switch (qi.content) { case let .image(_, image): @@ -244,7 +243,8 @@ struct FramedItemView: View { // if enable this always, size of the framed voice message item will be incorrect after end of playback .overlay { if case .voice = chatItem.content.msgContent {} else { DetermineWidth() } } .frame(minWidth: msgWidth, alignment: .leading) - .background(chatItemFrameContextColor(chatItem, theme)) + .background(backgroundColor) + .environment(\.containerBackground, UIColor(backgroundColor)) if let mediaWidth = maxMediaWidth(), mediaWidth < maxWidth { v.frame(maxWidth: mediaWidth, alignment: .leading) } else { @@ -270,14 +270,12 @@ struct FramedItemView: View { .padding(.top, 6) .padding(.horizontal, 12) } - + + @inline(__always) private func ciQuotedMsgTextView(_ qi: CIQuote, lines: Int) -> some View { - toggleSecrets(qi.formattedText, $showQuoteSecrets, - MsgContentView(chat: chat, text: qi.text, formattedText: qi.formattedText, showSecrets: showQuoteSecrets) - .lineLimit(lines) - .font(.subheadline) - .padding(.bottom, 6) - ) + MsgContentView(chat: chat, text: qi.text, formattedText: qi.formattedText, textStyle: .subheadline) + .lineLimit(lines) + .padding(.bottom, 6) } private func ciQuoteIconView(_ image: String) -> some View { @@ -297,21 +295,22 @@ struct FramedItemView: View { } } - @ViewBuilder private func ciMsgContentView(_ ci: ChatItem, _ txtPrefix: Text? = nil) -> some View { + @ViewBuilder private func ciMsgContentView(_ ci: ChatItem, txtPrefix: NSAttributedString? = nil) -> some View { let text = ci.meta.isLive ? ci.content.msgContent?.text ?? ci.text : ci.text let rtl = isRightToLeft(text) let ft = text == "" ? [] : ci.formattedText - let v = toggleSecrets(ft, $showSecrets, MsgContentView( + let v = MsgContentView( chat: chat, text: text, formattedText: ft, + textStyle: .body, meta: ci.meta, mentions: ci.mentions, userMemberId: chat.chatInfo.groupInfo?.membership.memberId, rightToLeft: rtl, - showSecrets: showSecrets, prefix: txtPrefix - )) + ) + .environment(\.containerBackground, UIColor(chatItemFrameColor(ci, theme))) .multilineTextAlignment(rtl ? .trailing : .leading) .padding(.vertical, 6) .padding(.horizontal, 12) @@ -351,14 +350,6 @@ struct FramedItemView: View { } } -@ViewBuilder func toggleSecrets(_ ft: [FormattedText]?, _ showSecrets: Binding, _ v: V) -> some View { - if let ft = ft, ft.contains(where: { $0.isSecret }) { - v.onTapGesture { showSecrets.wrappedValue.toggle() } - } else { - v - } -} - func isRightToLeft(_ s: String) -> Bool { if let lang = CFStringTokenizerCopyBestStringLanguage(s as CFString, CFRange(location: 0, length: min(s.count, 80))) { return NSLocale.characterDirection(forLanguage: lang as String) == .rightToLeft diff --git a/apps/ios/Shared/Views/Chat/ChatItem/FullScreenMediaView.swift b/apps/ios/Shared/Views/Chat/ChatItem/FullScreenMediaView.swift index c3aad9490d..10e5efa298 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/FullScreenMediaView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/FullScreenMediaView.swift @@ -126,7 +126,7 @@ struct FullScreenMediaView: View { .scaledToFit() } } - .onTapGesture { showView = false } + .onTapGesture { showView = false } // this is used in full screen view, onTapGesture works } private func videoView( _ player: AVPlayer, _ url: URL) -> some View { diff --git a/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift index c6d1afa04a..47a30f6cf3 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/IntegrityErrorItemView.swift @@ -71,7 +71,7 @@ struct CIMsgError: View { .padding(.vertical, 6) .background { chatItemFrameColor(chatItem, theme).modifier(ChatTailPadding()) } .textSelection(.disabled) - .onTapGesture(perform: onTap) + .simultaneousGesture(TapGesture().onEnded(onTap)) } } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift b/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift index d82b8314a7..e04584dfff 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/MsgContentView.swift @@ -11,53 +11,74 @@ import SimpleXChat let uiLinkColor = UIColor(red: 0, green: 0.533, blue: 1, alpha: 1) -private let noTyping = Text(verbatim: " ") - -private let typingIndicators: [Text] = [ - (typing(.black) + typing() + typing()), - (typing(.bold) + typing(.black) + typing()), - (typing() + typing(.bold) + typing(.black)), - (typing() + typing() + typing(.bold)) -] - -private func typing(_ w: Font.Weight = .light) -> Text { - Text(verbatim: ".").fontWeight(w) +private func typing(_ theme: AppTheme, _ descr: UIFontDescriptor, _ ws: [UIFont.Weight]) -> NSMutableAttributedString { + let res = NSMutableAttributedString() + for w in ws { + res.append(NSAttributedString(string: ".", attributes: [ + .font: UIFont.monospacedSystemFont(ofSize: descr.pointSize, weight: w), + .kern: -2 as NSNumber, + .foregroundColor: UIColor(theme.colors.secondary) + ])) + } + return res } struct MsgContentView: View { @ObservedObject var chat: Chat @Environment(\.showTimestamp) var showTimestamp: Bool + @Environment(\.containerBackground) var containerBackground: UIColor @EnvironmentObject var theme: AppTheme var text: String var formattedText: [FormattedText]? = nil + var textStyle: UIFont.TextStyle var sender: String? = nil var meta: CIMeta? = nil var mentions: [String: CIMention]? = nil var userMemberId: String? = nil var rightToLeft = false - var showSecrets: Bool - var prefix: Text? = nil + var prefix: NSAttributedString? = nil + @State private var showSecrets: Set = [] @State private var typingIdx = 0 @State private var timer: Timer? + @State private var typingIndicators: [NSAttributedString] = [] + @State private var noTyping = NSAttributedString(string: " ") + @State private var phase: CGFloat = 0 @AppStorage(DEFAULT_SHOW_SENT_VIA_RPOXY) private var showSentViaProxy = false var body: some View { + let v = msgContentView() if meta?.isLive == true { - msgContentView() - .onAppear { switchTyping() } + v.onAppear { + let descr = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body) + noTyping = NSAttributedString(string: " ", attributes: [ + .font: UIFont.monospacedSystemFont(ofSize: descr.pointSize, weight: .regular), + .kern: -2 as NSNumber, + .foregroundColor: UIColor(theme.colors.secondary) + ]) + switchTyping() + } .onDisappear(perform: stopTyping) .onChange(of: meta?.isLive, perform: switchTyping) .onChange(of: meta?.recent, perform: switchTyping) } else { - msgContentView() + v } } private func switchTyping(_: Bool? = nil) { if let meta = meta, meta.isLive && meta.recent { + if typingIndicators.isEmpty { + let descr = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body) + typingIndicators = [ + typing(theme, descr, [.black, .light, .light]), + typing(theme, descr, [.bold, .black, .light]), + typing(theme, descr, [.light, .bold, .black]), + typing(theme, descr, [.light, .light, .bold]) + ] + } timer = timer ?? Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { _ in - typingIdx = (typingIdx + 1) % typingIndicators.count + typingIdx = typingIdx + 1 } } else { stopTyping() @@ -67,119 +88,276 @@ struct MsgContentView: View { private func stopTyping() { timer?.invalidate() timer = nil + typingIdx = 0 } - private func msgContentView() -> Text { - var v = messageText(text, formattedText, sender, mentions: mentions, userMemberId: userMemberId, showSecrets: showSecrets, secondaryColor: theme.colors.secondary, prefix: prefix) + @inline(__always) + private func msgContentView() -> some View { + let r = messageText(text, formattedText, textStyle: textStyle, sender: sender, mentions: mentions, userMemberId: userMemberId, showSecrets: showSecrets, backgroundColor: containerBackground, prefix: prefix) + let s = r.string + let t: Text if let mt = meta { if mt.isLive { - v = v + typingIndicator(mt.recent) + s.append(typingIndicator(mt.recent)) } - v = v + reserveSpaceForMeta(mt) + t = Text(AttributedString(s)) + reserveSpaceForMeta(mt) + } else { + t = Text(AttributedString(s)) } - return v + return msgTextResultView(r, t, showSecrets: $showSecrets) } - private func typingIndicator(_ recent: Bool) -> Text { - return (recent ? typingIndicators[typingIdx] : noTyping) - .font(.body.monospaced()) - .kerning(-2) - .foregroundColor(theme.colors.secondary) + @inline(__always) + private func typingIndicator(_ recent: Bool) -> NSAttributedString { + recent && !typingIndicators.isEmpty + ? typingIndicators[typingIdx % 4] + : noTyping } + @inline(__always) private func reserveSpaceForMeta(_ mt: CIMeta) -> Text { (rightToLeft ? textNewLine : Text(verbatim: " ")) + ciMetaText(mt, chatTTL: chat.chatInfo.timedMessagesTTL, encrypted: nil, colorMode: .transparent, showViaProxy: showSentViaProxy, showTimesamp: showTimestamp) } } -func messageText(_ text: String, _ formattedText: [FormattedText]?, _ sender: String?, icon: String? = nil, preview: Bool = false, mentions: [String: CIMention]?, userMemberId: String?, showSecrets: Bool, secondaryColor: Color, prefix: Text? = nil) -> Text { - let s = text - var res: Text - - if let ft = formattedText, ft.count > 0 && ft.count <= 200 { - res = formatText(ft[0], preview, showSecret: showSecrets, mentions: mentions, userMemberId: userMemberId) - var i = 1 - while i < ft.count { - res = res + formatText(ft[i], preview, showSecret: showSecrets, mentions: mentions, userMemberId: userMemberId) - i = i + 1 - } - } else { - res = Text(s) - } - - if let i = icon { - res = Text(Image(systemName: i)).foregroundColor(secondaryColor) + textSpace + res - } - - if let p = prefix { - res = p + res - } - - if let s = sender { - let t = Text(s) - return (preview ? t : t.fontWeight(.medium)) + Text(verbatim: ": ") + res - } else { - return res - } +func msgTextResultView(_ r: MsgTextResult, _ t: Text, showSecrets: Binding>? = nil) -> some View { + t.if(r.hasSecrets, transform: hiddenSecretsView) + .if(r.handleTaps) { $0.overlay(handleTextTaps(r.string, showSecrets: showSecrets)) } } -private func formatText(_ ft: FormattedText, _ preview: Bool, showSecret: Bool, mentions: [String: CIMention]?, userMemberId: String?) -> Text { - let t = ft.text - if let f = ft.format { - switch (f) { - case .bold: return Text(t).bold() - case .italic: return Text(t).italic() - case .strikeThrough: return Text(t).strikethrough() - case .snippet: return Text(t).font(.body.monospaced()) - case .secret: return - showSecret - ? Text(t) - : Text(AttributedString(t, attributes: AttributeContainer([ - .foregroundColor: UIColor.clear as Any, - .backgroundColor: UIColor.secondarySystemFill as Any - ]))) - case let .colored(color): return Text(t).foregroundColor(color.uiColor) - case .uri: return linkText(t, t, preview, prefix: "") - case let .simplexLink(linkType, simplexUri, smpHosts): - switch privacySimplexLinkModeDefault.get() { - case .description: return linkText(simplexLinkText(linkType, smpHosts), simplexUri, preview, prefix: "") - case .full: return linkText(t, simplexUri, preview, prefix: "") - case .browser: return linkText(t, simplexUri, preview, prefix: "") - } - case let .mention(memberName): - if let m = mentions?[memberName] { - if let ref = m.memberRef { - let name: String = if let alias = ref.localAlias, alias != "" { - "\(alias) (\(ref.displayName))" - } else { - ref.displayName +@inline(__always) +private func handleTextTaps(_ s: NSAttributedString, showSecrets: Binding>? = nil) -> some View { + return GeometryReader { g in + Rectangle() + .fill(Color.clear) + .contentShape(Rectangle()) + .simultaneousGesture(DragGesture(minimumDistance: 0).onEnded { event in + let t = event.translation + if t.width * t.width + t.height * t.height > 100 { return } + let framesetter = CTFramesetterCreateWithAttributedString(s as CFAttributedString) + let path = CGPath(rect: CGRect(origin: .zero, size: g.size), transform: nil) + let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, s.length), path, nil) + let point = CGPoint(x: event.location.x, y: g.size.height - event.location.y) // Flip y for UIKit + var index: CFIndex? + if let lines = CTFrameGetLines(frame) as? [CTLine] { + var origins = [CGPoint](repeating: .zero, count: lines.count) + CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), &origins) + for i in 0 ..< lines.count { + let bounds = CTLineGetBoundsWithOptions(lines[i], .useOpticalBounds) + if bounds.offsetBy(dx: origins[i].x, dy: origins[i].y).contains(point) { + index = CTLineGetStringIndexForPosition(lines[i], point) + break + } } - let tName = mentionText(name) - return m.memberId == userMemberId ? tName.foregroundColor(.accentColor) : tName - } else { - return mentionText(memberName) } + if let index, let (url, browser) = attributedStringLink(s, for: index) { + if browser { + openBrowserAlert(uri: url) + } else { + UIApplication.shared.open(url) + } + } + }) + } + + func attributedStringLink(_ s: NSAttributedString, for index: CFIndex) -> (URL, Bool)? { + var linkURL: URL? + var browser: Bool = false + s.enumerateAttributes(in: NSRange(location: 0, length: s.length)) { attrs, range, stop in + if index >= range.location && index < range.location + range.length { + if let url = attrs[linkAttrKey] as? NSURL { + linkURL = url.absoluteURL + browser = attrs[webLinkAttrKey] != nil + } else if let showSecrets, let i = attrs[secretAttrKey] as? Int { + if showSecrets.wrappedValue.contains(i) { + showSecrets.wrappedValue.remove(i) + } else { + showSecrets.wrappedValue.insert(i) + } + } + stop.pointee = true } - return Text(t) - case .email: return linkText(t, t, preview, prefix: "mailto:") - case .phone: return linkText(t, t.replacingOccurrences(of: " ", with: ""), preview, prefix: "tel:") } - } else { - return Text(t) + return if let linkURL { (linkURL, browser) } else { nil } } } -private func mentionText(_ name: String) -> Text { - Text(verbatim: name.contains(" @") ? "@'\(name)'" : "@\(name)").fontWeight(.semibold) +func hiddenSecretsView(_ v: V) -> some View { + v.overlay( + GeometryReader { g in + let size = (g.size.width + g.size.height) / 1.4142 + Image("vertical_logo") + .resizable(resizingMode: .tile) + .frame(width: size, height: size) + .rotationEffect(.degrees(45), anchor: .center) + .position(x: g.size.width / 2, y: g.size.height / 2) + .clipped() + .saturation(0.65) + .opacity(0.35) + } + .mask(v) + ) } -private func linkText(_ s: String, _ link: String, _ preview: Bool, prefix: String, color: Color = Color(uiColor: uiLinkColor), uiColor: UIColor = uiLinkColor) -> Text { - preview - ? Text(s).foregroundColor(color).underline(color: color) - : Text(AttributedString(s, attributes: AttributeContainer([ - .link: NSURL(string: prefix + link) as Any, - .foregroundColor: uiColor as Any - ]))).underline() +private let linkAttrKey = NSAttributedString.Key("chat.simplex.app.link") + +private let webLinkAttrKey = NSAttributedString.Key("chat.simplex.app.webLink") + +private let secretAttrKey = NSAttributedString.Key("chat.simplex.app.secret") + +typealias MsgTextResult = (string: NSMutableAttributedString, hasSecrets: Bool, handleTaps: Bool) + +func messageText( + _ text: String, + _ formattedText: [FormattedText]?, + textStyle: UIFont.TextStyle = .body, + sender: String?, + preview: Bool = false, + mentions: [String: CIMention]?, + userMemberId: String?, + showSecrets: Set?, + backgroundColor: UIColor, + prefix: NSAttributedString? = nil +) -> MsgTextResult { + let res = NSMutableAttributedString() + let descr = UIFontDescriptor.preferredFontDescriptor(withTextStyle: textStyle) + let font = UIFont.preferredFont(forTextStyle: textStyle) + let plain: [NSAttributedString.Key: Any] = [ + .font: font, + .foregroundColor: UIColor.label + ] + let secretColor = backgroundColor.withAlphaComponent(1) + var link: [NSAttributedString.Key: Any]? + var hasSecrets = false + var handleTaps = false + + if let sender { + if preview { + res.append(NSAttributedString(string: sender + ": ", attributes: plain)) + } else { + var attrs = plain + attrs[.font] = UIFont(descriptor: descr.addingAttributes([.traits: [UIFontDescriptor.TraitKey.weight: UIFont.Weight.medium]]), size: descr.pointSize) + res.append(NSAttributedString(string: sender, attributes: attrs)) + res.append(NSAttributedString(string: ": ", attributes: plain)) + } + } + + if let prefix { + res.append(prefix) + } + + if let fts = formattedText, fts.count > 0 { + var bold: UIFont? + var italic: UIFont? + var snippet: UIFont? + var mention: UIFont? + var secretIdx: Int = 0 + for ft in fts { + var t = ft.text + var attrs = plain + switch (ft.format) { + case .bold: + bold = bold ?? UIFont(descriptor: descr.addingAttributes([.traits: [UIFontDescriptor.TraitKey.weight: UIFont.Weight.bold]]), size: descr.pointSize) + attrs[.font] = bold + case .italic: + italic = italic ?? UIFont(descriptor: descr.withSymbolicTraits(.traitItalic) ?? descr, size: descr.pointSize) + attrs[.font] = italic + case .strikeThrough: + attrs[.strikethroughStyle] = NSUnderlineStyle.single.rawValue + case .snippet: + snippet = snippet ?? UIFont.monospacedSystemFont(ofSize: descr.pointSize, weight: .regular) + attrs[.font] = snippet + case .secret: + if let showSecrets { + if !showSecrets.contains(secretIdx) { + attrs[.foregroundColor] = UIColor.clear + attrs[.backgroundColor] = secretColor + } + attrs[secretAttrKey] = secretIdx + secretIdx += 1 + handleTaps = true + } else { + attrs[.foregroundColor] = UIColor.clear + attrs[.backgroundColor] = secretColor + } + hasSecrets = true + case let .colored(color): + if let c = color.uiColor { + attrs[.foregroundColor] = UIColor(c) + } + case .uri: + attrs = linkAttrs() + if !preview { + let s = t.lowercased() + let link = s.hasPrefix("http://") || s.hasPrefix("https://") + ? t + : "https://" + t + attrs[linkAttrKey] = NSURL(string: link) + attrs[webLinkAttrKey] = true + handleTaps = true + } + case let .simplexLink(linkType, simplexUri, smpHosts): + attrs = linkAttrs() + if !preview { + attrs[linkAttrKey] = NSURL(string: simplexUri) + handleTaps = true + } + if case .description = privacySimplexLinkModeDefault.get() { + t = simplexLinkText(linkType, smpHosts) + } + case let .mention(memberName): + if let m = mentions?[memberName] { + mention = mention ?? UIFont(descriptor: descr.addingAttributes([.traits: [UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold]]), size: descr.pointSize) + attrs[.font] = mention + if let ref = m.memberRef { + let name: String = if let alias = ref.localAlias, alias != "" { + "\(alias) (\(ref.displayName))" + } else { + ref.displayName + } + if m.memberId == userMemberId { + attrs[.foregroundColor] = UIColor.tintColor + } + t = mentionText(name) + } else { + t = mentionText(memberName) + } + } + case .email: + attrs = linkAttrs() + if !preview { + attrs[linkAttrKey] = NSURL(string: "mailto:" + ft.text) + handleTaps = true + } + case .phone: + attrs = linkAttrs() + if !preview { + attrs[linkAttrKey] = NSURL(string: "tel:" + t.replacingOccurrences(of: " ", with: "")) + handleTaps = true + } + case .none: () + } + res.append(NSAttributedString(string: t, attributes: attrs)) + } + } else { + res.append(NSMutableAttributedString(string: text, attributes: plain)) + } + + return (string: res, hasSecrets: hasSecrets, handleTaps: handleTaps) + + func linkAttrs() -> [NSAttributedString.Key: Any] { + link = link ?? [ + .font: font, + .foregroundColor: uiLinkColor, + .underlineStyle: NSUnderlineStyle.single.rawValue + ] + return link! + } +} + +@inline(__always) +private func mentionText(_ name: String) -> String { + name.contains(" @") ? "@'\(name)'" : "@\(name)" } func simplexLinkText(_ linkType: SimplexLinkType, _ smpHosts: [String]) -> String { @@ -193,9 +371,9 @@ struct MsgContentView_Previews: PreviewProvider { chat: Chat.sampleData, text: chatItem.text, formattedText: chatItem.formattedText, + textStyle: .body, sender: chatItem.memberDisplayName, - meta: chatItem.meta, - showSecrets: false + meta: chatItem.meta ) .environmentObject(Chat.sampleData) } diff --git a/apps/ios/Shared/Views/Chat/ChatItemForwardingView.swift b/apps/ios/Shared/Views/Chat/ChatItemForwardingView.swift index 587957cd5d..dfc620c402 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemForwardingView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemForwardingView.swift @@ -41,7 +41,7 @@ struct ChatItemForwardingView: View { .alert(item: $alert) { $0.alert } } - @ViewBuilder private func forwardListView() -> some View { + private func forwardListView() -> some View { VStack(alignment: .leading) { if !chatsToForwardTo.isEmpty { List { diff --git a/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift b/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift index 0fe9f5d4c2..cd75d1b0cd 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemInfoView.swift @@ -131,9 +131,9 @@ struct ChatItemInfoView: View { } } - @ViewBuilder private func details() -> some View { + private func details() -> some View { let meta = ci.meta - VStack(alignment: .leading, spacing: 16) { + return VStack(alignment: .leading, spacing: 16) { Text(title) .font(.largeTitle) .bold() @@ -197,7 +197,7 @@ struct ChatItemInfoView: View { } } - @ViewBuilder private func historyTab() -> some View { + private func historyTab() -> some View { GeometryReader { g in let maxWidth = (g.size.width - 32) * 0.84 ScrollView { @@ -227,12 +227,13 @@ struct ChatItemInfoView: View { } } - @ViewBuilder private func itemVersionView(_ itemVersion: ChatItemVersion, _ maxWidth: CGFloat, current: Bool) -> some View { - VStack(alignment: .leading, spacing: 4) { - textBubble(itemVersion.msgContent.text, itemVersion.formattedText, nil) + private func itemVersionView(_ itemVersion: ChatItemVersion, _ maxWidth: CGFloat, current: Bool) -> some View { + let backgroundColor = chatItemFrameColor(ci, theme) + return VStack(alignment: .leading, spacing: 4) { + textBubble(itemVersion.msgContent.text, itemVersion.formattedText, nil, backgroundColor: UIColor(backgroundColor)) .padding(.horizontal, 12) .padding(.vertical, 6) - .background(chatItemFrameColor(ci, theme)) + .background(backgroundColor) .modifier(ChatItemClipped()) .contextMenu { if itemVersion.msgContent.text != "" { @@ -257,9 +258,9 @@ struct ChatItemInfoView: View { .frame(maxWidth: maxWidth, alignment: .leading) } - @ViewBuilder private func textBubble(_ text: String, _ formattedText: [FormattedText]?, _ sender: String? = nil) -> some View { + @ViewBuilder private func textBubble(_ text: String, _ formattedText: [FormattedText]?, _ sender: String? = nil, backgroundColor: UIColor) -> some View { if text != "" { - TextBubble(text: text, formattedText: formattedText, sender: sender, mentions: ci.mentions, userMemberId: userMemberId) + TextBubble(text: text, formattedText: formattedText, sender: sender, mentions: ci.mentions, userMemberId: userMemberId, backgroundColor: backgroundColor) } else { Text("no text") .italic() @@ -274,14 +275,16 @@ struct ChatItemInfoView: View { var sender: String? = nil var mentions: [String: CIMention]? var userMemberId: String? - @State private var showSecrets = false + var backgroundColor: UIColor + @State private var showSecrets: Set = [] var body: some View { - toggleSecrets(formattedText, $showSecrets, messageText(text, formattedText, sender, mentions: mentions, userMemberId: userMemberId, showSecrets: showSecrets, secondaryColor: theme.colors.secondary)) + let r = messageText(text, formattedText, sender: sender, mentions: mentions, userMemberId: userMemberId, showSecrets: showSecrets, backgroundColor: backgroundColor) + return msgTextResultView(r, Text(AttributedString(r.string)), showSecrets: $showSecrets) } } - @ViewBuilder private func quoteTab(_ qi: CIQuote) -> some View { + private func quoteTab(_ qi: CIQuote) -> some View { GeometryReader { g in let maxWidth = (g.size.width - 32) * 0.84 ScrollView { @@ -299,9 +302,10 @@ struct ChatItemInfoView: View { } } - @ViewBuilder private func quotedMsgView(_ qi: CIQuote, _ maxWidth: CGFloat) -> some View { - VStack(alignment: .leading, spacing: 4) { - textBubble(qi.text, qi.formattedText, qi.getSender(nil)) + private func quotedMsgView(_ qi: CIQuote, _ maxWidth: CGFloat) -> some View { + let backgroundColor = quotedMsgFrameColor(qi, theme) + return VStack(alignment: .leading, spacing: 4) { + textBubble(qi.text, qi.formattedText, qi.getSender(nil), backgroundColor: UIColor(backgroundColor)) .padding(.horizontal, 12) .padding(.vertical, 6) .background(quotedMsgFrameColor(qi, theme)) @@ -334,7 +338,7 @@ struct ChatItemInfoView: View { : theme.appColors.receivedMessage } - @ViewBuilder private func forwardedFromTab(_ forwardedFromItem: AChatItem) -> some View { + private func forwardedFromTab(_ forwardedFromItem: AChatItem) -> some View { ScrollView { VStack(alignment: .leading, spacing: 16) { details() @@ -372,7 +376,7 @@ struct ChatItemInfoView: View { } } - @ViewBuilder private func forwardedFromSender(_ forwardedFromItem: AChatItem) -> some View { + private func forwardedFromSender(_ forwardedFromItem: AChatItem) -> some View { HStack { ChatInfoImage(chat: Chat(chatInfo: forwardedFromItem.chatInfo), size: 48) .padding(.trailing, 6) @@ -403,7 +407,7 @@ struct ChatItemInfoView: View { } } - @ViewBuilder private func deliveryTab(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View { + private func deliveryTab(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View { ScrollView { VStack(alignment: .leading, spacing: 16) { details() @@ -418,7 +422,7 @@ struct ChatItemInfoView: View { .frame(maxHeight: .infinity, alignment: .top) } - @ViewBuilder private func memberDeliveryStatusesView(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View { + private func memberDeliveryStatusesView(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View { LazyVStack(alignment: .leading, spacing: 12) { let mss = membersStatuses(memberDeliveryStatuses) if !mss.isEmpty { diff --git a/apps/ios/Shared/Views/Chat/ChatItemView.swift b/apps/ios/Shared/Views/Chat/ChatItemView.swift index 5d09e153d5..f5558bcd93 100644 --- a/apps/ios/Shared/Views/Chat/ChatItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItemView.swift @@ -18,6 +18,10 @@ extension EnvironmentValues { static let defaultValue: Bool = true } + struct ContainerBackground: EnvironmentKey { + static let defaultValue: UIColor = .clear + } + var showTimestamp: Bool { get { self[ShowTimestamp.self] } set { self[ShowTimestamp.self] = newValue } @@ -27,6 +31,11 @@ extension EnvironmentValues { get { self[Revealed.self] } set { self[Revealed.self] = newValue } } + + var containerBackground: UIColor { + get { self[ContainerBackground.self] } + set { self[ContainerBackground.self] = newValue } + } } struct ChatItemView: View { diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 1349996683..9e648ef98c 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -71,10 +71,9 @@ struct ChatView: View { } } - @ViewBuilder private var viewBody: some View { let cInfo = chat.chatInfo - ZStack { + return ZStack { let wallpaperImage = theme.wallpaper.type.image let wallpaperType = theme.wallpaper.type let backgroundColor = theme.wallpaper.background ?? wallpaperType.defaultBackgroundColor(theme.base, theme.colors.background) @@ -1277,10 +1276,10 @@ struct ChatView: View { if let selected = selectedChatItems, chatItem.canBeDeletedForSelf { Color.clear .contentShape(Rectangle()) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { let checked = selected.contains(chatItem.id) selectUnselectChatItem(select: !checked, chatItem) - } + }) } } if let date = itemSeparation.date { @@ -1469,7 +1468,7 @@ struct ChatView: View { } HStack(alignment: .top, spacing: 10) { MemberProfileImage(member, size: memberImageSize, backgroundColor: theme.colors.background) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { if let mem = m.getGroupMember(member.groupMemberId) { selectedMember = mem } else { @@ -1478,7 +1477,7 @@ struct ChatView: View { m.groupMembersIndexes[member.groupMemberId] = m.groupMembers.count - 1 selectedMember = mem } - } + }) chatItemWithMenu(ci, range, maxWidth, itemSeparation) .onPreferenceChange(DetermineWidth.Key.self) { msgWidth = $0 } } @@ -1528,9 +1527,9 @@ struct ChatView: View { } } - @ViewBuilder func chatItemWithMenu(_ ci: ChatItem, _ range: ClosedRange?, _ maxWidth: CGFloat, _ itemSeparation: ItemSeparation) -> some View { + func chatItemWithMenu(_ ci: ChatItem, _ range: ClosedRange?, _ maxWidth: CGFloat, _ itemSeparation: ItemSeparation) -> some View { let alignment: Alignment = ci.chatDir.sent ? .trailing : .leading - VStack(alignment: alignment.horizontal, spacing: 3) { + return VStack(alignment: alignment.horizontal, spacing: 3) { HStack { if ci.chatDir.sent { goToItemButton(true) @@ -1622,9 +1621,9 @@ struct ChatView: View { .padding(.horizontal, 6) .padding(.vertical, 4) .if(chat.chatInfo.featureEnabled(.reactions) && (ci.allowAddReaction || r.userReacted)) { v in - v.onTapGesture { + v.simultaneousGesture(TapGesture().onEnded { setReaction(ci, add: !r.userReacted, reaction: r.reaction) - } + }) } switch chat.chatInfo { case let .group(groupInfo): @@ -2214,15 +2213,12 @@ struct ChatView: View { } func goToItemInnerButton(_ alignStart: Bool, _ image: String, touchInProgress: Bool, _ onClick: @escaping () -> Void) -> some View { - Button { - onClick() - } label: { - Image(systemName: image) - .resizable() - .frame(width: 13, height: 13) - .padding([alignStart ? .trailing : .leading], 10) - .tint(theme.colors.secondary.opacity(touchInProgress ? 1.0 : 0.4)) - } + Image(systemName: image) + .resizable() + .frame(width: 13, height: 13) + .padding([alignStart ? .trailing : .leading], 10) + .tint(theme.colors.secondary.opacity(touchInProgress ? 1.0 : 0.4)) + .simultaneousGesture(TapGesture().onEnded(onClick)) } @ViewBuilder diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift index 6c44aeea83..e629a984df 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeLinkView.swift @@ -18,7 +18,7 @@ struct ComposeLinkView: View { var body: some View { HStack(alignment: .center, spacing: 8) { - if let linkPreview = linkPreview { + if let linkPreview { linkPreviewView(linkPreview) } else { ProgressView() diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 6ded9cae72..3e9c340266 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -1254,11 +1254,14 @@ struct ComposeView: View { if pendingLinkUrl == url { composeState = composeState.copy(preview: .linkPreview(linkPreview: nil)) getLinkPreview(url: url) { linkPreview in - if let linkPreview = linkPreview, - pendingLinkUrl == url { + if let linkPreview, pendingLinkUrl == url { composeState = composeState.copy(preview: .linkPreview(linkPreview: linkPreview)) - pendingLinkUrl = nil + } else { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + composeState = composeState.copy(preview: .noPreview) + } } + pendingLinkUrl = nil } } } diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift index d5b5e6ccf4..845442c75f 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ContextItemView.swift @@ -70,8 +70,10 @@ struct ContextItemView: View { .lineLimit(lines) } - private func contextMsgPreview(_ contextItem: ChatItem) -> Text { - return attachment() + messageText(contextItem.text, contextItem.formattedText, nil, preview: true, mentions: contextItem.mentions, userMemberId: nil, showSecrets: false, secondaryColor: theme.colors.secondary) + private func contextMsgPreview(_ contextItem: ChatItem) -> some View { + let r = messageText(contextItem.text, contextItem.formattedText, sender: nil, preview: true, mentions: contextItem.mentions, userMemberId: nil, showSecrets: nil, backgroundColor: UIColor(background)) + let t = attachment() + Text(AttributedString(r.string)) + return t.if(r.hasSecrets, transform: hiddenSecretsView) func attachment() -> Text { let isFileLoaded = if let fileSource = getLoadedFileSource(contextItem.file) { diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift index 30767d66ec..d7b29a0ecb 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift @@ -263,13 +263,12 @@ struct SendMessageView: View { @State private var pressed: TimeInterval? = nil var body: some View { - Button(action: {}) { - Image(systemName: "mic.fill") - .resizable() - .scaledToFit() - .frame(width: 20, height: 20) - .foregroundColor(theme.colors.primary) - } + Image(systemName: "mic.fill") + .resizable() + .scaledToFit() + .frame(width: 20, height: 20) + .foregroundColor(theme.colors.primary) + .opacity(holdingVMR ? 0.7 : 1) .disabled(disabled) .frame(width: 31, height: 31) .padding([.bottom, .trailing], 4) @@ -279,9 +278,7 @@ struct SendMessageView: View { pressed = ProcessInfo.processInfo.systemUptime startVoiceMessageRecording?() } else { - let now = ProcessInfo.processInfo.systemUptime - if let pressed = pressed, - now - pressed >= 1 { + if let pressed, ProcessInfo.processInfo.systemUptime - pressed >= 1 { finishVoiceMessageRecording?() } holdingVMR = false diff --git a/apps/ios/Shared/Views/Chat/Group/AddGroupMembersView.swift b/apps/ios/Shared/Views/Chat/Group/AddGroupMembersView.swift index 66fe67a29e..7cd543af10 100644 --- a/apps/ios/Shared/Views/Chat/Group/AddGroupMembersView.swift +++ b/apps/ios/Shared/Views/Chat/Group/AddGroupMembersView.swift @@ -145,9 +145,9 @@ struct AddGroupMembersViewCommon: View { return dummy }() - @ViewBuilder private func inviteMembersButton() -> some View { + private func inviteMembersButton() -> some View { let label: LocalizedStringKey = groupInfo.businessChat == nil ? "Invite to group" : "Invite to chat" - Button { + return Button { inviteMembers() } label: { HStack { diff --git a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift index 9fa07bc391..96a4981be0 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift @@ -292,9 +292,9 @@ struct GroupChatInfoView: View { .disabled(!groupInfo.ready || chat.chatItems.isEmpty) } - @ViewBuilder private func addMembersActionButton(width: CGFloat) -> some View { - if chat.chatInfo.incognito { - ZStack { + private func addMembersActionButton(width: CGFloat) -> some View { + ZStack { + if chat.chatInfo.incognito { InfoViewButton(image: "link.badge.plus", title: "invite", width: width) { groupLinkNavLinkActive = true } @@ -306,10 +306,7 @@ struct GroupChatInfoView: View { } .frame(width: 1, height: 1) .hidden() - } - .disabled(!groupInfo.ready) - } else { - ZStack { + } else { InfoViewButton(image: "person.fill.badge.plus", title: "invite", width: width) { addMembersNavLinkActive = true } @@ -322,8 +319,8 @@ struct GroupChatInfoView: View { .frame(width: 1, height: 1) .hidden() } - .disabled(!groupInfo.ready) } + .disabled(!groupInfo.ready) } private func muteButton(width: CGFloat, nextNtfMode: MsgFilter) -> some View { @@ -569,9 +566,9 @@ struct GroupChatInfoView: View { } } - @ViewBuilder private func leaveGroupButton() -> some View { + private func leaveGroupButton() -> some View { let label: LocalizedStringKey = groupInfo.businessChat == nil ? "Leave group" : "Leave chat" - Button(role: .destructive) { + return Button(role: .destructive) { alert = .leaveGroupAlert } label: { Label(label, systemImage: "rectangle.portrait.and.arrow.right") diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMentions.swift b/apps/ios/Shared/Views/Chat/Group/GroupMentions.swift index 168f0490c3..9bb4a0cc35 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupMentions.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupMentions.swift @@ -196,7 +196,9 @@ struct GroupMentionsView: View { newName = composeState.mentionMemberName(member.wrapped.memberProfile.displayName) } mentions[newName] = CIMention(groupMember: member.wrapped) - var msgMention = "@" + (newName.contains(" ") ? "'\(newName)'" : newName) + var msgMention = newName.contains(" ") || newName.last?.isPunctuation == true + ? "@'\(newName)'" + : "@\(newName)" var newPos = r.location + msgMention.count let newMsgLength = composeState.message.count + msgMention.count - r.length print(newPos) diff --git a/apps/ios/Shared/Views/Chat/Group/GroupWelcomeView.swift b/apps/ios/Shared/Views/Chat/Group/GroupWelcomeView.swift index 58bfe182cb..97bff70efb 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupWelcomeView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupWelcomeView.swift @@ -18,6 +18,7 @@ struct GroupWelcomeView: View { @State private var editMode = true @FocusState private var keyboardVisible: Bool @State private var showSaveDialog = false + @State private var showSecrets: Set = [] let maxByteCount = 1200 @@ -58,7 +59,8 @@ struct GroupWelcomeView: View { } private func textPreview() -> some View { - messageText(welcomeText, parseSimpleXMarkdown(welcomeText), nil, mentions: nil, userMemberId: nil, showSecrets: false, secondaryColor: theme.colors.secondary) + let r = messageText(welcomeText, parseSimpleXMarkdown(welcomeText), sender: nil, mentions: nil, userMemberId: nil, showSecrets: showSecrets, backgroundColor: UIColor(theme.colors.background)) + return msgTextResultView(r, Text(AttributedString(r.string)), showSecrets: $showSecrets) .frame(minHeight: 130, alignment: .topLeading) .frame(maxWidth: .infinity, alignment: .leading) } diff --git a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift index f5234ed331..f9cf5e98e4 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift @@ -90,7 +90,7 @@ struct ChatListNavLink: View { .actionSheet(item: $actionSheet) { $0.actionSheet } } - @ViewBuilder private func contactNavLink(_ contact: Contact) -> some View { + private func contactNavLink(_ contact: Contact) -> some View { Group { if contact.activeConn == nil && contact.profile.contactLink != nil && contact.active { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) @@ -243,7 +243,7 @@ struct ChatListNavLink: View { } } - @ViewBuilder private func noteFolderNavLink(_ noteFolder: NoteFolder) -> some View { + private func noteFolderNavLink(_ noteFolder: NoteFolder) -> some View { NavLinkPlain( chatId: chat.chatInfo.id, selection: $chatModel.chatId, diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 93c18f28cc..5c491b6303 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -335,9 +335,9 @@ struct ChatListView: View { } } - @ViewBuilder private var chatList: some View { + private var chatList: some View { let cs = filteredChats() - ZStack { + return ZStack { ScrollViewReader { scrollProxy in List { if !chatModel.chats.isEmpty { @@ -804,7 +804,7 @@ struct TagsView: View { } } - @ViewBuilder private func expandedPresetTagsFiltersView() -> some View { + private func expandedPresetTagsFiltersView() -> some View { ForEach(PresetTag.allCases, id: \.id) { tag in if (chatTagsModel.presetTags[tag] ?? 0) > 0 { expandedTagFilterView(tag) diff --git a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift index 7f92862f66..b8c8233e6e 100644 --- a/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatPreviewView.swift @@ -187,13 +187,14 @@ struct ChatPreviewView: View { .kerning(-2) } - private func chatPreviewLayout(_ text: Text?, draft: Bool = false, _ hasFilePreview: Bool = false) -> some View { + private func chatPreviewLayout(_ text: Text?, draft: Bool = false, hasFilePreview: Bool = false, hasSecrets: Bool) -> some View { ZStack(alignment: .topTrailing) { let s = chat.chatStats let mentionWidth: CGFloat = if s.unreadMentions > 0 && s.unreadCount > 1 { dynamicSize(userFont).unreadCorner } else { 0 } let t = text .lineLimit(userFont <= .xxxLarge ? 2 : 1) .multilineTextAlignment(.leading) + .if(hasSecrets, transform: hiddenSecretsView) .frame(maxWidth: .infinity, alignment: .topLeading) .padding(.leading, hasFilePreview ? 0 : 8) .padding(.trailing, mentionWidth + (hasFilePreview ? 38 : 36)) @@ -259,11 +260,13 @@ struct ChatPreviewView: View { } } - private func messageDraft(_ draft: ComposeState) -> Text { + private func messageDraft(_ draft: ComposeState) -> (Text, Bool) { let msg = draft.message - return image("rectangle.and.pencil.and.ellipsis", color: theme.colors.primary) - + attachment() - + messageText(msg, parseSimpleXMarkdown(msg), nil, preview: true, mentions: draft.mentions, userMemberId: nil, showSecrets: false, secondaryColor: theme.colors.secondary) + let r = messageText(msg, parseSimpleXMarkdown(msg), sender: nil, preview: true, mentions: draft.mentions, userMemberId: nil, showSecrets: nil, backgroundColor: UIColor(theme.colors.background)) + return (image("rectangle.and.pencil.and.ellipsis", color: theme.colors.primary) + + attachment() + + Text(AttributedString(r.string)), + r.hasSecrets) func image(_ s: String, color: Color = Color(uiColor: .tertiaryLabel)) -> Text { Text(Image(systemName: s)).foregroundColor(color) + textSpace @@ -279,10 +282,11 @@ struct ChatPreviewView: View { } } - func chatItemPreview(_ cItem: ChatItem) -> Text { + func chatItemPreview(_ cItem: ChatItem) -> (Text, Bool) { let itemText = cItem.meta.itemDeleted == nil ? cItem.text : markedDeletedText() let itemFormattedText = cItem.meta.itemDeleted == nil ? cItem.formattedText : nil - return messageText(itemText, itemFormattedText, cItem.memberDisplayName, icon: nil, preview: true, mentions: cItem.mentions, userMemberId: chat.chatInfo.groupInfo?.membership.memberId, showSecrets: false, secondaryColor: theme.colors.secondary, prefix: prefix()) + let r = messageText(itemText, itemFormattedText, sender: cItem.memberDisplayName, preview: true, mentions: cItem.mentions, userMemberId: chat.chatInfo.groupInfo?.membership.memberId, showSecrets: nil, backgroundColor: UIColor(theme.colors.background), prefix: prefix()) + return (Text(AttributedString(r.string)), r.hasSecrets) // same texts are in markedDeletedText in MarkedDeletedItemView, but it returns LocalizedStringKey; // can be refactored into a single function if functions calling these are changed to return same type @@ -309,19 +313,21 @@ struct ChatPreviewView: View { } } - func prefix() -> Text { + func prefix() -> NSAttributedString? { switch cItem.content.msgContent { - case let .report(_, reason): return Text(!itemText.isEmpty ? "\(reason.text): " : reason.text).italic().foregroundColor(Color.red) - default: return Text("") + case let .report(_, reason): reason.attrString + default: nil } } } @ViewBuilder private func chatMessagePreview(_ cItem: ChatItem?, _ hasFilePreview: Bool = false) -> some View { if chatModel.draftChatId == chat.id, let draft = chatModel.draft { - chatPreviewLayout(messageDraft(draft), draft: true, hasFilePreview) + let (t, hasSecrets) = messageDraft(draft) + chatPreviewLayout(t, draft: true, hasFilePreview: hasFilePreview, hasSecrets: hasSecrets) } else if let cItem = cItem { - chatPreviewLayout(itemStatusMark(cItem) + chatItemPreview(cItem), hasFilePreview) + let (t, hasSecrets) = chatItemPreview(cItem) + chatPreviewLayout(itemStatusMark(cItem) + t, hasFilePreview: hasFilePreview, hasSecrets: hasSecrets) } else { switch (chat.chatInfo) { case let .direct(contact): @@ -348,7 +354,6 @@ struct ChatPreviewView: View { } @ViewBuilder func chatItemContentPreview(_ chat: Chat, _ ci: ChatItem) -> some View { - let linkClicksEnabled = privacyChatListOpenLinksDefault.get() != PrivacyChatListOpenLinksMode.no let mc = ci.content.msgContent switch mc { case let .link(_, preview): @@ -370,17 +375,7 @@ struct ChatPreviewView: View { .cornerRadius(8) } .onTapGesture { - switch privacyChatListOpenLinksDefault.get() { - case .yes: UIApplication.shared.open(preview.uri) - case .no: ItemsModel.shared.loadOpenChat(chat.id) - case .ask: AlertManager.shared.showAlert( - Alert(title: Text("Open web link?"), - message: Text(preview.uri.absoluteString), - primaryButton: .default(Text("Open chat"), action: { ItemsModel.shared.loadOpenChat(chat.id) }), - secondaryButton: .default(Text("Open link"), action: { UIApplication.shared.open(preview.uri) }) - ) - ) - } + openBrowserAlert(uri: preview.uri) } } case let .image(_, image): @@ -410,7 +405,7 @@ struct ChatPreviewView: View { : chatPreviewInfoText("you are invited to group") } - @ViewBuilder private func chatPreviewInfoText(_ text: LocalizedStringKey) -> some View { + private func chatPreviewInfoText(_ text: LocalizedStringKey) -> some View { Text(text) .frame(maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .topLeading) .padding([.leading, .trailing], 8) @@ -490,7 +485,7 @@ struct ChatPreviewView: View { } } -@ViewBuilder func groupReportsIcon(size: CGFloat) -> some View { +func groupReportsIcon(size: CGFloat) -> some View { Image(systemName: "flag") .resizable() .scaledToFit() diff --git a/apps/ios/Shared/Views/ChatList/ServersSummaryView.swift b/apps/ios/Shared/Views/ChatList/ServersSummaryView.swift index 4dbdc81620..8b0a8af888 100644 --- a/apps/ios/Shared/Views/ChatList/ServersSummaryView.swift +++ b/apps/ios/Shared/Views/ChatList/ServersSummaryView.swift @@ -245,7 +245,7 @@ struct ServersSummaryView: View { } } - @ViewBuilder private func smpServersListView( + private func smpServersListView( _ servers: [SMPServerSummary], _ statsStartedAt: Date, _ header: LocalizedStringKey? = nil, @@ -256,7 +256,7 @@ struct ServersSummaryView: View { ? serverAddress($0.smpServer) < serverAddress($1.smpServer) : $0.hasSubs && !$1.hasSubs } - Section { + return Section { ForEach(sortedServers) { server in smpServerView(server, statsStartedAt) } @@ -318,14 +318,14 @@ struct ServersSummaryView: View { return onionHosts == .require ? .indigo : .accentColor } - @ViewBuilder private func xftpServersListView( + private func xftpServersListView( _ servers: [XFTPServerSummary], _ statsStartedAt: Date, _ header: LocalizedStringKey? = nil, _ footer: LocalizedStringKey? = nil ) -> some View { let sortedServers = servers.sorted { serverAddress($0.xftpServer) < serverAddress($1.xftpServer) } - Section { + return Section { ForEach(sortedServers) { server in xftpServerView(server, statsStartedAt) } diff --git a/apps/ios/Shared/Views/ChatList/TagListView.swift b/apps/ios/Shared/Views/ChatList/TagListView.swift index 74ed9534e0..2063fe15de 100644 --- a/apps/ios/Shared/Views/ChatList/TagListView.swift +++ b/apps/ios/Shared/Views/ChatList/TagListView.swift @@ -138,7 +138,7 @@ struct TagListView: View { } } - @ViewBuilder private func radioButton(selected: Bool) -> some View { + private func radioButton(selected: Bool) -> some View { Image(systemName: selected ? "checkmark.circle.fill" : "circle") .imageScale(.large) .foregroundStyle(selected ? Color.accentColor : Color(.tertiaryLabel)) diff --git a/apps/ios/Shared/Views/Contacts/ContactListNavLink.swift b/apps/ios/Shared/Views/Contacts/ContactListNavLink.swift index fe840006cd..456c46d318 100644 --- a/apps/ios/Shared/Views/Contacts/ContactListNavLink.swift +++ b/apps/ios/Shared/Views/Contacts/ContactListNavLink.swift @@ -140,9 +140,9 @@ struct ContactListNavLink: View { } } - @ViewBuilder private func previewTitle(_ contact: Contact, titleColor: Color) -> some View { + private func previewTitle(_ contact: Contact, titleColor: Color) -> some View { let t = Text(chat.chatInfo.chatViewName).foregroundColor(titleColor) - ( + return ( contact.verified == true ? verifiedIcon + t : t diff --git a/apps/ios/Shared/Views/Database/DatabaseErrorView.swift b/apps/ios/Shared/Views/Database/DatabaseErrorView.swift index 1ded0acc90..02a1b87826 100644 --- a/apps/ios/Shared/Views/Database/DatabaseErrorView.swift +++ b/apps/ios/Shared/Views/Database/DatabaseErrorView.swift @@ -28,7 +28,7 @@ struct DatabaseErrorView: View { } } - @ViewBuilder private func databaseErrorView() -> some View { + private func databaseErrorView() -> some View { VStack(alignment: .center, spacing: 20) { switch status { case let .errorNotADatabase(dbFile): diff --git a/apps/ios/Shared/Views/Helpers/ViewModifiers.swift b/apps/ios/Shared/Views/Helpers/ViewModifiers.swift index c790b9cff2..85ef85c611 100644 --- a/apps/ios/Shared/Views/Helpers/ViewModifiers.swift +++ b/apps/ios/Shared/Views/Helpers/ViewModifiers.swift @@ -9,6 +9,7 @@ import SwiftUI extension View { + @inline(__always) @ViewBuilder func `if`(_ condition: Bool, transform: (Self) -> Content) -> some View { if condition { transform(self) @@ -36,9 +37,9 @@ struct PrivacyBlur: ViewModifier { .overlay { if (blurred && enabled) { Color.clear.contentShape(Rectangle()) - .onTapGesture { + .simultaneousGesture(TapGesture().onEnded { blurred = false - } + }) } } .onReceive(NotificationCenter.default.publisher(for: .chatViewWillBeginScrolling)) { _ in diff --git a/apps/ios/Shared/Views/LocalAuth/PasscodeEntry.swift b/apps/ios/Shared/Views/LocalAuth/PasscodeEntry.swift index 609943bcb6..4a6f8e7549 100644 --- a/apps/ios/Shared/Views/LocalAuth/PasscodeEntry.swift +++ b/apps/ios/Shared/Views/LocalAuth/PasscodeEntry.swift @@ -28,7 +28,7 @@ struct PasscodeEntry: View { } } - @ViewBuilder private func passwordView() -> some View { + private func passwordView() -> some View { Text( password == "" ? " " diff --git a/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift b/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift index 39656c1534..e5263813fa 100644 --- a/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift +++ b/apps/ios/Shared/Views/NewChat/NewChatMenuButton.swift @@ -85,7 +85,7 @@ struct NewChatSheet: View { } } - @ViewBuilder private func viewBody(_ showArchive: Bool) -> some View { + private func viewBody(_ showArchive: Bool) -> some View { List { HStack { ContactsListSearchBar( @@ -258,7 +258,7 @@ struct ContactsList: View { } } - @ViewBuilder private func noResultSection(text: String) -> some View { + private func noResultSection(text: String) -> some View { Section { Text(text) .foregroundColor(theme.colors.secondary) diff --git a/apps/ios/Shared/Views/NewChat/NewChatView.swift b/apps/ios/Shared/Views/NewChat/NewChatView.swift index 2524b5e682..110eda7882 100644 --- a/apps/ios/Shared/Views/NewChat/NewChatView.swift +++ b/apps/ios/Shared/Views/NewChat/NewChatView.swift @@ -506,7 +506,7 @@ private struct ActiveProfilePicker: View { } } - @ViewBuilder private func profilerPickerUserOption(_ user: User) -> some View { + private func profilerPickerUserOption(_ user: User) -> some View { Button { if selectedProfile == user && incognitoEnabled { incognitoEnabled = false diff --git a/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift b/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift index 45ef186671..17e1735472 100644 --- a/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift +++ b/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift @@ -304,11 +304,11 @@ struct ChooseServerOperators: View { } } - @ViewBuilder private func operatorCheckView(_ serverOperator: ServerOperator) -> some View { + private func operatorCheckView(_ serverOperator: ServerOperator) -> some View { let checked = selectedOperatorIds.contains(serverOperator.operatorId) let icon = checked ? "checkmark.circle.fill" : "circle" let iconColor = checked ? theme.colors.primary : Color(uiColor: .tertiaryLabel).asAnotherColorFromSecondary(theme) - HStack(spacing: 10) { + return HStack(spacing: 10) { Image(serverOperator.largeLogo(colorScheme)) .resizable() .scaledToFit() diff --git a/apps/ios/Shared/Views/UserSettings/AppSettings.swift b/apps/ios/Shared/Views/UserSettings/AppSettings.swift index 00532c0a8e..44e0b20958 100644 --- a/apps/ios/Shared/Views/UserSettings/AppSettings.swift +++ b/apps/ios/Shared/Views/UserSettings/AppSettings.swift @@ -38,7 +38,6 @@ extension AppSettings { privacyLinkPreviewsGroupDefault.set(val) def.setValue(val, forKey: DEFAULT_PRIVACY_LINK_PREVIEWS) } - if let val = privacyChatListOpenLinks { privacyChatListOpenLinksDefault.set(val) } if let val = privacyShowChatPreviews { def.setValue(val, forKey: DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) } if let val = privacySaveLastDraft { def.setValue(val, forKey: DEFAULT_PRIVACY_SAVE_LAST_DRAFT) } if let val = privacyProtectScreen { def.setValue(val, forKey: DEFAULT_PRIVACY_PROTECT_SCREEN) } @@ -78,7 +77,6 @@ extension AppSettings { c.privacyAskToApproveRelays = privacyAskToApproveRelaysGroupDefault.get() c.privacyAcceptImages = privacyAcceptImagesGroupDefault.get() c.privacyLinkPreviews = def.bool(forKey: DEFAULT_PRIVACY_LINK_PREVIEWS) - c.privacyChatListOpenLinks = privacyChatListOpenLinksDefault.get() c.privacyShowChatPreviews = def.bool(forKey: DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) c.privacySaveLastDraft = def.bool(forKey: DEFAULT_PRIVACY_SAVE_LAST_DRAFT) c.privacyProtectScreen = def.bool(forKey: DEFAULT_PRIVACY_PROTECT_SCREEN) diff --git a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/OperatorView.swift b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/OperatorView.swift index 24da6a94a8..afbccc109c 100644 --- a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/OperatorView.swift +++ b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/OperatorView.swift @@ -38,9 +38,9 @@ struct OperatorView: View { .allowsHitTesting(!testing) } - @ViewBuilder private func operatorView() -> some View { + private func operatorView() -> some View { let duplicateHosts = findDuplicateHosts(serverErrors) - VStack { + return VStack { List { Section { infoViewLink() @@ -500,14 +500,14 @@ struct SingleOperatorUsageConditionsView: View { } } - @ViewBuilder private func acceptConditionsButton() -> some View { + private func acceptConditionsButton() -> some View { let operatorIds = ChatModel.shared.conditions.serverOperators .filter { $0.operatorId == userServers[operatorIndex].operator_.operatorId || // Opened operator ($0.enabled && !$0.conditionsAcceptance.conditionsAccepted) // Other enabled operators with conditions not accepted } .map { $0.operatorId } - Button { + return Button { acceptForOperators(operatorIds, operatorIndex) } label: { Text("Accept conditions") diff --git a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/ProtocolServersView.swift b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/ProtocolServersView.swift index ed3c5c773c..b9737914ec 100644 --- a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/ProtocolServersView.swift +++ b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/ProtocolServersView.swift @@ -38,9 +38,9 @@ struct YourServersView: View { .allowsHitTesting(!testing) } - @ViewBuilder private func yourServersView() -> some View { + private func yourServersView() -> some View { let duplicateHosts = findDuplicateHosts(serverErrors) - List { + return List { if !userServers[operatorIndex].smpServers.filter({ !$0.deleted }).isEmpty { Section { ForEach($userServers[operatorIndex].smpServers) { srv in diff --git a/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift b/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift index 1a17b9d661..eba7f8066a 100644 --- a/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift +++ b/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift @@ -14,7 +14,6 @@ struct PrivacySettings: View { @EnvironmentObject var theme: AppTheme @AppStorage(DEFAULT_PRIVACY_ACCEPT_IMAGES) private var autoAcceptImages = true @AppStorage(DEFAULT_PRIVACY_LINK_PREVIEWS) private var useLinkPreviews = true - @State private var chatListOpenLinks = privacyChatListOpenLinksDefault.get() @AppStorage(DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS) private var showChatPreviews = true @AppStorage(DEFAULT_PRIVACY_SAVE_LAST_DRAFT) private var saveLastDraft = true @AppStorage(GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES, store: groupDefaults) private var encryptLocalFiles = true @@ -77,17 +76,6 @@ struct PrivacySettings: View { privacyLinkPreviewsGroupDefault.set(linkPreviews) } } - settingsRow("arrow.up.right.circle", color: theme.colors.secondary) { - Picker("Open links from chat list", selection: $chatListOpenLinks) { - ForEach(PrivacyChatListOpenLinksMode.allCases) { mode in - Text(mode.text) - } - } - } - .frame(height: 36) - .onChange(of: chatListOpenLinks) { mode in - privacyChatListOpenLinksDefault.set(mode) - } settingsRow("message", color: theme.colors.secondary) { Toggle("Show last messages", isOn: $showChatPreviews) } diff --git a/apps/ios/Shared/Views/UserSettings/SettingsView.swift b/apps/ios/Shared/Views/UserSettings/SettingsView.swift index 961cad128f..e06b1c4dd3 100644 --- a/apps/ios/Shared/Views/UserSettings/SettingsView.swift +++ b/apps/ios/Shared/Views/UserSettings/SettingsView.swift @@ -29,7 +29,6 @@ let DEFAULT_WEBRTC_ICE_SERVERS = "webrtcICEServers" let DEFAULT_CALL_KIT_CALLS_IN_RECENTS = "callKitCallsInRecents" let DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages" // unused. Use GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES instead let DEFAULT_PRIVACY_LINK_PREVIEWS = "privacyLinkPreviews" // deprecated, moved to app group -let DEFAULT_PRIVACY_CHAT_LIST_OPEN_LINKS = "privacyChatListOpenLinks" let DEFAULT_PRIVACY_SIMPLEX_LINK_MODE = "privacySimplexLinkMode" let DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS = "privacyShowChatPreviews" let DEFAULT_PRIVACY_SAVE_LAST_DRAFT = "privacySaveLastDraft" @@ -185,8 +184,6 @@ let connectViaLinkTabDefault = EnumDefault(defaults: UserDefa let privacySimplexLinkModeDefault = EnumDefault(defaults: UserDefaults.standard, forKey: DEFAULT_PRIVACY_SIMPLEX_LINK_MODE, withDefault: .description) -let privacyChatListOpenLinksDefault = EnumDefault(defaults: UserDefaults.standard, forKey: DEFAULT_PRIVACY_CHAT_LIST_OPEN_LINKS, withDefault: PrivacyChatListOpenLinksMode.ask) - let privacyLocalAuthModeDefault = EnumDefault(defaults: UserDefaults.standard, forKey: DEFAULT_LA_MODE, withDefault: .system) let privacyDeliveryReceiptsSet = BoolDefault(defaults: UserDefaults.standard, forKey: DEFAULT_PRIVACY_DELIVERY_RECEIPTS_SET) @@ -283,159 +280,159 @@ struct SettingsView: View { } } - @ViewBuilder func settingsView() -> some View { - let user = chatModel.currentUser - List { - Section(header: Text("Settings").foregroundColor(theme.colors.secondary)) { - NavigationLink { - NotificationsView() - .navigationTitle("Notifications") - .modifier(ThemedBackground(grouped: true)) - } label: { - HStack { - notificationsIcon() - Text("Notifications") - } - } - .disabled(chatModel.chatRunning != true) - - NavigationLink { - NetworkAndServers() - .navigationTitle("Network & servers") - .modifier(ThemedBackground(grouped: true)) - } label: { - settingsRow("externaldrive.connected.to.line.below", color: theme.colors.secondary) { Text("Network & servers") } - } - .disabled(chatModel.chatRunning != true) - - NavigationLink { - CallSettings() - .navigationTitle("Your calls") - .modifier(ThemedBackground(grouped: true)) - } label: { - settingsRow("video", color: theme.colors.secondary) { Text("Audio & video calls") } - } - .disabled(chatModel.chatRunning != true) - - NavigationLink { - PrivacySettings() - .navigationTitle("Your privacy") - .modifier(ThemedBackground(grouped: true)) - } label: { - settingsRow("lock", color: theme.colors.secondary) { Text("Privacy & security") } - } - .disabled(chatModel.chatRunning != true) - - if UIApplication.shared.supportsAlternateIcons { - NavigationLink { - AppearanceSettings() - .navigationTitle("Appearance") - .modifier(ThemedBackground(grouped: true)) - } label: { - settingsRow("sun.max", color: theme.colors.secondary) { Text("Appearance") } - } - .disabled(chatModel.chatRunning != true) + func settingsView() -> some View { + List { + let user = chatModel.currentUser + Section(header: Text("Settings").foregroundColor(theme.colors.secondary)) { + NavigationLink { + NotificationsView() + .navigationTitle("Notifications") + .modifier(ThemedBackground(grouped: true)) + } label: { + HStack { + notificationsIcon() + Text("Notifications") } } + .disabled(chatModel.chatRunning != true) - Section(header: Text("Chat database").foregroundColor(theme.colors.secondary)) { - chatDatabaseRow() - NavigationLink { - MigrateFromDevice(showProgressOnSettings: $showProgress) - .toolbar { - // Redaction broken for `.navigationTitle` - using a toolbar item instead. - ToolbarItem(placement: .principal) { - Text("Migrate device").font(.headline) - } - } - .modifier(ThemedBackground(grouped: true)) - .navigationBarTitleDisplayMode(.large) - } label: { - settingsRow("tray.and.arrow.up", color: theme.colors.secondary) { Text("Migrate to another device") } - } + NavigationLink { + NetworkAndServers() + .navigationTitle("Network & servers") + .modifier(ThemedBackground(grouped: true)) + } label: { + settingsRow("externaldrive.connected.to.line.below", color: theme.colors.secondary) { Text("Network & servers") } } - - Section(header: Text("Help").foregroundColor(theme.colors.secondary)) { - if let user = user { - NavigationLink { - ChatHelp(dismissSettingsSheet: dismiss) - .navigationTitle("Welcome \(user.displayName)!") - .modifier(ThemedBackground()) - .frame(maxHeight: .infinity, alignment: .top) - } label: { - settingsRow("questionmark", color: theme.colors.secondary) { Text("How to use it") } - } - } + .disabled(chatModel.chatRunning != true) + + NavigationLink { + CallSettings() + .navigationTitle("Your calls") + .modifier(ThemedBackground(grouped: true)) + } label: { + settingsRow("video", color: theme.colors.secondary) { Text("Audio & video calls") } + } + .disabled(chatModel.chatRunning != true) + + NavigationLink { + PrivacySettings() + .navigationTitle("Your privacy") + .modifier(ThemedBackground(grouped: true)) + } label: { + settingsRow("lock", color: theme.colors.secondary) { Text("Privacy & security") } + } + .disabled(chatModel.chatRunning != true) + + if UIApplication.shared.supportsAlternateIcons { NavigationLink { - WhatsNewView(viaSettings: true, updatedConditions: false) - .modifier(ThemedBackground()) - .navigationBarTitleDisplayMode(.inline) + AppearanceSettings() + .navigationTitle("Appearance") + .modifier(ThemedBackground(grouped: true)) } label: { - settingsRow("plus", color: theme.colors.secondary) { Text("What's new") } + settingsRow("sun.max", color: theme.colors.secondary) { Text("Appearance") } } + .disabled(chatModel.chatRunning != true) + } + } + + Section(header: Text("Chat database").foregroundColor(theme.colors.secondary)) { + chatDatabaseRow() + NavigationLink { + MigrateFromDevice(showProgressOnSettings: $showProgress) + .toolbar { + // Redaction broken for `.navigationTitle` - using a toolbar item instead. + ToolbarItem(placement: .principal) { + Text("Migrate device").font(.headline) + } + } + .modifier(ThemedBackground(grouped: true)) + .navigationBarTitleDisplayMode(.large) + } label: { + settingsRow("tray.and.arrow.up", color: theme.colors.secondary) { Text("Migrate to another device") } + } + } + + Section(header: Text("Help").foregroundColor(theme.colors.secondary)) { + if let user = user { NavigationLink { - SimpleXInfo(onboarding: false) - .navigationBarTitle("", displayMode: .inline) + ChatHelp(dismissSettingsSheet: dismiss) + .navigationTitle("Welcome \(user.displayName)!") .modifier(ThemedBackground()) .frame(maxHeight: .infinity, alignment: .top) } label: { - settingsRow("info", color: theme.colors.secondary) { Text("About SimpleX Chat") } + settingsRow("questionmark", color: theme.colors.secondary) { Text("How to use it") } } - settingsRow("number", color: theme.colors.secondary) { - Button("Send questions and ideas") { - dismiss() - DispatchQueue.main.async { - UIApplication.shared.open(simplexTeamURL) - } + } + NavigationLink { + WhatsNewView(viaSettings: true, updatedConditions: false) + .modifier(ThemedBackground()) + .navigationBarTitleDisplayMode(.inline) + } label: { + settingsRow("plus", color: theme.colors.secondary) { Text("What's new") } + } + NavigationLink { + SimpleXInfo(onboarding: false) + .navigationBarTitle("", displayMode: .inline) + .modifier(ThemedBackground()) + .frame(maxHeight: .infinity, alignment: .top) + } label: { + settingsRow("info", color: theme.colors.secondary) { Text("About SimpleX Chat") } + } + settingsRow("number", color: theme.colors.secondary) { + Button("Send questions and ideas") { + dismiss() + DispatchQueue.main.async { + UIApplication.shared.open(simplexTeamURL) } } - .disabled(chatModel.chatRunning != true) - settingsRow("envelope", color: theme.colors.secondary) { Text("[Send us email](mailto:chat@simplex.chat)") } } + .disabled(chatModel.chatRunning != true) + settingsRow("envelope", color: theme.colors.secondary) { Text("[Send us email](mailto:chat@simplex.chat)") } + } - Section(header: Text("Support SimpleX Chat").foregroundColor(theme.colors.secondary)) { - settingsRow("keyboard", color: theme.colors.secondary) { Text("[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)") } - settingsRow("star", color: theme.colors.secondary) { - Button("Rate the app") { - if let scene = sceneDelegate.windowScene { - SKStoreReviewController.requestReview(in: scene) - } + Section(header: Text("Support SimpleX Chat").foregroundColor(theme.colors.secondary)) { + settingsRow("keyboard", color: theme.colors.secondary) { Text("[Contribute](https://github.com/simplex-chat/simplex-chat#contribute)") } + settingsRow("star", color: theme.colors.secondary) { + Button("Rate the app") { + if let scene = sceneDelegate.windowScene { + SKStoreReviewController.requestReview(in: scene) } } - ZStack(alignment: .leading) { - Image(colorScheme == .dark ? "github_light" : "github") - .resizable() - .frame(width: 24, height: 24) - .opacity(0.5) - .colorMultiply(theme.colors.secondary) - Text("[Star on GitHub](https://github.com/simplex-chat/simplex-chat)") - .padding(.leading, indent) - } } + ZStack(alignment: .leading) { + Image(colorScheme == .dark ? "github_light" : "github") + .resizable() + .frame(width: 24, height: 24) + .opacity(0.5) + .colorMultiply(theme.colors.secondary) + Text("[Star on GitHub](https://github.com/simplex-chat/simplex-chat)") + .padding(.leading, indent) + } + } - Section(header: Text("Develop").foregroundColor(theme.colors.secondary)) { - NavigationLink { - DeveloperView() - .navigationTitle("Developer tools") - .modifier(ThemedBackground(grouped: true)) - } label: { - settingsRow("chevron.left.forwardslash.chevron.right", color: theme.colors.secondary) { Text("Developer tools") } - } - NavigationLink { - VersionView() - .navigationBarTitle("App version") - .modifier(ThemedBackground()) - } label: { - Text("v\(appVersion ?? "?") (\(appBuild ?? "?"))") - } + Section(header: Text("Develop").foregroundColor(theme.colors.secondary)) { + NavigationLink { + DeveloperView() + .navigationTitle("Developer tools") + .modifier(ThemedBackground(grouped: true)) + } label: { + settingsRow("chevron.left.forwardslash.chevron.right", color: theme.colors.secondary) { Text("Developer tools") } + } + NavigationLink { + VersionView() + .navigationBarTitle("App version") + .modifier(ThemedBackground()) + } label: { + Text("v\(appVersion ?? "?") (\(appBuild ?? "?"))") } } - .navigationTitle("Your settings") - .modifier(ThemedBackground(grouped: true)) - .onDisappear { - chatModel.showingTerminal = false - chatModel.terminalItems = [] - } + } + .navigationTitle("Your settings") + .modifier(ThemedBackground(grouped: true)) + .onDisappear { + chatModel.showingTerminal = false + chatModel.terminalItems = [] + } } private func chatDatabaseRow() -> some View { diff --git a/apps/ios/Shared/Views/UserSettings/UserProfile.swift b/apps/ios/Shared/Views/UserSettings/UserProfile.swift index 8a70efbe82..9aa42930bf 100644 --- a/apps/ios/Shared/Views/UserSettings/UserProfile.swift +++ b/apps/ios/Shared/Views/UserSettings/UserProfile.swift @@ -133,7 +133,6 @@ struct UserProfile: View { .alert(item: $alert) { a in userProfileAlert(a, $profile.displayName) } } - @ViewBuilder private func overlayButton( _ systemName: String, edge: Edge.Set, diff --git a/apps/ios/Shared/Views/UserSettings/UserProfilesView.swift b/apps/ios/Shared/Views/UserSettings/UserProfilesView.swift index 781ea4bc34..887023b670 100644 --- a/apps/ios/Shared/Views/UserSettings/UserProfilesView.swift +++ b/apps/ios/Shared/Views/UserSettings/UserProfilesView.swift @@ -221,11 +221,11 @@ struct UserProfilesView: View { !user.hidden ? nil : trimmedSearchTextOrPassword } - @ViewBuilder private func profileActionView(_ action: UserProfileAction) -> some View { + private func profileActionView(_ action: UserProfileAction) -> some View { let passwordValid = actionPassword == actionPassword.trimmingCharacters(in: .whitespaces) let passwordField = PassphraseField(key: $actionPassword, placeholder: "Profile password", valid: passwordValid) let actionEnabled: (User) -> Bool = { user in actionPassword != "" && passwordValid && correctPassword(user, actionPassword) } - List { + return List { switch action { case let .deleteUser(user, delSMPQueues): actionHeader("Delete profile", user) diff --git a/apps/ios/SimpleX Localizations/ar.xcloc/Localized Contents/ar.xliff b/apps/ios/SimpleX Localizations/ar.xcloc/Localized Contents/ar.xliff index 613a5e08ad..278b9ec9b2 100644 --- a/apps/ios/SimpleX Localizations/ar.xcloc/Localized Contents/ar.xliff +++ b/apps/ios/SimpleX Localizations/ar.xcloc/Localized Contents/ar.xliff @@ -814,8 +814,9 @@ جهة الاتصال مخفية: notification - + Contact is connected + تم الاتصال notification @@ -850,8 +851,9 @@ Core built at: %@ No comment provided by engineer. - + Core version: v%@ + الإصدار الأساسي: v%@ No comment provided by engineer. @@ -901,8 +903,9 @@ عبارة المرور الحالية… No comment provided by engineer. - + Currently maximum supported file size is %@. + الحد الأقصى لحجم الملف المدعوم حاليًا هو %@. No comment provided by engineer. @@ -920,9 +923,11 @@ قاعدة البيانات مُعمّاة! No comment provided by engineer. - + Database encryption passphrase will be updated and stored in the keychain. + سيتم تحديث عبارة المرور الخاصة بتشفير قاعدة البيانات وتخزينها في سلسلة المفاتيح. + No comment provided by engineer. @@ -957,8 +962,9 @@ عبارة مرور قاعدة البيانات وتصديرها No comment provided by engineer. - + Database passphrase is different from saved in the keychain. + عبارة المرور الخاصة بقاعدة البيانات مختلفة عن تلك المحفوظة في سلسلة المفاتيح. No comment provided by engineer. @@ -966,9 +972,11 @@ عبارة مرور قاعدة البيانات مطلوبة لفتح الدردشة. No comment provided by engineer. - + Database will be encrypted and the passphrase stored in the keychain. + سيتم تشفير قاعدة البيانات وتخزين عبارة المرور في سلسلة المفاتيح. + No comment provided by engineer. @@ -978,8 +986,9 @@ No comment provided by engineer. - + Database will be migrated when the app restarts + سيتم نقل قاعدة البيانات عند إعادة تشغيل التطبيق No comment provided by engineer. @@ -1079,36 +1088,44 @@ حذف المجموعة؟ No comment provided by engineer. - + Delete invitation + حذف الدعوة No comment provided by engineer. - + Delete link + حذف الرابط No comment provided by engineer. - + Delete link? + حذف الرابط؟ No comment provided by engineer. - + Delete message? + حذف الرسالة؟ No comment provided by engineer. - + Delete messages + حذف الرسائل No comment provided by engineer. - + Delete messages after + حذف الرسائل بعد No comment provided by engineer. - + Delete old database + حذف قاعدة البيانات القديمة No comment provided by engineer. - + Delete old database? + حذف قاعدة البيانات القديمة؟ No comment provided by engineer. @@ -1125,8 +1142,9 @@ حذف قائمة الانتظار server test step - + Delete user profile? + حذف ملف تعريف المستخدم؟ No comment provided by engineer. @@ -1134,8 +1152,9 @@ الوصف No comment provided by engineer. - + Develop + يطور No comment provided by engineer. @@ -1168,28 +1187,34 @@ رسائل مباشرة chat feature - + Direct messages between members are prohibited. + الرسائل المباشرة بين الأعضاء ممنوعة. No comment provided by engineer. - + Disable SimpleX Lock + تعطيل قفل SimpleX authentication reason - + Disappearing messages + الرسائل المختفية chat feature - + Disappearing messages are prohibited in this chat. + يُحظر اختفاء الرسائل في هذه الدردشة. No comment provided by engineer. - + Disappearing messages are prohibited. + الرسائل المختفية ممنوعة. No comment provided by engineer. - + Disconnect + قطع الاتصال server test step @@ -1200,12 +1225,14 @@ Display name: No comment provided by engineer. - + Do NOT use SimpleX for emergency calls. + لا تستخدم SimpleX لإجراء مكالمات الطوارئ. No comment provided by engineer. - + Do it later + افعل ذلك لاحقا No comment provided by engineer. @@ -1258,76 +1285,93 @@ تفعيل الإشعارات دورية؟ No comment provided by engineer. - + Encrypt + التشفير No comment provided by engineer. - + Encrypt database? + تشفير قاعدة البيانات؟ No comment provided by engineer. - + Encrypted database + قاعدة بيانات مشفرة No comment provided by engineer. - + Encrypted message or another event + رسالة مشفرة أو حدث آخر notification - + Encrypted message: database error + رسالة مشفرة: خطأ في قاعدة البيانات notification - + Encrypted message: keychain error + رسالة مشفرة: خطأ في سلسلة المفاتيح notification - + Encrypted message: no passphrase + الرسالة المشفرة: لا توجد عبارة مرور notification - + Encrypted message: unexpected error + رسالة مشفرة: خطأ غير متوقع notification - + Enter correct passphrase. + أدخل عبارة المرور الصحيحة. No comment provided by engineer. - + Enter passphrase… + أدخل عبارة المرور… No comment provided by engineer. - + Enter server manually + أدخل الخادم يدوياً No comment provided by engineer. - + Error + خطأ No comment provided by engineer. - + Error accepting contact request + خطأ في قبول طلب الاتصال No comment provided by engineer. Error accessing database file No comment provided by engineer. - + Error adding member(s) + خطأ في إضافة عضو (أعضاء) No comment provided by engineer. - + Error changing address + خطأ في تغيير العنوان No comment provided by engineer. - + Error changing role + خطأ في تغيير الدور المتغير No comment provided by engineer. - + Error changing setting + خطأ في تغيير الإعدادات No comment provided by engineer. @@ -5477,6 +5521,242 @@ This is your own one-time link! Conditions will be automatically accepted for enabled operators on: %@. سيتم قبول الشروط تلقائيًا للمشغلين الممكّنين على: %@. + + Create new profile in [desktop app](https://simplex.chat/downloads/). 💻 + أنشئ ملفًا شخصيًا جديدًا في [تطبيق سطح المكتب](https://simplex.chat/downloads/). 💻 + + + Error adding server + خطأ في إضافة الخادم + + + Created at: %@ + تم الإنشاء في: %@ + + + Delete %lld messages of members? + حذف %lld الرسائل القديمة للأعضاء؟ + + + Disappearing message + رسالة اختفاء + + + Enabled + ممكّنة + + + Encrypted message: database migration error + رسالة مشفرة: خطأ في ترحيل قاعدة البيانات + + + Delete list? + Delete list? + + + Delivered even when Apple drops them. + يتم تسليمها حتى عندما تسقطها شركة Apple. + + + Destination server address of %@ is incompatible with forwarding server %@ settings. + عنوان خادم الوجهة %@ غير متوافق مع إعدادات خادم التوجيه %@. + + + Destination server version of %@ is incompatible with forwarding server %@. + إصدار خادم الوجهة لـ %@ غير متوافق مع خادم التوجيه %@. + + + Don't create address + لا تنشئ عنوان + + + Done + تم + + + Duration + المدة + + + Encrypt local files + تشفير الملفات المحلية + + + Encryption renegotiation in progress. + إعادة التفاوض على التشفير قيد التنفيذ. + + + Enter Passcode + أدخل رمز المرور + + + Enter passphrase + قم بأدخل عبارة المرور + + + Enter welcome message… + أدخل رسالة ترحيب… + + + Enter your name… + أدخل اسمك… + + + Error changing to incognito! + خطأ في التغيير إلى التصفح المتخفي! + + + Delete %lld messages? + حذف %lld رسائل؟ + + + Error aborting address change + خطأ في إجهاض تغيير العنوان + + + Disappears at + يختفي عند + + + Do not use credentials with proxy. + لا تستخدم بيانات الاعتماد مع البروكسي. + + + Error accepting conditions + خطأ في قبول الشروط + + + Enter password above to show! + أدخل كلمة المرور أعلاه للعرض! + + + Error changing connection profile + خطأ في تغيير ملف تعريف الاتصال + + + Desktop app version %@ is not compatible with this app. + إصدار تطبيق سطح المكتب %@ غير متوافق مع هذا التطبيق. + + + Encrypt stored files & media + تشفير الملفات والوسائط المخزنة + + + Enter this device name… + أدخل اسم الجهاز… + + + Enter welcome message… (optional) + أدخل رسالة ترحيب... (اختياري) + + + Correct name to %@? + الاسم الصحيح ل %@؟ + + + Delete member message? + حذف رسالة العضو؟ + + + Disable automatic message deletion? + تعطيل حذف الرسائل التلقائي؟ + + + Disable delete messages + تعطيل حذف الرسائل + + + Disable for all + تعطيل للجميع + + + Disabled + عاجز + + + Documents: + المستندات: + + + By using SimpleX Chat you agree to: +- send only legal content in public groups. +- respect other users – no spam. + باستخدامك SimpleX Chat، فإنك توافق على: +- إرسال محتوى قانوني فقط في المجموعات العامة. +- احترام المستخدمين الآخرين - ممنوع إرسال رسائل مزعجة. + + + Configure server operators + تكوين مشغلي الخادم + + + Enable Flux in Network & servers settings for better metadata privacy. + تمكين التدفق في إعدادات الشبكة والخوادم لتحسين خصوصية البيانات الوصفية. + + + Discover and join groups + اكتشف المجموعات وانضم إليها + + + Discover via local network + اكتشف عبر الشبكة المحلية + + + Enabled for + ممكّن ل + + + Encrypted message: app is stopped + رسالة مشفرة: تم إيقاف التطبيق + + + Enter group name… + أدخل اسم المجموعة… + + + Do NOT use private routing. + لا تستخدم التوجيه الخاص. + + + Encryption re-negotiation error + خطأ في إعادة تفاوض التشفير + + + Connection with desktop stopped + تم إيقاف الاتصال بسطح المكتب + + + Destination server error: %@ + خطأ خادم الوجهة: %@ + + + Do NOT send messages directly, even if your or destination server does not support private routing. + لا ترسل الرسائل بشكل مباشر، حتى لو كان خادمك أو خادم الوجهة لا يدعم التوجيه الخاص. + + + Direct messages between members are prohibited in this chat. + يُحظر إرسال الرسائل المباشرة بين الأعضاء في هذه الدردشة. + + + Disconnect desktop? + فصل سطح المكتب؟ + + + Disable (keep overrides) + تعطيل (الاحتفاظ بالتجاوزات) + + + Disappears at: %@ + يختفي عند: %@ + + + Do not send history to new members. + لا ترسل التاريخ إلى الأعضاء الجدد. + + + Encryption re-negotiation failed. + فشل إعادة التفاوض على التشفير. + diff --git a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff index 213394aa14..56553b3283 100644 --- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff +++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff @@ -778,6 +778,10 @@ swipe action All reports will be archived for you. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Всички ваши контакти ще останат свързани. @@ -1059,10 +1063,6 @@ swipe action Архивиране на база данни No comment provided by engineer. - - Ask - No comment provided by engineer. - Attach Прикачи @@ -5260,7 +5260,7 @@ Requires compatible VPN. Open Отвори - No comment provided by engineer. + alert action Open Settings @@ -5290,23 +5290,15 @@ Requires compatible VPN. Отвори група No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device Отвори миграцията към друго устройство authentication reason - - Open web link? - No comment provided by engineer. - Opening app… Приложението се отваря… @@ -7832,6 +7824,10 @@ To connect, please ask your contact to create another connection link and check Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Използвай чата @@ -8177,10 +8173,6 @@ To connect, please ask your contact to create another connection link and check XFTP server No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. **Не трябва** да използвате една и съща база данни на две устройства. @@ -9661,6 +9653,10 @@ last received msg: %2$@ %d new events notification body + + From %d chat(s) + notification body + From: %@ notification body @@ -9673,10 +9669,6 @@ last received msg: %2$@ New messages notification - - New messages in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff index 826ad0171b..21bf0aef60 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -145,18 +145,22 @@ %d file(s) are still being downloaded. + %d soubor(y) stále stahován(y). forward confirmation reason %d file(s) failed to download. + %d soubor(y) se nepodařilo stáhnout. forward confirmation reason %d file(s) were deleted. + %d soubor(y) smazán(y). forward confirmation reason %d file(s) were not downloaded. + %d soubor(y) nestažen(y). forward confirmation reason @@ -743,6 +747,10 @@ swipe action All reports will be archived for you. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Všechny vaše kontakty zůstanou připojeny. @@ -1008,10 +1016,6 @@ swipe action Archiving database No comment provided by engineer. - - Ask - No comment provided by engineer. - Attach Připojit @@ -5060,7 +5064,7 @@ Vyžaduje povolení sítě VPN. Open Otevřít - No comment provided by engineer. + alert action Open Settings @@ -5089,22 +5093,14 @@ Vyžaduje povolení sítě VPN. Open group No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device authentication reason - - Open web link? - No comment provided by engineer. - Opening app… No comment provided by engineer. @@ -7560,6 +7556,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Použijte chat @@ -7885,10 +7885,6 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu XFTP server No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. No comment provided by engineer. @@ -9323,6 +9319,10 @@ last received msg: %2$@ %d new events notification body + + From %d chat(s) + notification body + From: %@ notification body @@ -9335,10 +9335,6 @@ last received msg: %2$@ New messages notification - - New messages in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff index facf6d5a9e..a113d35bbd 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -796,6 +796,11 @@ swipe action Alle Meldungen werden für Sie archiviert. No comment provided by engineer. + + All servers + Alle Server + No comment provided by engineer. + All your contacts will remain connected. Alle Ihre Kontakte bleiben verbunden. @@ -1086,11 +1091,6 @@ swipe action Datenbank wird archiviert No comment provided by engineer. - - Ask - Fragen - No comment provided by engineer. - Attach Anhängen @@ -2195,7 +2195,7 @@ Das ist Ihr eigener Einmal-Link! Current profile - Aktueller Profil + Aktuelles Profil No comment provided by engineer. @@ -5541,7 +5541,7 @@ Dies erfordert die Aktivierung eines VPNs. Open Öffnen - No comment provided by engineer. + alert action Open Settings @@ -5573,26 +5573,15 @@ Dies erfordert die Aktivierung eines VPNs. Gruppe öffnen No comment provided by engineer. - - Open link - Web-Link öffnen - No comment provided by engineer. - - - Open links from chat list - Web-Links aus der Chat-Liste öffnen - No comment provided by engineer. + + Open link? + alert title Open migration to another device Migration auf ein anderes Gerät öffnen authentication reason - - Open web link? - Web-Link öffnen? - No comment provided by engineer. - Opening app… App wird geöffnet… @@ -7201,6 +7190,7 @@ chat item action Short link + Verkürzter Link No comment provided by engineer. @@ -7305,6 +7295,7 @@ chat item action SimpleX channel link + SimpleX-Kanal-Link simplex link type @@ -7899,6 +7890,7 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link. + Für diesen Link wird eine neuere App-Version benötigt. Bitte aktualisieren Sie die App oder bitten Sie Ihren Kontakt einen kompatiblen Link zu senden. No comment provided by engineer. @@ -8202,6 +8194,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s Unsupported connection link + Verbindungs-Link wird nicht unterstützt No comment provided by engineer. @@ -8299,6 +8292,11 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s Solange kein Port konfiguriert ist, wird TCP-Port %@ genutzt. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + TCP-Port 443 nur für voreingestellte Server verwenden. + No comment provided by engineer. + Use chat Verwenden Sie Chat @@ -8366,6 +8364,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s Use short links (BETA) + Kurze Links verwenden (BETA) No comment provided by engineer. @@ -8663,11 +8662,6 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s XFTP-Server No comment provided by engineer. - - Yes - Ja - No comment provided by engineer. - You **must not** use the same database on two devices. Sie dürfen die selbe Datenbank **nicht** auf zwei Geräten nutzen. @@ -10191,6 +10185,11 @@ Zuletzt empfangene Nachricht: %2$@ %d neue Ereignisse notification body + + From %d chat(s) + Von %d Chat(s) + notification body + From: %@ Von: %@ @@ -10206,11 +10205,6 @@ Zuletzt empfangene Nachricht: %2$@ Neue Nachrichten notification - - New messages in %d chats - Neue Nachrichten in %d Chats - notification body - diff --git a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff index 9eb60c2cbc..641af86c2a 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -796,6 +796,11 @@ swipe action All reports will be archived for you. No comment provided by engineer. + + All servers + All servers + No comment provided by engineer. + All your contacts will remain connected. All your contacts will remain connected. @@ -1086,11 +1091,6 @@ swipe action Archiving database No comment provided by engineer. - - Ask - Ask - No comment provided by engineer. - Attach Attach @@ -5541,7 +5541,7 @@ Requires compatible VPN. Open Open - No comment provided by engineer. + alert action Open Settings @@ -5573,26 +5573,16 @@ Requires compatible VPN. Open group No comment provided by engineer. - - Open link - Open link - No comment provided by engineer. - - - Open links from chat list - Open links from chat list - No comment provided by engineer. + + Open link? + Open link? + alert title Open migration to another device Open migration to another device authentication reason - - Open web link? - Open web link? - No comment provided by engineer. - Opening app… Opening app… @@ -8303,6 +8293,11 @@ To connect, please ask your contact to create another connection link and check Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Use chat @@ -8668,11 +8663,6 @@ To connect, please ask your contact to create another connection link and check XFTP server No comment provided by engineer. - - Yes - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. You **must not** use the same database on two devices. @@ -10196,6 +10186,11 @@ last received msg: %2$@ %d new events notification body + + From %d chat(s) + From %d chat(s) + notification body + From: %@ From: %@ @@ -10211,11 +10206,6 @@ last received msg: %2$@ New messages notification - - New messages in %d chats - New messages in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff index 5250aa0de7..73f88e1cab 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -796,6 +796,11 @@ swipe action Todos los informes serán archivados para ti. No comment provided by engineer. + + All servers + Todos los servidores + No comment provided by engineer. + All your contacts will remain connected. Todos tus contactos permanecerán conectados. @@ -1086,11 +1091,6 @@ swipe action Archivando base de datos No comment provided by engineer. - - Ask - Preguntar - No comment provided by engineer. - Attach Adjuntar @@ -5541,7 +5541,7 @@ Requiere activación de la VPN. Open Abrir - No comment provided by engineer. + alert action Open Settings @@ -5573,26 +5573,15 @@ Requiere activación de la VPN. Grupo abierto No comment provided by engineer. - - Open link - Abrir enlace - No comment provided by engineer. - - - Open links from chat list - Abrir enlaces desde listado de chats - No comment provided by engineer. + + Open link? + alert title Open migration to another device Abrir menú migración a otro dispositivo authentication reason - - Open web link? - ¿Abrir enlace web? - No comment provided by engineer. - Opening app… Iniciando aplicación… @@ -7201,6 +7190,7 @@ chat item action Short link + Enlace corto No comment provided by engineer. @@ -7305,6 +7295,7 @@ chat item action SimpleX channel link + Enlace de canal SimpleX simplex link type @@ -7899,6 +7890,7 @@ Puede ocurrir por algún bug o cuando la conexión está comprometida. This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link. + Este enlace requiere una versión más reciente de la aplicación. Por favor, actualiza la aplicación o pide a tu contacto un enlace compatible. No comment provided by engineer. @@ -8095,7 +8087,7 @@ Se te pedirá que completes la autenticación antes de activar esta función. Unblock member for all? - ¿Desbloquear miembro para todos? + ¿Desbloquear el miembro para todos? No comment provided by engineer. @@ -8202,6 +8194,7 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión Unsupported connection link + Enlace de conexión no compatible No comment provided by engineer. @@ -8299,6 +8292,11 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión Se usa el puerto TCP %@ cuando no se ha especificado otro. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + Usar puerto TCP 443 solo en servidores predefinidos. + No comment provided by engineer. + Use chat Usar Chat @@ -8366,6 +8364,7 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión Use short links (BETA) + Usar enlaces cortos (BETA) No comment provided by engineer. @@ -8663,11 +8662,6 @@ Para conectarte pide a tu contacto que cree otro enlace y comprueba la conexión Servidor XFTP No comment provided by engineer. - - Yes - Si - No comment provided by engineer. - You **must not** use the same database on two devices. **No debes** usar la misma base de datos en dos dispositivos. @@ -10191,6 +10185,11 @@ last received msg: %2$@ %d evento(s) nuevo(s) notification body + + From %d chat(s) + De %d chat(s) + notification body + From: %@ De: %@ @@ -10206,11 +10205,6 @@ last received msg: %2$@ Mensajes nuevos notification - - New messages in %d chats - Mensajes nuevos en %d chat(s) - notification body - diff --git a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff index 8dc4250e20..5281fbc701 100644 --- a/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff +++ b/apps/ios/SimpleX Localizations/fi.xcloc/Localized Contents/fi.xliff @@ -730,6 +730,10 @@ swipe action All reports will be archived for you. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Kaikki kontaktisi pysyvät yhteydessä. @@ -994,10 +998,6 @@ swipe action Archiving database No comment provided by engineer. - - Ask - No comment provided by engineer. - Attach Liitä @@ -5040,7 +5040,7 @@ Edellyttää VPN:n sallimista. Open - No comment provided by engineer. + alert action Open Settings @@ -5069,22 +5069,14 @@ Edellyttää VPN:n sallimista. Open group No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device authentication reason - - Open web link? - No comment provided by engineer. - Opening app… No comment provided by engineer. @@ -7537,6 +7529,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Käytä chattia @@ -7862,10 +7858,6 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja XFTP server No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. No comment provided by engineer. @@ -9298,6 +9290,10 @@ last received msg: %2$@ %d new events notification body + + From %d chat(s) + notification body + From: %@ notification body @@ -9310,10 +9306,6 @@ last received msg: %2$@ New messages notification - - New messages in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff index 304b9e2084..1e5da0b0ed 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -796,6 +796,10 @@ swipe action Tous les rapports seront archivés pour vous. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Tous vos contacts resteront connectés. @@ -1085,11 +1089,6 @@ swipe action Archivage de la base de données No comment provided by engineer. - - Ask - Demander - No comment provided by engineer. - Attach Attacher @@ -5506,7 +5505,7 @@ Nécessite l'activation d'un VPN. Open Ouvrir - No comment provided by engineer. + alert action Open Settings @@ -5538,23 +5537,15 @@ Nécessite l'activation d'un VPN. Ouvrir le groupe No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device Ouvrir le transfert vers un autre appareil authentication reason - - Open web link? - No comment provided by engineer. - Opening app… Ouverture de l'app… @@ -8227,6 +8218,10 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Utiliser le chat @@ -8590,10 +8585,6 @@ Pour vous connecter, veuillez demander à votre contact de créer un autre lien Serveur XFTP No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. Vous **ne devez pas** utiliser la même base de données sur deux appareils. @@ -10111,6 +10102,10 @@ dernier message reçu : %2$@ %d nouveaux événements notification body + + From %d chat(s) + notification body + From: %@ De : %@ @@ -10126,11 +10121,6 @@ dernier message reçu : %2$@ Nouveaux messages notification - - New messages in %d chats - Nouveaux messages dans %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff index f24ba2b781..9be5879eb6 100644 --- a/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff +++ b/apps/ios/SimpleX Localizations/hu.xcloc/Localized Contents/hu.xliff @@ -768,7 +768,7 @@ swipe action All messages and files are sent **end-to-end encrypted**, with post-quantum security in direct messages. - Az összes üzenet és fájl **végpontok közötti titkosítással**, a közvetlen üzenetek továbbá kvantumálló titkosítással is rendelkeznek. + Az összes üzenet és fájl **végpontok közötti titkosítással**, a közvetlen üzenetek továbbá kvantumbiztos titkosítással is rendelkeznek. No comment provided by engineer. @@ -796,6 +796,11 @@ swipe action Az összes jelentés archiválva lesz az Ön számára. No comment provided by engineer. + + All servers + Összes kiszolgáló + No comment provided by engineer. + All your contacts will remain connected. Az összes partnerével kapcsolatban marad. @@ -1086,14 +1091,9 @@ swipe action Adatbázis archiválása No comment provided by engineer. - - Ask - Mindig kérdezzen rá - No comment provided by engineer. - Attach - Csatolás + Mellékelés No comment provided by engineer. @@ -4055,7 +4055,7 @@ Hiba: %2$@ Hide: - Elrejtés: + Elrejtve: No comment provided by engineer. @@ -4942,12 +4942,12 @@ Ez a saját hivatkozása a(z) %@ nevű csoporthoz! Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery. - Az üzeneteket, fájlokat és hívásokat **végpontok közötti titkosítással**, sérülés utáni titkosság-védelemmel és -helyreállítással, továbbá visszautasítással védi. + Az üzenetek, a fájlok és a hívások **végpontok közötti titkosítással**, sérülés utáni titkosságvédelemmel és -helyreállítással, továbbá letagadhatósággal vannak védve. No comment provided by engineer. Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery. - Az üzenetek, fájlok és hívások **végpontok közötti kvantumálló titkosítással** sérülés utáni titkosságvédelemmel, visszautasítással és feltörés utáni helyreállítással vannak védve. + Az üzenetek, a fájlok és a hívások **végpontok közötti kvantumbiztos titkosítással**, sérülés utáni titkosságvédelemmel és -helyreállítással, továbbá letagadhatósággal vannak védve. No comment provided by engineer. @@ -5541,7 +5541,7 @@ VPN engedélyezése szükséges. Open Megnyitás - No comment provided by engineer. + alert action Open Settings @@ -5573,26 +5573,15 @@ VPN engedélyezése szükséges. Csoport megnyitása No comment provided by engineer. - - Open link - Hivatkozás megnyitása - No comment provided by engineer. - - - Open links from chat list - Hivatkozás megnyitása a csevegési listából - No comment provided by engineer. + + Open link? + alert title Open migration to another device Átköltöztetés indítása egy másik eszközre authentication reason - - Open web link? - Megnyitja a webhivatkozást? - No comment provided by engineer. - Opening app… Az alkalmazás megnyitása… @@ -5906,7 +5895,7 @@ Hiba: %@ Privacy redefined - Adatvédelem újraértelmezve + Újraértelmezett adatvédelem No comment provided by engineer. @@ -6088,7 +6077,7 @@ Engedélyezze a *Hálózat és kiszolgálók* menüben. Quantum resistant encryption - Kvantumálló titkosítás + Kvantumbiztos titkosítás No comment provided by engineer. @@ -7201,6 +7190,7 @@ chat item action Short link + Rövid hivatkozás No comment provided by engineer. @@ -7245,7 +7235,7 @@ chat item action Show: - Megjelenítés: + Megjelenítve: No comment provided by engineer. @@ -7305,6 +7295,7 @@ chat item action SimpleX channel link + SimpleX-csatornahivatkozás simplex link type @@ -7864,7 +7855,7 @@ Ez valamilyen hiba vagy sérült kapcsolat esetén fordulhat elő. This chat is protected by quantum resistant end-to-end encryption. - Ez a csevegés végpontok közötti kvantumálló titkosítással védett. + Ez a csevegés végpontok közötti kvantumbiztos titkosítással védett. E2EE info chat item @@ -7899,6 +7890,7 @@ Ez valamilyen hiba vagy sérült kapcsolat esetén fordulhat elő. This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link. + Ez a hivatkozás újabb alkalmazásverziót igényel. Frissítse az alkalmazást vagy kérjen egy kompatibilis hivatkozást a partnerétől. No comment provided by engineer. @@ -8202,6 +8194,7 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso Unsupported connection link + Nem támogatott kapcsolattartási hivatkozás No comment provided by engineer. @@ -8299,6 +8292,11 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso A következő TCP-port használata, amikor nincs port megadva: %@. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + A 443-as TCP-port használata kizárólag az előre beállított kiszolgálokhoz. + No comment provided by engineer. + Use chat SimpleX Chat használata @@ -8366,6 +8364,7 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso Use short links (BETA) + Rövid hivatkozások használata (béta) No comment provided by engineer. @@ -8440,7 +8439,7 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso Via secure quantum resistant protocol. - Biztonságos kvantumálló-protokollon keresztül. + Biztonságos kvantumbiztos protokollon keresztül. No comment provided by engineer. @@ -8663,11 +8662,6 @@ A kapcsolódáshoz kérje meg a partnerét, hogy hozzon létre egy másik kapcso XFTP-kiszolgáló No comment provided by engineer. - - Yes - Igen - No comment provided by engineer. - You **must not** use the same database on two devices. **Nem szabad** ugyanazt az adatbázist használni egyszerre két eszközön. @@ -9808,7 +9802,7 @@ time to disappear quantum resistant e2e encryption - végpontok közötti kvantumálló titkosítás + végpontok közötti kvantumbiztos titkosítás chat item text @@ -10191,6 +10185,11 @@ utoljára fogadott üzenet: %2$@ %d új esemény notification body + + From %d chat(s) + %d csevegésből + notification body + From: %@ Tőle: %@ @@ -10206,11 +10205,6 @@ utoljára fogadott üzenet: %2$@ Új üzenetek notification - - New messages in %d chats - Új üzenetek %d csevegésben - notification body - diff --git a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff index 353d420e27..0c0c12004e 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -796,6 +796,11 @@ swipe action Tutte le segnalazioni verranno archiviate per te. No comment provided by engineer. + + All servers + Tutti i server + No comment provided by engineer. + All your contacts will remain connected. Tutti i tuoi contatti resteranno connessi. @@ -1086,11 +1091,6 @@ swipe action Archiviazione del database No comment provided by engineer. - - Ask - Chiedi - No comment provided by engineer. - Attach Allega @@ -5541,7 +5541,7 @@ Richiede l'attivazione della VPN. Open Apri - No comment provided by engineer. + alert action Open Settings @@ -5573,26 +5573,15 @@ Richiede l'attivazione della VPN. Apri gruppo No comment provided by engineer. - - Open link - Apri link - No comment provided by engineer. - - - Open links from chat list - Apri i link dall'elenco delle chat - No comment provided by engineer. + + Open link? + alert title Open migration to another device Apri migrazione ad un altro dispositivo authentication reason - - Open web link? - Aprire il link? - No comment provided by engineer. - Opening app… Apertura dell'app… @@ -7201,6 +7190,7 @@ chat item action Short link + Link breve No comment provided by engineer. @@ -7305,6 +7295,7 @@ chat item action SimpleX channel link + Link del canale SimpleX simplex link type @@ -7899,6 +7890,7 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa. This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link. + Questo link richiede una versione più recente dell'app. Aggiornala o chiedi al tuo contatto di inviare un link compatibile. No comment provided by engineer. @@ -8202,6 +8194,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Unsupported connection link + Link di connessione non supportato No comment provided by engineer. @@ -8299,6 +8292,11 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Usa la porta TCP %@ quando non è specificata alcuna porta. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + Usa la porta TCP 443 solo per i server preimpostati. + No comment provided by engineer. + Use chat Usa la chat @@ -8366,6 +8364,7 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Use short links (BETA) + Usa link brevi (BETA) No comment provided by engineer. @@ -8663,11 +8662,6 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e Server XFTP No comment provided by engineer. - - Yes - - No comment provided by engineer. - You **must not** use the same database on two devices. **Non devi** usare lo stesso database su due dispositivi. @@ -10191,6 +10185,11 @@ ultimo msg ricevuto: %2$@ %d nuovi eventi notification body + + From %d chat(s) + Da %d chat + notification body + From: %@ Da: %@ @@ -10206,11 +10205,6 @@ ultimo msg ricevuto: %2$@ Nuovi messaggi notification - - New messages in %d chats - Nuovi messaggi in %d chat - notification body - diff --git a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff index 34856e2e2b..26f415dd13 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -768,6 +768,10 @@ swipe action All reports will be archived for you. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. あなたの連絡先が繋がったまま継続します。 @@ -1043,10 +1047,6 @@ swipe action Archiving database No comment provided by engineer. - - Ask - No comment provided by engineer. - Attach 添付する @@ -5117,7 +5117,7 @@ VPN を有効にする必要があります。 Open 開く - No comment provided by engineer. + alert action Open Settings @@ -5146,22 +5146,14 @@ VPN を有効にする必要があります。 Open group No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device authentication reason - - Open web link? - No comment provided by engineer. - Opening app… No comment provided by engineer. @@ -7607,6 +7599,10 @@ To connect, please ask your contact to create another connection link and check Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat チャット @@ -7932,10 +7928,6 @@ To connect, please ask your contact to create another connection link and check XFTP server No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. No comment provided by engineer. @@ -9369,6 +9361,10 @@ last received msg: %2$@ %d new events notification body + + From %d chat(s) + notification body + From: %@ notification body @@ -9381,10 +9377,6 @@ last received msg: %2$@ New messages notification - - New messages in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff index 4d9df505db..681502e255 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -796,6 +796,10 @@ swipe action Alle rapporten worden voor u gearchiveerd. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Al uw contacten blijven verbonden. @@ -1086,11 +1090,6 @@ swipe action Database archiveren No comment provided by engineer. - - Ask - Vragen - No comment provided by engineer. - Attach Bijvoegen @@ -5541,7 +5540,7 @@ Vereist het inschakelen van VPN. Open Open - No comment provided by engineer. + alert action Open Settings @@ -5573,26 +5572,15 @@ Vereist het inschakelen van VPN. Open groep No comment provided by engineer. - - Open link - Link openen - No comment provided by engineer. - - - Open links from chat list - Open links van chatlijst - No comment provided by engineer. + + Open link? + alert title Open migration to another device Open de migratie naar een ander apparaat authentication reason - - Open web link? - Weblink openen? - No comment provided by engineer. - Opening app… App openen… @@ -8299,6 +8287,10 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak Gebruik TCP-poort %@ als er geen poort is opgegeven. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Gebruik chat @@ -8663,11 +8655,6 @@ Om verbinding te maken, vraagt u uw contact om een andere verbinding link te mak XFTP server No comment provided by engineer. - - Yes - Ja - No comment provided by engineer. - You **must not** use the same database on two devices. U **mag** niet dezelfde database op twee apparaten gebruiken. @@ -10191,6 +10178,10 @@ laatst ontvangen bericht: %2$@ ‐%d nieuwe gebeurtenissen notification body + + From %d chat(s) + notification body + From: %@ Van: %@ @@ -10206,11 +10197,6 @@ laatst ontvangen bericht: %2$@ Nieuwe berichten notification - - New messages in %d chats - Nieuwe berichten in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff index 0a548dc227..01bc0b8508 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -796,6 +796,10 @@ swipe action Wszystkie raporty zostaną dla Ciebie zarchiwizowane. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Wszystkie Twoje kontakty pozostaną połączone. @@ -1086,11 +1090,6 @@ swipe action Archiwizowanie bazy danych No comment provided by engineer. - - Ask - Zapytaj - No comment provided by engineer. - Attach Dołącz @@ -5420,7 +5419,7 @@ Wymaga włączenia VPN. Open Otwórz - No comment provided by engineer. + alert action Open Settings @@ -5450,23 +5449,15 @@ Wymaga włączenia VPN. Grupa otwarta No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device Otwórz migrację na innym urządzeniu authentication reason - - Open web link? - No comment provided by engineer. - Opening app… Otwieranie aplikacji… @@ -8104,6 +8095,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Użyj czatu @@ -8461,10 +8456,6 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc Serwer XFTP No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. **Nie możesz** używać tej samej bazy na dwóch urządzeniach. @@ -9975,6 +9966,10 @@ ostatnia otrzymana wiadomość: %2$@ %d new events notification body + + From %d chat(s) + notification body + From: %@ notification body @@ -9987,11 +9982,6 @@ ostatnia otrzymana wiadomość: %2$@ New messages notification - - New messages in %d chats - Nowe wiadomości w %d czatach - notification body - diff --git a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff index 61495069c7..a7b63e38ba 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -796,6 +796,10 @@ swipe action Все сообщения о нарушениях будут заархивированы для вас. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Все контакты, которые соединились через этот адрес, сохранятся. @@ -1086,11 +1090,6 @@ swipe action Подготовка архива No comment provided by engineer. - - Ask - Спросить - No comment provided by engineer. - Attach Прикрепить @@ -5507,7 +5506,7 @@ Requires compatible VPN. Open Открыть - No comment provided by engineer. + alert action Open Settings @@ -5539,26 +5538,15 @@ Requires compatible VPN. Открыть группу No comment provided by engineer. - - Open link - Открыть ссылку - No comment provided by engineer. - - - Open links from chat list - Открыть ссылку из списка чатов - No comment provided by engineer. + + Open link? + alert title Open migration to another device Открытие миграции на другое устройство authentication reason - - Open web link? - Открыть веб-ссылку? - No comment provided by engineer. - Opening app… Приложение отрывается… @@ -8249,6 +8237,10 @@ To connect, please ask your contact to create another connection link and check Использовать TCP-порт %@, когда порт не указан. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Использовать чат @@ -8613,11 +8605,6 @@ To connect, please ask your contact to create another connection link and check XFTP сервер No comment provided by engineer. - - Yes - Да - No comment provided by engineer. - You **must not** use the same database on two devices. Вы **не должны** использовать одну и ту же базу данных на двух устройствах. @@ -10135,6 +10122,10 @@ last received msg: %2$@ %d новых сообщений notification body + + From %d chat(s) + notification body + From: %@ От: %@ @@ -10150,11 +10141,6 @@ last received msg: %2$@ Новые сообщения notification - - New messages in %d chats - Новые сообщения в %d разговоре(ах) - notification body - diff --git a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff index 7431c13969..be68dc9780 100644 --- a/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff +++ b/apps/ios/SimpleX Localizations/th.xcloc/Localized Contents/th.xliff @@ -722,6 +722,10 @@ swipe action All reports will be archived for you. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่. @@ -986,10 +990,6 @@ swipe action Archiving database No comment provided by engineer. - - Ask - No comment provided by engineer. - Attach แนบ @@ -5019,7 +5019,7 @@ Requires compatible VPN. Open - No comment provided by engineer. + alert action Open Settings @@ -5048,22 +5048,14 @@ Requires compatible VPN. Open group No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device authentication reason - - Open web link? - No comment provided by engineer. - Opening app… No comment provided by engineer. @@ -7509,6 +7501,10 @@ To connect, please ask your contact to create another connection link and check Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat ใช้แชท @@ -7832,10 +7828,6 @@ To connect, please ask your contact to create another connection link and check XFTP server No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. No comment provided by engineer. @@ -9265,6 +9257,10 @@ last received msg: %2$@ %d new events notification body + + From %d chat(s) + notification body + From: %@ notification body @@ -9277,10 +9273,6 @@ last received msg: %2$@ New messages notification - - New messages in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff index 935c4885b5..6eb1daf84b 100644 --- a/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff +++ b/apps/ios/SimpleX Localizations/tr.xcloc/Localized Contents/tr.xliff @@ -788,6 +788,10 @@ swipe action All reports will be archived for you. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Konuştuğun kişilerin tümü bağlı kalacaktır. @@ -1069,10 +1073,6 @@ swipe action Veritabanı arşivleniyor No comment provided by engineer. - - Ask - No comment provided by engineer. - Attach Ekle @@ -5432,7 +5432,7 @@ VPN'nin etkinleştirilmesi gerekir. Open - No comment provided by engineer. + alert action Open Settings @@ -5462,23 +5462,15 @@ VPN'nin etkinleştirilmesi gerekir. Grubu aç No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device Başka bir cihaza açık geçiş authentication reason - - Open web link? - No comment provided by engineer. - Opening app… Uygulama açılıyor… @@ -8119,6 +8111,10 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Sohbeti kullan @@ -8476,10 +8472,6 @@ Bağlanmak için lütfen kişinizden başka bir bağlantı oluşturmasını iste XFTP sunucusu No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. Aynı veritabanını iki cihazda **kullanmamalısınız**. @@ -9989,6 +9981,10 @@ son alınan msj: %2$@ %d new events notification body + + From %d chat(s) + notification body + From: %@ notification body @@ -10001,10 +9997,6 @@ son alınan msj: %2$@ New messages notification - - New messages in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff index 9ea65c4b11..7c8c6f4254 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -788,6 +788,10 @@ swipe action All reports will be archived for you. No comment provided by engineer. + + All servers + No comment provided by engineer. + All your contacts will remain connected. Всі ваші контакти залишаться на зв'язку. @@ -1069,10 +1073,6 @@ swipe action Архівування бази даних No comment provided by engineer. - - Ask - No comment provided by engineer. - Attach Прикріпити @@ -5447,7 +5447,7 @@ Requires compatible VPN. Open Відкрито - No comment provided by engineer. + alert action Open Settings @@ -5479,23 +5479,15 @@ Requires compatible VPN. Відкрита група No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device Відкрита міграція на інший пристрій authentication reason - - Open web link? - No comment provided by engineer. - Opening app… Відкриваємо програму… @@ -8168,6 +8160,10 @@ To connect, please ask your contact to create another connection link and check Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat Використовуйте чат @@ -8531,10 +8527,6 @@ To connect, please ask your contact to create another connection link and check XFTP-сервер No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. Ви **не повинні використовувати** одну і ту ж базу даних на двох пристроях. @@ -10052,6 +10044,10 @@ last received msg: %2$@ %d нових подій notification body + + From %d chat(s) + notification body + From: %@ Від: %@ @@ -10067,11 +10063,6 @@ last received msg: %2$@ Нові повідомлення notification - - New messages in %d chats - Нові повідомлення в чатах %d - notification body - diff --git a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff index 30a6567414..03e053326a 100644 --- a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff @@ -122,6 +122,7 @@ %1$@, %2$@ + %1$@, %2$@ format for date separator in chat @@ -146,18 +147,22 @@ %d file(s) are still being downloaded. + 仍在下载 %d 个文件。 forward confirmation reason %d file(s) failed to download. + %d 个文件下载失败。 forward confirmation reason %d file(s) were deleted. + 已刪除 %d 个文件。 forward confirmation reason %d file(s) were not downloaded. + 未能下载 %d 个文件。 forward confirmation reason @@ -167,6 +172,7 @@ %d messages not forwarded + 未转发 %d 条消息 alert title @@ -186,11 +192,12 @@ %d seconds(s) + %d 秒 delete after time %d skipped message(s) - %d 跳过消息 + 跳过的 %d 条消息 integrity error chat item @@ -355,6 +362,7 @@ **Scan / Paste link**: to connect via a link you received. + **扫描/粘贴链接**:用您收到的链接连接。 No comment provided by engineer. @@ -458,14 +466,17 @@ time interval 1 year + 1 年 delete after time 1-time link + 一次性链接 No comment provided by engineer. 1-time link can be used *with one contact only* - share in person or via any messenger. + 一次性链接*只能给一名联系人*使用。当面或使用聊天应用分享链接。 No comment provided by engineer. @@ -539,6 +550,7 @@ time interval About operators + 关于运营方 No comment provided by engineer. @@ -555,6 +567,7 @@ swipe action Accept conditions + 接受条款 No comment provided by engineer. @@ -575,6 +588,7 @@ swipe action Accepted conditions + 已接受的条款 No comment provided by engineer. @@ -589,6 +603,7 @@ swipe action Active + 活跃 token status text @@ -603,10 +618,12 @@ swipe action Add friends + 添加好友 No comment provided by engineer. Add list + 添加列表 No comment provided by engineer. @@ -626,6 +643,7 @@ swipe action Add team members + 添加团队成员 No comment provided by engineer. @@ -635,6 +653,7 @@ swipe action Add to list + 添加到列表 No comment provided by engineer. @@ -644,14 +663,17 @@ swipe action Add your team members to the conversations. + 将你的团队成员加入对话。 No comment provided by engineer. Added media & file servers + 已添加媒体和文件服务器 No comment provided by engineer. Added message servers + 已添加消息服务器 No comment provided by engineer. @@ -681,10 +703,12 @@ swipe action Address or 1-time link? + 地址还是一次性链接? No comment provided by engineer. Address settings + 地址设置 No comment provided by engineer. @@ -709,6 +733,7 @@ swipe action All + 全部 No comment provided by engineer. @@ -723,6 +748,7 @@ swipe action All chats will be removed from the list %@, and the list deleted. + 列表 %@ 和其中全部聊天将被删除。 alert message @@ -742,6 +768,7 @@ swipe action All messages and files are sent **end-to-end encrypted**, with post-quantum security in direct messages. + 所有消息和文件均通过**端到端加密**发送;私信以量子安全方式发送。 No comment provided by engineer. @@ -766,6 +793,12 @@ swipe action All reports will be archived for you. + 将为你存档所有举报。 + No comment provided by engineer. + + + All servers + 全部服务器 No comment provided by engineer. @@ -845,6 +878,7 @@ swipe action Allow to report messsages to moderators. + 允许向 moderators 举报消息。 No comment provided by engineer. @@ -929,6 +963,7 @@ swipe action Another reason + 另一个理由 report reason @@ -958,6 +993,7 @@ swipe action App group: + 应用组: No comment provided by engineer. @@ -977,6 +1013,7 @@ swipe action App session + 应用会话 No comment provided by engineer. @@ -1006,14 +1043,17 @@ swipe action Archive + 存档 No comment provided by engineer. Archive %lld reports? + 存档 %lld 个举报? No comment provided by engineer. Archive all reports? + 存档所有举报? No comment provided by engineer. @@ -1028,14 +1068,17 @@ swipe action Archive report + 存档举报 No comment provided by engineer. Archive report? + 存档举报? No comment provided by engineer. Archive reports + 存档举报 swipe action @@ -1048,10 +1091,6 @@ swipe action 正在存档数据库 No comment provided by engineer. - - Ask - No comment provided by engineer. - Attach 附件 @@ -1114,6 +1153,7 @@ swipe action Auto-accept settings + 自动接受设置 alert title @@ -1143,6 +1183,7 @@ swipe action Better calls + 更佳的通话 No comment provided by engineer. @@ -1152,10 +1193,12 @@ swipe action Better groups performance + 更好的群性能 No comment provided by engineer. Better message dates. + 更好的消息日期。 No comment provided by engineer. @@ -1170,18 +1213,22 @@ swipe action Better notifications + 更佳的通知 No comment provided by engineer. Better privacy and security + 更好的隐私和安全 No comment provided by engineer. Better security ✅ + 更佳的安全性✅ No comment provided by engineer. Better user experience + 更佳的使用体验 No comment provided by engineer. @@ -1266,14 +1313,17 @@ swipe action Business address + 企业地址 No comment provided by engineer. Business chats + 企业聊天 No comment provided by engineer. Businesses + 企业 No comment provided by engineer. @@ -1378,10 +1428,12 @@ alert button Change automatic message deletion? + 更改消息自动删除设置? alert title Change chat profiles + 更改聊天资料 authentication reason @@ -1432,14 +1484,17 @@ set passcode view Chat + 聊天 No comment provided by engineer. Chat already exists + 聊天已存在 No comment provided by engineer. Chat already exists! + 聊天已存在! No comment provided by engineer. @@ -1504,6 +1559,7 @@ set passcode view Chat preferences were changed. + 聊天偏好设置已修改。 alert message @@ -1518,10 +1574,12 @@ set passcode view Chat will be deleted for all members - this cannot be undone! + 将为所有成员删除聊天 - 此操作无法撤销! No comment provided by engineer. Chat will be deleted for you - this cannot be undone! + 将为你删除聊天 - 此操作无法撤销! No comment provided by engineer. @@ -1531,10 +1589,12 @@ set passcode view Check messages every 20 min. + 每 20 分钟检查消息。 No comment provided by engineer. Check messages when allowed. + 在被允许时检查消息。 No comment provided by engineer. @@ -1594,10 +1654,12 @@ set passcode view Clear group? + 清除群? No comment provided by engineer. Clear or delete group? + 清除还是删除群? No comment provided by engineer. @@ -1622,6 +1684,7 @@ set passcode view Community guidelines violation + 违反社区指导方针 report reason @@ -1641,14 +1704,17 @@ set passcode view Conditions accepted on: %@. + 已于 %@ 接受条款。 No comment provided by engineer. Conditions are accepted for the operator(s): **%@**. + 已接受运营方 **%@** 的条款。 No comment provided by engineer. Conditions are already accepted for these operator(s): **%@**. + 已经接受下列运营方的条款:**%@**。 No comment provided by engineer. @@ -1658,14 +1724,17 @@ set passcode view Conditions will be accepted for the operator(s): **%@**. + 将接受下列运营方的条款:**%@**。 No comment provided by engineer. Conditions will be accepted on: %@. + 将于 %@ 接受条款。 No comment provided by engineer. Conditions will be automatically accepted for enabled operators on: %@. + 将在 %@ 自动接受启用的运营方的条款。 No comment provided by engineer. @@ -1730,6 +1799,7 @@ set passcode view Confirmed + 已确定 token status text @@ -1853,6 +1923,7 @@ This is your own one-time link! Connection blocked + 连接被阻止 No comment provided by engineer. @@ -1868,10 +1939,12 @@ This is your own one-time link! Connection is blocked by server operator: %@ + 连接被运营方 %@ 阻止 No comment provided by engineer. Connection not ready. + 连接未就绪。 No comment provided by engineer. @@ -1886,10 +1959,12 @@ This is your own one-time link! Connection requires encryption renegotiation. + 连接需要加密重协商。 No comment provided by engineer. Connection security + 连接安全性 No comment provided by engineer. @@ -1969,6 +2044,7 @@ This is your own one-time link! Content violates conditions of use + 内容违反使用条款 blocking reason @@ -1998,6 +2074,7 @@ This is your own one-time link! Corner + 拐角 No comment provided by engineer. @@ -2012,6 +2089,7 @@ This is your own one-time link! Create 1-time link + 创建一次性链接 No comment provided by engineer. @@ -2046,6 +2124,7 @@ This is your own one-time link! Create list + 创建列表 No comment provided by engineer. @@ -2105,6 +2184,7 @@ This is your own one-time link! Current conditions text couldn't be loaded, you can review conditions via this link: + 无法加载当前条款文本,你可以通过此链接审阅条款: No comment provided by engineer. @@ -2129,6 +2209,7 @@ This is your own one-time link! Customizable message shape. + 可自定义消息形状。 No comment provided by engineer. @@ -2302,10 +2383,12 @@ swipe action Delete chat + 删除聊天 No comment provided by engineer. Delete chat messages from your device. + 从你的设备删除聊天消息。 No comment provided by engineer. @@ -2320,6 +2403,7 @@ swipe action Delete chat? + 删除聊天? No comment provided by engineer. @@ -2399,6 +2483,7 @@ swipe action Delete list? + 删除列表? alert title @@ -2433,6 +2518,7 @@ swipe action Delete or moderate up to 200 messages. + 允许自行删除或管理员移除最多200条消息。 No comment provided by engineer. @@ -2452,6 +2538,7 @@ swipe action Delete report + 删除举报 No comment provided by engineer. @@ -2491,6 +2578,7 @@ swipe action Delivered even when Apple drops them. + 已送达,即使苹果已将其删除。 No comment provided by engineer. @@ -2575,7 +2663,7 @@ swipe action Device authentication is disabled. Turning off SimpleX Lock. - 设备验证被禁用。关闭 SimpleX 锁定。 + 设备验证已禁用。 SimpleX 已解锁。 No comment provided by engineer. @@ -2595,11 +2683,12 @@ swipe action Direct messages between members are prohibited in this chat. + 此群禁止成员间私信。 No comment provided by engineer. Direct messages between members are prohibited. - 此群中禁止成员之间私信。 + 此群禁止成员间私信。 No comment provided by engineer. @@ -2614,10 +2703,12 @@ swipe action Disable automatic message deletion? + 禁用消息自动销毁? alert title Disable delete messages + 停用消息删除 alert button @@ -2707,10 +2798,12 @@ swipe action Do not use credentials with proxy. + 代理不使用身份验证凭据。 No comment provided by engineer. Documents: + 文档: No comment provided by engineer. @@ -2725,6 +2818,7 @@ swipe action Don't miss important messages. + 不错过重要消息。 No comment provided by engineer. @@ -2734,6 +2828,7 @@ swipe action Done + 完成 No comment provided by engineer. @@ -2764,6 +2859,7 @@ chat item action Download files + 下载文件 alert action @@ -2798,6 +2894,7 @@ chat item action E2E encrypted notifications. + 端到端加密的通知。 No comment provided by engineer. @@ -2822,6 +2919,7 @@ chat item action Enable Flux in Network & servers settings for better metadata privacy. + 在“网络&服务器”设置中启用 Flux,更好地保护元数据隐私。 No comment provided by engineer. @@ -2966,6 +3064,7 @@ chat item action Encryption renegotiation in progress. + 正进行加密重协商。 No comment provided by engineer. @@ -3035,6 +3134,7 @@ chat item action Error accepting conditions + 接受条款出错 alert title @@ -3049,6 +3149,7 @@ chat item action Error adding server + 添加服务器出错 alert title @@ -3058,6 +3159,7 @@ chat item action Error changing connection profile + 更改连接资料出错 No comment provided by engineer. @@ -3072,6 +3174,7 @@ chat item action Error changing to incognito! + 切换至隐身聊天出错! No comment provided by engineer. @@ -3100,6 +3203,7 @@ chat item action Error creating list + 创建列表出错 alert title @@ -3119,6 +3223,7 @@ chat item action Error creating report + 创建举报出错 No comment provided by engineer. @@ -3203,10 +3308,12 @@ chat item action Error loading servers + 加载服务器出错 alert title Error migrating settings + 迁移设置出错 No comment provided by engineer. @@ -3231,6 +3338,7 @@ chat item action Error registering for notifications + 注册消息推送出错 alert title @@ -3240,6 +3348,7 @@ chat item action Error reordering lists + 重排列表出错 alert title @@ -3254,6 +3363,7 @@ chat item action Error saving chat list + 保存聊天列表出错 alert title @@ -3273,6 +3383,7 @@ chat item action Error saving servers + 保存服务器出错 alert title @@ -3322,6 +3433,7 @@ chat item action Error switching profile + 切换配置文件出错 No comment provided by engineer. @@ -3336,6 +3448,7 @@ chat item action Error testing server connection + 检验服务器连接出错 No comment provided by engineer. @@ -3350,6 +3463,7 @@ chat item action Error updating server + 更新服务器出错 alert title @@ -3401,6 +3515,7 @@ snd error text Errors in servers configuration. + 服务器配置有错误。 servers error @@ -3420,6 +3535,7 @@ snd error text Expired + 已过期 token status text @@ -3464,6 +3580,7 @@ snd error text Faster deletion of groups. + 更快地删除群。 No comment provided by engineer. @@ -3473,6 +3590,7 @@ snd error text Faster sending messages. + 更快发送消息。 No comment provided by engineer. @@ -3482,6 +3600,7 @@ snd error text Favorites + 收藏 No comment provided by engineer. @@ -3492,11 +3611,15 @@ snd error text File errors: %@ + 文件错误: +%@ alert message File is blocked by server operator: %@. + 文件被服务器运营方阻止: +%@。 file error text @@ -3626,10 +3749,12 @@ snd error text For all moderators + 所有 moderators No comment provided by engineer. For chat profile %@: + 为聊天资料 %@: servers error @@ -3639,18 +3764,22 @@ snd error text For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server. + 比如,如果你通过 SimpleX 服务器收到消息,应用会通过 Flux 服务器传送它们。 No comment provided by engineer. For me + 仅自己 No comment provided by engineer. For private routing + 用于私密路由 No comment provided by engineer. For social media + 用于社交媒体 No comment provided by engineer. @@ -3660,6 +3789,7 @@ snd error text Forward %d message(s)? + 转发 %d 条消息? alert title @@ -3669,14 +3799,17 @@ snd error text Forward messages + 已转发的消息 alert action Forward messages without files? + 仅转发消息不转发文件? alert message Forward up to 20 messages at once. + 一次转发最多20条消息。 No comment provided by engineer. @@ -3691,6 +3824,7 @@ snd error text Forwarding %lld messages + 正在转发 %lld 条消息 No comment provided by engineer. @@ -3764,6 +3898,7 @@ Error: %2$@ Get notified when mentioned. + 被提及时收到通知。 No comment provided by engineer. @@ -3873,6 +4008,7 @@ Error: %2$@ Groups + No comment provided by engineer. @@ -3882,6 +4018,7 @@ Error: %2$@ Help admins moderating their groups. + 帮助管理员管理群组。 No comment provided by engineer. @@ -3936,14 +4073,17 @@ Error: %2$@ How it affects privacy + 它如何影响隐私 No comment provided by engineer. How it helps privacy + 它如何帮助隐私 No comment provided by engineer. How it works + 工作原理 alert button @@ -3973,6 +4113,7 @@ Error: %2$@ IP address + IP 地址 No comment provided by engineer. @@ -4053,6 +4194,8 @@ Error: %2$@ Improved delivery, reduced traffic usage. More improvements are coming soon! + 改善传送,降低流量使用。 +更多改进即将推出! No comment provided by engineer. @@ -4087,10 +4230,12 @@ More improvements are coming soon! Inappropriate content + 不当内容 report reason Inappropriate profile + 不当个人资料 report reason @@ -4187,22 +4332,27 @@ More improvements are coming soon! Invalid + 无效 token status text Invalid (bad token) + Token 无效 token status text Invalid (expired) + 无效(已过期) token status text Invalid (unregistered) + 无效(未注册) token status text Invalid (wrong topic) + 无效(话题有误) token status text @@ -4267,6 +4417,7 @@ More improvements are coming soon! Invite to chat + 邀请加入聊天 No comment provided by engineer. @@ -4429,10 +4580,12 @@ This is your link for group %@! Leave chat + 离开聊天 No comment provided by engineer. Leave chat? + 离开聊天? No comment provided by engineer. @@ -4477,14 +4630,17 @@ This is your link for group %@! List + 列表 swipe action List name and emoji should be different for all lists. + 所有列表的名称和表情符号都应不同。 No comment provided by engineer. List name... + 列表名… No comment provided by engineer. @@ -4579,10 +4735,12 @@ This is your link for group %@! Member reports + 成员举报 chat feature Member role will be changed to "%@". All chat members will be notified. + 将变更成员角色为“%@”。所有成员都会收到通知。 No comment provided by engineer. @@ -4597,6 +4755,7 @@ This is your link for group %@! Member will be removed from chat - this cannot be undone! + 将从聊天中删除成员 - 此操作无法撤销! No comment provided by engineer. @@ -4616,6 +4775,7 @@ This is your link for group %@! Members can report messsages to moderators. + 成员可以向 moderators 举报消息。 No comment provided by engineer. @@ -4645,6 +4805,7 @@ This is your link for group %@! Mention members 👋 + 提及成员👋 No comment provided by engineer. @@ -4714,6 +4875,7 @@ This is your link for group %@! Message shape + 消息形状 No comment provided by engineer. @@ -4758,6 +4920,7 @@ This is your link for group %@! Messages in this chat will never be deleted. + 此聊天中的消息永远不会被删除。 alert message @@ -4772,6 +4935,7 @@ This is your link for group %@! Messages were deleted after you selected them. + 在你选中消息后这些消息已被删除。 alert message @@ -4861,6 +5025,7 @@ This is your link for group %@! More + 更多 swipe action @@ -4875,6 +5040,7 @@ This is your link for group %@! More reliable notifications + 更可靠的通知 No comment provided by engineer. @@ -4894,6 +5060,7 @@ This is your link for group %@! Mute all + 全部静音 notification label action @@ -4918,6 +5085,7 @@ This is your link for group %@! Network decentralization + 网络去中心化 No comment provided by engineer. @@ -4932,6 +5100,7 @@ This is your link for group %@! Network operator + 网络运营方 No comment provided by engineer. @@ -4946,6 +5115,7 @@ This is your link for group %@! New + token status text @@ -4955,10 +5125,12 @@ This is your link for group %@! New SOCKS credentials will be used every time you start the app. + 每次启动应用都会使用新的 SOCKS 凭据。 No comment provided by engineer. New SOCKS credentials will be used for each server. + 每个服务器都会使用新的 SOCKS 凭据。 No comment provided by engineer. @@ -4993,6 +5165,7 @@ This is your link for group %@! New events + 新事件 notification @@ -5022,6 +5195,7 @@ This is your link for group %@! New server + 新服务器 No comment provided by engineer. @@ -5036,14 +5210,17 @@ This is your link for group %@! No chats + 无聊天 No comment provided by engineer. No chats found + 找不到聊天 No comment provided by engineer. No chats in list %@ + 列表 %@ 中无聊天 No comment provided by engineer. @@ -5093,14 +5270,17 @@ This is your link for group %@! No media & file servers. + 无媒体和文件服务器。 servers error No message + 无消息 No comment provided by engineer. No message servers. + 无消息服务器。 servers error @@ -5110,10 +5290,12 @@ This is your link for group %@! No permission to record speech + 无录音权限 No comment provided by engineer. No permission to record video + 无录像权限 No comment provided by engineer. @@ -5133,26 +5315,32 @@ This is your link for group %@! No servers for private message routing. + 无私密消息路由服务器。 servers error No servers to receive files. + 无文件接收服务器。 servers error No servers to receive messages. + 无消息接收服务器。 servers error No servers to send files. + 无文件发送服务器。 servers error No token! + 无 token! alert title No unread chats + 没有未读聊天 No comment provided by engineer. @@ -5167,6 +5355,7 @@ This is your link for group %@! Notes + 附注 No comment provided by engineer. @@ -5176,6 +5365,7 @@ This is your link for group %@! Nothing to forward! + 无可转发! alert title @@ -5190,14 +5380,17 @@ This is your link for group %@! Notifications error + 通知错误 alert title Notifications privacy + 通知隐私 No comment provided by engineer. Notifications status + 通知状态 alert title @@ -5255,6 +5448,7 @@ Requires compatible VPN. Only chat owners can change preferences. + 仅聊天所有人可更改首选项。 No comment provided by engineer. @@ -5284,10 +5478,12 @@ Requires compatible VPN. Only sender and moderators see it + 仅发送人和moderators能看到 No comment provided by engineer. Only you and moderators see it + 只有你和moderators能看到 No comment provided by engineer. @@ -5343,7 +5539,7 @@ Requires compatible VPN. Open 打开 - No comment provided by engineer. + alert action Open Settings @@ -5352,6 +5548,7 @@ Requires compatible VPN. Open changes + 打开更改 No comment provided by engineer. @@ -5366,6 +5563,7 @@ Requires compatible VPN. Open conditions + 打开条款 No comment provided by engineer. @@ -5373,23 +5571,15 @@ Requires compatible VPN. 打开群 No comment provided by engineer. - - Open link - No comment provided by engineer. - - - Open links from chat list - No comment provided by engineer. + + Open link? + alert title Open migration to another device 打开迁移到另一台设备 authentication reason - - Open web link? - No comment provided by engineer. - Opening app… 正在打开应用程序… @@ -5397,14 +5587,17 @@ Requires compatible VPN. Operator + 运营方 No comment provided by engineer. Operator server + 运营方服务器 alert title Or import archive file + 或者导入或者导入压缩文件 No comment provided by engineer. @@ -5429,10 +5622,12 @@ Requires compatible VPN. Or to share privately + 或者私下分享 No comment provided by engineer. Organize chats into lists + 将聊天组织到列表 No comment provided by engineer. @@ -5482,6 +5677,7 @@ Requires compatible VPN. Password + 密码 No comment provided by engineer. @@ -6280,21 +6476,22 @@ swipe action Review conditions + 审阅条款 No comment provided by engineer. Revoke - 撤销 + 吊销 No comment provided by engineer. Revoke file - 撤销文件 + 吊销文件 cancel file action Revoke file? - 撤销文件? + 吊销文件? No comment provided by engineer. @@ -6304,7 +6501,7 @@ swipe action Run chat - 运行聊天程序 + 运行聊天 No comment provided by engineer. @@ -6364,6 +6561,7 @@ chat item action Save list + 保存列表 No comment provided by engineer. @@ -6403,6 +6601,7 @@ chat item action Save your profile? + 保存您的个人资料? alert title @@ -6427,6 +6626,7 @@ chat item action Saving %lld messages + 正在保存 %lld 条消息 No comment provided by engineer. @@ -7007,6 +7207,7 @@ chat item action SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app. + SimpleX Chat 与 Flux 达成了协议,将由 Flux 控制的服务器纳入 SimpleX 应用。 No comment provided by engineer. @@ -7041,14 +7242,17 @@ chat item action SimpleX address and 1-time links are safe to share via any messenger. + 可以通过任何消息应用安全分享 SimpleX 地址和一次性链接。 No comment provided by engineer. SimpleX address or 1-time link? + SimpleX 地址或一次性链接? No comment provided by engineer. SimpleX channel link + SimpleX 频道链接 simplex link type @@ -7058,12 +7262,12 @@ chat item action SimpleX encrypted message or connection event - SimpleX 加密消息或连接项目 + SimpleX 加密的消息或连接事件 notification SimpleX group link - SimpleX 群组链接 + SimpleX 群链接 simplex link type @@ -7088,6 +7292,7 @@ chat item action SimpleX protocols reviewed by Trail of Bits. + SimpleX 协议由 Trail of Bits 审阅。 No comment provided by engineer. @@ -7122,6 +7327,7 @@ chat item action Some app settings were not migrated. + 部分应用设置未被迁移。 No comment provided by engineer. @@ -8010,6 +8216,10 @@ To connect, please ask your contact to create another connection link and check Use TCP port %@ when no port is specified. No comment provided by engineer. + + Use TCP port 443 for preset servers only. + No comment provided by engineer. + Use chat 使用聊天 @@ -8366,10 +8576,6 @@ To connect, please ask your contact to create another connection link and check XFTP 服务器 No comment provided by engineer. - - Yes - No comment provided by engineer. - You **must not** use the same database on two devices. 您 **不得** 在两台设备上使用相同的数据库。 @@ -9151,7 +9357,7 @@ pref value duplicates - 复本 + 副本 No comment provided by engineer. @@ -9875,6 +10081,10 @@ last received msg: %2$@ %d new events notification body + + From %d chat(s) + notification body + From: %@ notification body @@ -9887,10 +10097,6 @@ last received msg: %2$@ New messages notification - - New messages in %d chats - notification body - diff --git a/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff b/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff index 93b9725131..8a771369e6 100644 --- a/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hant.xcloc/Localized Contents/zh-Hant.xliff @@ -109,7 +109,7 @@ %d skipped message(s) - %d錯過了訊息 + 錯過的 %d 則訊息 integrity error chat item @@ -124,17 +124,17 @@ %lld contact(s) selected - %lld 已選擇聯絡人(s) + 已選擇 %lld 個聯絡人 No comment provided by engineer. %lld file(s) with total size of %@ - %lld 檔案(s) 的總共大小為%@ + %lld 個檔案,總共大小 %@ No comment provided by engineer. %lld members - %lld 成員 + %lld 個成員 No comment provided by engineer. @@ -224,7 +224,7 @@ **Warning**: Instant push notifications require passphrase saved in Keychain. - **警告**:即時推送訊息通知需要數據庫的密碼儲存在資料庫中。 + **警告**:即時推送訊息通知需要將數據庫的密碼儲存在資料庫中。 No comment provided by engineer. @@ -2704,12 +2704,12 @@ We will be adding server redundancy to prevent lost messages. Send link previews - 傳送可以預覽的連結 + 傳送連結預覽 No comment provided by engineer. Send live message - 傳送實況的訊息 + 傳送實時訊息 No comment provided by engineer. @@ -2724,7 +2724,7 @@ We will be adding server redundancy to prevent lost messages. Send questions and ideas - 傳送問題和想法給開發者 + 給開發者提問題和想法 No comment provided by engineer. @@ -2774,7 +2774,7 @@ We will be adding server redundancy to prevent lost messages. Set 1 day - 設定為1天 + 設定為 1 天 No comment provided by engineer. @@ -3022,7 +3022,7 @@ We will be adding server redundancy to prevent lost messages. The connection you accepted will be cancelled! - 你所接受的連接將被取消! + 你接受的連接將被取消! No comment provided by engineer. @@ -3061,7 +3061,7 @@ We will be adding server redundancy to prevent lost messages. The sender will NOT be notified - 發送者不會接收到通知 + 發送者不會收到通知 No comment provided by engineer. @@ -3071,12 +3071,12 @@ We will be adding server redundancy to prevent lost messages. This action cannot be undone - all received and sent files and media will be deleted. Low resolution pictures will remain. - 這操作不能還原 - 所有已經接收和傳送的檔案和媒體檔案將刪除。低解析度圖片將保留。 + 這操作不能還原 - 將刪除所有已經接收和傳送的檔案和媒體。將保留低解析度圖片。 No comment provided by engineer. This action cannot be undone - the messages sent and received earlier than selected will be deleted. It may take several minutes. - 這操作無法撤銷 - 早於所選擇的時間發送和接收的訊息將被刪除。這可能需要幾分鐘的時間。 + 這操作無法撤銷 - 早於所選時間的收發訊息將被刪除。可能需要幾分鐘。 No comment provided by engineer. @@ -3263,7 +3263,7 @@ To connect, please ask your contact to create another connection link and check Use for new connections - 用於新的連接 + 用於新的連線 No comment provided by engineer. @@ -3283,7 +3283,7 @@ To connect, please ask your contact to create another connection link and check Verify connection security - 驗證連接安全性 + 驗證連線安全性 No comment provided by engineer. @@ -4163,7 +4163,7 @@ SimpleX 伺服器並不會看到你的個人檔案。 via contact address link - 透過聯絡人的邀請連結連接 + 透過聯絡人的邀請連結連線 chat list item description @@ -4173,7 +4173,7 @@ SimpleX 伺服器並不會看到你的個人檔案。 via one-time link - 透過一次性連結連接 + 透過一次性連結連線 chat list item description @@ -4702,7 +4702,7 @@ Available in v5.1 %u messages failed to decrypt. - %u 訊息解密失敗。 + %u 則訊息解密失敗。 No comment provided by engineer. @@ -5152,7 +5152,7 @@ Available in v5.1 Tap to activate profile. - 點擊以激活配置檔案。 + 點擊以激活設定檔。 No comment provided by engineer. @@ -6034,7 +6034,7 @@ It can happen because of some bug or when the connection is compromised. %lld messages marked deleted - %lld 條訊息已刪除 + %lld 則訊息已標記為刪除 Already connecting! @@ -6046,7 +6046,7 @@ It can happen because of some bug or when the connection is compromised. (new) - (新) + (新) %@, %@ and %lld other members connected @@ -6112,6 +6112,374 @@ It can happen because of some bug or when the connection is compromised.Background 後台 + + SimpleX links not allowed + 不允許 SimpleX 連結 + + + Voice messages not allowed + 不允許語音訊息 + + + The text you pasted is not a SimpleX link. + 您貼在這裡的連結不是 SimpleX 連結。 + + + %d file(s) were deleted. + 已刪除 %d 個檔案。 + + + Reset to app theme + 重設至應用程式主題 + + + Retry + 重試 + + + The uploaded database archive will be permanently removed from the servers. + 上傳的資料庫存檔將從伺服器永久移除。 + + + Shape profile images + 塑造個人資料圖片 + + + **Scan / Paste link**: to connect via a link you received. + **掃描/貼上連結**:以透過您收到的連結連線。 + + + Reports + 舉報 + + + Use SOCKS proxy + 使用 SOCKS 代理 + + + Reset all statistics + 重設所有統計數據 + + + SOCKS proxy + SOCKS 代理 + + + Send message to enable calls. + 發送訊息以啟用通話功能。 + + + Send direct message to connect + 直接發送訊息以連結 + + + Scale + 顯示比例 + + + Sent via proxy + 通過代理發送 + + + Servers info + 伺服器訊息 + + + Set message expiration in chats. + 設定聊天中訊息期限。 + + + Share SimpleX address on social media. + 在社交媒體上分享 SimpleX 聯絡地址。 + + + Storage + 存儲 + + + Starting from %@. + 開始於 %@。 + + + The second tick we missed! ✅ + 我們錯過的第二個勾選! ✅ + + + Themes + 主題 + + + %d file(s) failed to download. + %d 個檔案下載失敗。 + + + Session code + 會話代碼 + + + Servers statistics will be reset - this cannot be undone! + 伺服器統計資料將被重設 - 此操作無法撤銷! + + + **Create 1-time link**: to create and share a new invitation link. + **建立一次性連結**:建立並分享新邀請連結。 + + + Set default theme + 設定缺省主題 + + + %lld group events + %lld 個群組事件 + + + Reset all statistics? + 重設所有統計數據? + + + %@ server + %@ 伺服器 + + + %d file(s) were not downloaded. + %d 個檔案未下載。 + + + %d messages not forwarded + %d 則訊息未轉發 + + + Test notifications + 测试通知 + + + (this device v%@) + (此設備 v%@) + + + Settings were changed. + 設定已更改。 + + + This action cannot be undone - the messages sent and received in this chat earlier than selected will be deleted. + 這操作不能撤銷 - 此聊天中早於所選訊息的收發訊息將被刪除。 + + + Subscription errors + 訂閱錯誤 + + + Report + 舉報 + + + Send messages directly when IP address is protected and your or destination server does not support private routing. + 當 IP 位址受保護且您或目的地伺服器不支援私人路由時,直接傳送訊息。 + + + Reset to user theme + 重設為使用者主題 + + + Use short links (BETA) + 使用短連結(Beta) + + + Up to 100 last messages are sent to new members. + 最多 100 則最後的訊息會傳送至新成員。 + + + %d seconds(s) + %d 秒 + + + %d file(s) are still being downloaded. + 仍在下載 %d 個檔案。 + + + %lld messages blocked by admin + %lld 則訊息被管理員封鎖 + + + Report: %@ + 舉報:%@ + + + Review conditions + 檢視使用條款 + + + Search or paste SimpleX link + 搜尋或貼上 SimpleX 連結 + + + Sent directly + 已直接發送 + + + SimpleX links are prohibited. + 這群組禁止 SimpleX 連結。 + + + Uploaded files + 已上傳的檔案 + + + Use %@ + 使用 %@ + + + Upload errors + 上傳錯誤 + + + Use servers + 使用伺服器 + + + security code changed + 安全碼已變更 + + + These settings are for your current profile **%@**. + 這些設定是針對您目前的設定檔 **%@**。 + + + They can be overridden in contact and group settings. + 您可在連絡人和群組設定中覆寫它們。 + + + %1$@, %2$@ + %1$@, %2$@ + + + Verify connections + 驗證連線 + + + Verify connection + 驗證連線 + + + Verify passphrase + 驗證密碼 + + + Verify code with desktop + 使用桌上電腦驗證代碼 + + + Save list + 儲存列表 + + + Saving %lld messages + 正在儲存 %lld 則訊息 + + + search + 搜尋 + + + requested to connect + 已請求連結 + + + saved + 已儲存 + + + video + 視訊 + + + Tap to Connect + 點擊以連結 + + + Unsupported connection link + 未受支持的連線連結 + + + Saved from + 儲存自 + + + Saved + 已儲存 + + + Scan / Paste link + 掃描/貼上連結 + + + SimpleX + SimpleX + + + Use the app while in the call. + 在通話時使用此應用程式。 + + + v%@ + v%@ + + + Save your profile? + 儲存設定檔? + + + Use for messages + 用於訊息 + + + Uploading archive + 正在上傳檔案庫 + + + Unlink + 從桌上電腦解除連結 + + + %lld messages blocked + 已封鎖 %d 則訊息 + + + The same conditions will apply to operator **%@**. + 相同條件也適用於 **%@** 操作員。 + + + These conditions will also apply for: **%@**. + 這些條件也適用於:**%@**。 + + + Upload failed + 上傳失敗 + + + Use the app with one hand. + 單手使用此應用程式。 + + + Safely receive files + 安全地接收檔案 + + + Saved message + 已儲存的訊息 + + + Use from desktop + 在桌上電腦上使用 + + + Via secure quantum resistant protocol. + 使用量子安全的協定。 + + + Uploaded + 已上傳 + diff --git a/apps/ios/SimpleX NSE/de.lproj/Localizable.strings b/apps/ios/SimpleX NSE/de.lproj/Localizable.strings index f9779c6e05..ec502c53c6 100644 --- a/apps/ios/SimpleX NSE/de.lproj/Localizable.strings +++ b/apps/ios/SimpleX NSE/de.lproj/Localizable.strings @@ -1,6 +1,9 @@ /* notification body */ "%d new events" = "%d neue Ereignisse"; +/* notification body */ +"From %d chat(s)" = "Von %d Chat(s)"; + /* notification body */ "From: %@" = "Von: %@"; @@ -10,6 +13,3 @@ /* notification */ "New messages" = "Neue Nachrichten"; -/* notification body */ -"New messages in %d chats" = "Neue Nachrichten in %d Chats"; - diff --git a/apps/ios/SimpleX NSE/es.lproj/Localizable.strings b/apps/ios/SimpleX NSE/es.lproj/Localizable.strings index fb190400e1..685eb3d93d 100644 --- a/apps/ios/SimpleX NSE/es.lproj/Localizable.strings +++ b/apps/ios/SimpleX NSE/es.lproj/Localizable.strings @@ -1,6 +1,9 @@ /* notification body */ "%d new events" = "%d evento(s) nuevo(s)"; +/* notification body */ +"From %d chat(s)" = "De %d chat(s)"; + /* notification body */ "From: %@" = "De: %@"; @@ -10,6 +13,3 @@ /* notification */ "New messages" = "Mensajes nuevos"; -/* notification body */ -"New messages in %d chats" = "Mensajes nuevos en %d chat(s)"; - diff --git a/apps/ios/SimpleX NSE/fr.lproj/Localizable.strings b/apps/ios/SimpleX NSE/fr.lproj/Localizable.strings index a57961c934..999bb3608f 100644 --- a/apps/ios/SimpleX NSE/fr.lproj/Localizable.strings +++ b/apps/ios/SimpleX NSE/fr.lproj/Localizable.strings @@ -10,6 +10,3 @@ /* notification */ "New messages" = "Nouveaux messages"; -/* notification body */ -"New messages in %d chats" = "Nouveaux messages dans %d chats"; - diff --git a/apps/ios/SimpleX NSE/hu.lproj/Localizable.strings b/apps/ios/SimpleX NSE/hu.lproj/Localizable.strings index e64c98df9e..a6330b93db 100644 --- a/apps/ios/SimpleX NSE/hu.lproj/Localizable.strings +++ b/apps/ios/SimpleX NSE/hu.lproj/Localizable.strings @@ -1,6 +1,9 @@ /* notification body */ "%d new events" = "%d új esemény"; +/* notification body */ +"From %d chat(s)" = "%d csevegésből"; + /* notification body */ "From: %@" = "Tőle: %@"; @@ -10,6 +13,3 @@ /* notification */ "New messages" = "Új üzenetek"; -/* notification body */ -"New messages in %d chats" = "Új üzenetek %d csevegésben"; - diff --git a/apps/ios/SimpleX NSE/it.lproj/Localizable.strings b/apps/ios/SimpleX NSE/it.lproj/Localizable.strings index 31f463eb5b..a6c1ec215b 100644 --- a/apps/ios/SimpleX NSE/it.lproj/Localizable.strings +++ b/apps/ios/SimpleX NSE/it.lproj/Localizable.strings @@ -1,6 +1,9 @@ /* notification body */ "%d new events" = "%d nuovi eventi"; +/* notification body */ +"From %d chat(s)" = "Da %d chat"; + /* notification body */ "From: %@" = "Da: %@"; @@ -10,6 +13,3 @@ /* notification */ "New messages" = "Nuovi messaggi"; -/* notification body */ -"New messages in %d chats" = "Nuovi messaggi in %d chat"; - diff --git a/apps/ios/SimpleX NSE/nl.lproj/Localizable.strings b/apps/ios/SimpleX NSE/nl.lproj/Localizable.strings index 4cf91689b5..12d1e01f1d 100644 --- a/apps/ios/SimpleX NSE/nl.lproj/Localizable.strings +++ b/apps/ios/SimpleX NSE/nl.lproj/Localizable.strings @@ -10,6 +10,3 @@ /* notification */ "New messages" = "Nieuwe berichten"; -/* notification body */ -"New messages in %d chats" = "Nieuwe berichten in %d chats"; - diff --git a/apps/ios/SimpleX NSE/ru.lproj/Localizable.strings b/apps/ios/SimpleX NSE/ru.lproj/Localizable.strings index 6ba39ccc63..7205b37e7f 100644 --- a/apps/ios/SimpleX NSE/ru.lproj/Localizable.strings +++ b/apps/ios/SimpleX NSE/ru.lproj/Localizable.strings @@ -10,6 +10,3 @@ /* notification */ "New messages" = "Новые сообщения"; -/* notification body */ -"New messages in %d chats" = "Новые сообщения в %d разговоре(ах)"; - diff --git a/apps/ios/SimpleX NSE/uk.lproj/Localizable.strings b/apps/ios/SimpleX NSE/uk.lproj/Localizable.strings index 69cc53bff1..ceace71e34 100644 --- a/apps/ios/SimpleX NSE/uk.lproj/Localizable.strings +++ b/apps/ios/SimpleX NSE/uk.lproj/Localizable.strings @@ -10,6 +10,3 @@ /* notification */ "New messages" = "Нові повідомлення"; -/* notification body */ -"New messages in %d chats" = "Нові повідомлення в чатах %d"; - diff --git a/apps/ios/SimpleX SE/ShareView.swift b/apps/ios/SimpleX SE/ShareView.swift index f2b9de9f72..07180ffa1b 100644 --- a/apps/ios/SimpleX SE/ShareView.swift +++ b/apps/ios/SimpleX SE/ShareView.swift @@ -160,7 +160,7 @@ struct ShareView: View { } } - @ViewBuilder private func linkPreview(_ linkPreview: LinkPreview) -> some View { + private func linkPreview(_ linkPreview: LinkPreview) -> some View { previewArea { HStack(alignment: .center, spacing: 8) { if let uiImage = imageFromBase64(linkPreview.image) { diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index aadca9e702..4992e24b91 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -179,8 +179,8 @@ 64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; }; 64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; }; 64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; }; - 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a */; }; - 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a */; }; + 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a */; }; + 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a */; }; 64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; }; 64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; }; 64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; }; @@ -543,8 +543,8 @@ 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = ""; }; 64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; 64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a"; sourceTree = ""; }; - 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a"; sourceTree = ""; }; + 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a"; sourceTree = ""; }; + 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a"; sourceTree = ""; }; 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = ""; }; 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = ""; }; @@ -702,8 +702,8 @@ 64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */, 64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */, 64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */, - 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a in Frameworks */, - 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a in Frameworks */, + 64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a in Frameworks */, + 64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -788,8 +788,8 @@ 64C829992D54AEEE006B9E89 /* libffi.a */, 64C829982D54AEED006B9E89 /* libgmp.a */, 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */, - 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe-ghc9.6.3.a */, - 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.3.1-5KR5yzeCZIzIubYi5BDCKe.a */, + 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM-ghc9.6.3.a */, + 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.3.4.0-47rHZ52LFetD6j9vq8gwHM.a */, ); path = Libraries; sourceTree = ""; @@ -1981,7 +1981,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -2031,7 +2031,7 @@ CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; @@ -2073,7 +2073,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -2093,7 +2093,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEVELOPMENT_TEAM = 5NN7GUYB6T; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -2118,7 +2118,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; GCC_OPTIMIZATION_LEVEL = s; @@ -2155,7 +2155,7 @@ CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_BITCODE = NO; ENABLE_CODE_COVERAGE = NO; @@ -2192,7 +2192,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2243,7 +2243,7 @@ CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES; CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5NN7GUYB6T; DYLIB_COMPATIBILITY_VERSION = 1; @@ -2294,7 +2294,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; @@ -2328,7 +2328,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 274; + CURRENT_PROJECT_VERSION = 276; DEVELOPMENT_TEAM = 5NN7GUYB6T; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index db8f1dd26e..960fdd466d 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -4137,18 +4137,16 @@ public enum FormatColor: String, Decodable, Hashable { case black = "black" case white = "white" - public var uiColor: Color { - get { - switch (self) { - case .red: return .red - case .green: return .green - case .blue: return .blue - case .yellow: return .yellow - case .cyan: return .cyan - case .magenta: return .purple - case .black: return .primary - case .white: return .primary - } + public var uiColor: Color? { + switch (self) { + case .red: .red + case .green: .green + case .blue: .blue + case .yellow: .yellow + case .cyan: .cyan + case .magenta: .purple + case .black: nil + case .white: nil } } } @@ -4173,6 +4171,14 @@ public enum ReportReason: Hashable { case let .unknown(type): return type } } + + public var attrString: NSAttributedString { + let descr = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body) + return NSAttributedString(string: text.isEmpty ? self.text : "\(self.text): ", attributes: [ + .font: UIFont(descriptor: descr.withSymbolicTraits(.traitItalic) ?? descr, size: 0), + .foregroundColor: UIColor(Color.red) + ]) + } } extension ReportReason: Encodable { diff --git a/apps/ios/bg.lproj/Localizable.strings b/apps/ios/bg.lproj/Localizable.strings index 432bc75894..f241158185 100644 --- a/apps/ios/bg.lproj/Localizable.strings +++ b/apps/ios/bg.lproj/Localizable.strings @@ -2825,7 +2825,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Само вашият контакт може да изпраща гласови съобщения."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Отвори"; /* No comment provided by engineer. */ diff --git a/apps/ios/cs.lproj/Localizable.strings b/apps/ios/cs.lproj/Localizable.strings index 25fb66aa12..003ac23325 100644 --- a/apps/ios/cs.lproj/Localizable.strings +++ b/apps/ios/cs.lproj/Localizable.strings @@ -124,6 +124,18 @@ /* time interval */ "%d days" = "%d dní"; +/* forward confirmation reason */ +"%d file(s) are still being downloaded." = "%d soubor(y) stále stahován(y)."; + +/* forward confirmation reason */ +"%d file(s) failed to download." = "%d soubor(y) se nepodařilo stáhnout."; + +/* forward confirmation reason */ +"%d file(s) were deleted." = "%d soubor(y) smazán(y)."; + +/* forward confirmation reason */ +"%d file(s) were not downloaded." = "%d soubor(y) nestažen(y)."; + /* time interval */ "%d hours" = "%d hodin"; @@ -2205,7 +2217,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Hlasové zprávy může odesílat pouze váš kontakt."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Otevřít"; /* No comment provided by engineer. */ diff --git a/apps/ios/de.lproj/Localizable.strings b/apps/ios/de.lproj/Localizable.strings index ef03de17f0..0eab764216 100644 --- a/apps/ios/de.lproj/Localizable.strings +++ b/apps/ios/de.lproj/Localizable.strings @@ -505,6 +505,9 @@ swipe action */ /* No comment provided by engineer. */ "All reports will be archived for you." = "Alle Meldungen werden für Sie archiviert."; +/* No comment provided by engineer. */ +"All servers" = "Alle Server"; + /* No comment provided by engineer. */ "All your contacts will remain connected." = "Alle Ihre Kontakte bleiben verbunden."; @@ -688,9 +691,6 @@ swipe action */ /* No comment provided by engineer. */ "Archiving database" = "Datenbank wird archiviert"; -/* No comment provided by engineer. */ -"Ask" = "Fragen"; - /* No comment provided by engineer. */ "Attach" = "Anhängen"; @@ -1460,7 +1460,7 @@ set passcode view */ "Current passphrase…" = "Aktuelles Passwort…"; /* No comment provided by engineer. */ -"Current profile" = "Aktueller Profil"; +"Current profile" = "Aktuelles Profil"; /* No comment provided by engineer. */ "Currently maximum supported file size is %@." = "Die derzeit maximal unterstützte Dateigröße beträgt %@."; @@ -3677,7 +3677,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Nur Ihr Kontakt kann Sprachnachrichten versenden."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Öffnen"; /* No comment provided by engineer. */ @@ -3695,21 +3695,12 @@ time to disappear */ /* No comment provided by engineer. */ "Open group" = "Gruppe öffnen"; -/* No comment provided by engineer. */ -"Open link" = "Web-Link öffnen"; - -/* No comment provided by engineer. */ -"Open links from chat list" = "Web-Links aus der Chat-Liste öffnen"; - /* authentication reason */ "Open migration to another device" = "Migration auf ein anderes Gerät öffnen"; /* No comment provided by engineer. */ "Open Settings" = "Geräte-Einstellungen öffnen"; -/* No comment provided by engineer. */ -"Open web link?" = "Web-Link öffnen?"; - /* No comment provided by engineer. */ "Opening app…" = "App wird geöffnet…"; @@ -4751,6 +4742,9 @@ chat item action */ /* No comment provided by engineer. */ "Share with contacts" = "Mit Kontakten teilen"; +/* No comment provided by engineer. */ +"Short link" = "Verkürzter Link"; + /* No comment provided by engineer. */ "Show → on messages sent via private routing." = "Bei Nachrichten, die über privates Routing versendet wurden, → anzeigen."; @@ -4793,6 +4787,9 @@ chat item action */ /* No comment provided by engineer. */ "SimpleX address or 1-time link?" = "SimpleX-Adresse oder Einmal-Link?"; +/* simplex link type */ +"SimpleX channel link" = "SimpleX-Kanal-Link"; + /* No comment provided by engineer. */ "SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "SimpleX-Chat und Flux haben vereinbart, die von Flux betriebenen Server in die App aufzunehmen."; @@ -5181,6 +5178,9 @@ report reason */ /* No comment provided by engineer. */ "This is your own SimpleX address!" = "Das ist Ihre eigene SimpleX-Adresse!"; +/* No comment provided by engineer. */ +"This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." = "Für diesen Link wird eine neuere App-Version benötigt. Bitte aktualisieren Sie die App oder bitten Sie Ihren Kontakt einen kompatiblen Link zu senden."; + /* No comment provided by engineer. */ "This link was used with another mobile device, please create a new link on the desktop." = "Dieser Link wurde schon mit einem anderen Mobiltelefon genutzt. Bitte erstellen sie einen neuen Link in der Desktop-App."; @@ -5373,6 +5373,9 @@ report reason */ /* swipe action */ "Unread" = "Ungelesen"; +/* No comment provided by engineer. */ +"Unsupported connection link" = "Verbindungs-Link wird nicht unterstützt"; + /* No comment provided by engineer. */ "Up to 100 last messages are sent to new members." = "Bis zu 100 der letzten Nachrichten werden an neue Mitglieder gesendet."; @@ -5466,6 +5469,9 @@ report reason */ /* No comment provided by engineer. */ "Use servers" = "Verwende Server"; +/* No comment provided by engineer. */ +"Use short links (BETA)" = "Kurze Links verwenden (BETA)"; + /* No comment provided by engineer. */ "Use SimpleX Chat servers?" = "Verwenden Sie SimpleX-Chat-Server?"; @@ -5475,6 +5481,9 @@ report reason */ /* No comment provided by engineer. */ "Use TCP port %@ when no port is specified." = "Solange kein Port konfiguriert ist, wird TCP-Port %@ genutzt."; +/* No comment provided by engineer. */ +"Use TCP port 443 for preset servers only." = "TCP-Port 443 nur für voreingestellte Server verwenden."; + /* No comment provided by engineer. */ "Use the app while in the call." = "Die App kann während eines Anrufs genutzt werden."; @@ -5694,9 +5703,6 @@ report reason */ /* pref value */ "yes" = "Ja"; -/* No comment provided by engineer. */ -"Yes" = "Ja"; - /* No comment provided by engineer. */ "you" = "Profil"; diff --git a/apps/ios/es.lproj/Localizable.strings b/apps/ios/es.lproj/Localizable.strings index f9fe85dba7..e797b73b98 100644 --- a/apps/ios/es.lproj/Localizable.strings +++ b/apps/ios/es.lproj/Localizable.strings @@ -505,6 +505,9 @@ swipe action */ /* No comment provided by engineer. */ "All reports will be archived for you." = "Todos los informes serán archivados para ti."; +/* No comment provided by engineer. */ +"All servers" = "Todos los servidores"; + /* No comment provided by engineer. */ "All your contacts will remain connected." = "Todos tus contactos permanecerán conectados."; @@ -688,9 +691,6 @@ swipe action */ /* No comment provided by engineer. */ "Archiving database" = "Archivando base de datos"; -/* No comment provided by engineer. */ -"Ask" = "Preguntar"; - /* No comment provided by engineer. */ "Attach" = "Adjuntar"; @@ -3677,7 +3677,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Sólo tu contacto puede enviar mensajes de voz."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Abrir"; /* No comment provided by engineer. */ @@ -3695,21 +3695,12 @@ time to disappear */ /* No comment provided by engineer. */ "Open group" = "Grupo abierto"; -/* No comment provided by engineer. */ -"Open link" = "Abrir enlace"; - -/* No comment provided by engineer. */ -"Open links from chat list" = "Abrir enlaces desde listado de chats"; - /* authentication reason */ "Open migration to another device" = "Abrir menú migración a otro dispositivo"; /* No comment provided by engineer. */ "Open Settings" = "Abrir Configuración"; -/* No comment provided by engineer. */ -"Open web link?" = "¿Abrir enlace web?"; - /* No comment provided by engineer. */ "Opening app…" = "Iniciando aplicación…"; @@ -4751,6 +4742,9 @@ chat item action */ /* No comment provided by engineer. */ "Share with contacts" = "Compartir con contactos"; +/* No comment provided by engineer. */ +"Short link" = "Enlace corto"; + /* No comment provided by engineer. */ "Show → on messages sent via private routing." = "Mostrar → en mensajes con enrutamiento privado."; @@ -4793,6 +4787,9 @@ chat item action */ /* No comment provided by engineer. */ "SimpleX address or 1-time link?" = "¿Dirección SimpleX o enlace de un uso?"; +/* simplex link type */ +"SimpleX channel link" = "Enlace de canal SimpleX"; + /* No comment provided by engineer. */ "SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "Simplex Chat y Flux han acordado incluir en la aplicación servidores operados por Flux."; @@ -5181,6 +5178,9 @@ report reason */ /* No comment provided by engineer. */ "This is your own SimpleX address!" = "¡Esta es tu propia dirección SimpleX!"; +/* No comment provided by engineer. */ +"This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." = "Este enlace requiere una versión más reciente de la aplicación. Por favor, actualiza la aplicación o pide a tu contacto un enlace compatible."; + /* No comment provided by engineer. */ "This link was used with another mobile device, please create a new link on the desktop." = "Este enlace ha sido usado en otro dispositivo móvil, por favor crea un enlace nuevo en el ordenador."; @@ -5296,7 +5296,7 @@ report reason */ "Unblock member" = "Desbloquear miembro"; /* No comment provided by engineer. */ -"Unblock member for all?" = "¿Desbloquear miembro para todos?"; +"Unblock member for all?" = "¿Desbloquear el miembro para todos?"; /* No comment provided by engineer. */ "Unblock member?" = "¿Desbloquear miembro?"; @@ -5373,6 +5373,9 @@ report reason */ /* swipe action */ "Unread" = "No leído"; +/* No comment provided by engineer. */ +"Unsupported connection link" = "Enlace de conexión no compatible"; + /* No comment provided by engineer. */ "Up to 100 last messages are sent to new members." = "Hasta 100 últimos mensajes son enviados a los miembros nuevos."; @@ -5466,6 +5469,9 @@ report reason */ /* No comment provided by engineer. */ "Use servers" = "Usar servidores"; +/* No comment provided by engineer. */ +"Use short links (BETA)" = "Usar enlaces cortos (BETA)"; + /* No comment provided by engineer. */ "Use SimpleX Chat servers?" = "¿Usar servidores SimpleX Chat?"; @@ -5475,6 +5481,9 @@ report reason */ /* No comment provided by engineer. */ "Use TCP port %@ when no port is specified." = "Se usa el puerto TCP %@ cuando no se ha especificado otro."; +/* No comment provided by engineer. */ +"Use TCP port 443 for preset servers only." = "Usar puerto TCP 443 solo en servidores predefinidos."; + /* No comment provided by engineer. */ "Use the app while in the call." = "Usar la aplicación durante la llamada."; @@ -5694,9 +5703,6 @@ report reason */ /* pref value */ "yes" = "sí"; -/* No comment provided by engineer. */ -"Yes" = "Si"; - /* No comment provided by engineer. */ "you" = "tu"; diff --git a/apps/ios/fr.lproj/Localizable.strings b/apps/ios/fr.lproj/Localizable.strings index a0145a7f47..1c16f8847d 100644 --- a/apps/ios/fr.lproj/Localizable.strings +++ b/apps/ios/fr.lproj/Localizable.strings @@ -682,9 +682,6 @@ swipe action */ /* No comment provided by engineer. */ "Archiving database" = "Archivage de la base de données"; -/* No comment provided by engineer. */ -"Ask" = "Demander"; - /* No comment provided by engineer. */ "Attach" = "Attacher"; @@ -3566,7 +3563,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Seul votre contact peut envoyer des messages vocaux."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Ouvrir"; /* No comment provided by engineer. */ diff --git a/apps/ios/hu.lproj/Localizable.strings b/apps/ios/hu.lproj/Localizable.strings index 2d2fbb2ad1..c190cccaba 100644 --- a/apps/ios/hu.lproj/Localizable.strings +++ b/apps/ios/hu.lproj/Localizable.strings @@ -488,7 +488,7 @@ swipe action */ "all members" = "összes tag"; /* No comment provided by engineer. */ -"All messages and files are sent **end-to-end encrypted**, with post-quantum security in direct messages." = "Az összes üzenet és fájl **végpontok közötti titkosítással**, a közvetlen üzenetek továbbá kvantumálló titkosítással is rendelkeznek."; +"All messages and files are sent **end-to-end encrypted**, with post-quantum security in direct messages." = "Az összes üzenet és fájl **végpontok közötti titkosítással**, a közvetlen üzenetek továbbá kvantumbiztos titkosítással is rendelkeznek."; /* No comment provided by engineer. */ "All messages will be deleted - this cannot be undone!" = "Az összes üzenet törölve lesz – ez a művelet nem vonható vissza!"; @@ -505,6 +505,9 @@ swipe action */ /* No comment provided by engineer. */ "All reports will be archived for you." = "Az összes jelentés archiválva lesz az Ön számára."; +/* No comment provided by engineer. */ +"All servers" = "Összes kiszolgáló"; + /* No comment provided by engineer. */ "All your contacts will remain connected." = "Az összes partnerével kapcsolatban marad."; @@ -689,10 +692,7 @@ swipe action */ "Archiving database" = "Adatbázis archiválása"; /* No comment provided by engineer. */ -"Ask" = "Mindig kérdezzen rá"; - -/* No comment provided by engineer. */ -"Attach" = "Csatolás"; +"Attach" = "Mellékelés"; /* No comment provided by engineer. */ "attempts" = "próbálkozások"; @@ -2671,7 +2671,7 @@ snd error text */ "Hide profile" = "Profil elrejtése"; /* No comment provided by engineer. */ -"Hide:" = "Elrejtés:"; +"Hide:" = "Elrejtve:"; /* No comment provided by engineer. */ "History" = "Előzmények"; @@ -3274,10 +3274,10 @@ snd error text */ "Messages were deleted after you selected them." = "Az üzeneteket törölték miután kijelölte őket."; /* No comment provided by engineer. */ -"Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzeneteket, fájlokat és hívásokat **végpontok közötti titkosítással**, sérülés utáni titkosság-védelemmel és -helyreállítással, továbbá visszautasítással védi."; +"Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzenetek, a fájlok és a hívások **végpontok közötti titkosítással**, sérülés utáni titkosságvédelemmel és -helyreállítással, továbbá letagadhatósággal vannak védve."; /* No comment provided by engineer. */ -"Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzenetek, fájlok és hívások **végpontok közötti kvantumálló titkosítással** sérülés utáni titkosságvédelemmel, visszautasítással és feltörés utáni helyreállítással vannak védve."; +"Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." = "Az üzenetek, a fájlok és a hívások **végpontok közötti kvantumbiztos titkosítással**, sérülés utáni titkosságvédelemmel és -helyreállítással, továbbá letagadhatósággal vannak védve."; /* No comment provided by engineer. */ "Migrate device" = "Eszköz átköltöztetése"; @@ -3677,7 +3677,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Csak a partnere tud hangüzeneteket küldeni."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Megnyitás"; /* No comment provided by engineer. */ @@ -3695,21 +3695,12 @@ time to disappear */ /* No comment provided by engineer. */ "Open group" = "Csoport megnyitása"; -/* No comment provided by engineer. */ -"Open link" = "Hivatkozás megnyitása"; - -/* No comment provided by engineer. */ -"Open links from chat list" = "Hivatkozás megnyitása a csevegési listából"; - /* authentication reason */ "Open migration to another device" = "Átköltöztetés indítása egy másik eszközre"; /* No comment provided by engineer. */ "Open Settings" = "Beállítások megnyitása"; -/* No comment provided by engineer. */ -"Open web link?" = "Megnyitja a webhivatkozást?"; - /* No comment provided by engineer. */ "Opening app…" = "Az alkalmazás megnyitása…"; @@ -3915,7 +3906,7 @@ time to disappear */ "Privacy policy and conditions of use." = "Adatvédelmi szabályzat és felhasználási feltételek."; /* No comment provided by engineer. */ -"Privacy redefined" = "Adatvédelem újraértelmezve"; +"Privacy redefined" = "Újraértelmezett adatvédelem"; /* No comment provided by engineer. */ "Private chats, groups and your contacts are not accessible to server operators." = "A privát csevegések, a csoportok és a partnerek nem érhetők el a szerver üzemeltetői számára."; @@ -4023,10 +4014,10 @@ time to disappear */ "Push server" = "Push-kiszolgáló"; /* chat item text */ -"quantum resistant e2e encryption" = "végpontok közötti kvantumálló titkosítás"; +"quantum resistant e2e encryption" = "végpontok közötti kvantumbiztos titkosítás"; /* No comment provided by engineer. */ -"Quantum resistant encryption" = "Kvantumálló titkosítás"; +"Quantum resistant encryption" = "Kvantumbiztos titkosítás"; /* No comment provided by engineer. */ "Rate the app" = "Értékelje az alkalmazást"; @@ -4751,6 +4742,9 @@ chat item action */ /* No comment provided by engineer. */ "Share with contacts" = "Megosztás a partnerekkel"; +/* No comment provided by engineer. */ +"Short link" = "Rövid hivatkozás"; + /* No comment provided by engineer. */ "Show → on messages sent via private routing." = "Egy „→” jel megjelenítése a privát útválasztáson keresztül küldött üzeneteknél."; @@ -4776,7 +4770,7 @@ chat item action */ "Show QR code" = "QR-kód megjelenítése"; /* No comment provided by engineer. */ -"Show:" = "Megjelenítés:"; +"Show:" = "Megjelenítve:"; /* No comment provided by engineer. */ "SimpleX" = "SimpleX"; @@ -4793,6 +4787,9 @@ chat item action */ /* No comment provided by engineer. */ "SimpleX address or 1-time link?" = "SimpleX-cím vagy egyszer használható meghívó?"; +/* simplex link type */ +"SimpleX channel link" = "SimpleX-csatornahivatkozás"; + /* No comment provided by engineer. */ "SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "A SimpleX Chat és a Flux megállapodást kötött arról, hogy a Flux által üzemeltetett kiszolgálókat beépítik az alkalmazásba."; @@ -5158,7 +5155,7 @@ report reason */ "This chat is protected by end-to-end encryption." = "Ez a csevegés végpontok közötti titkosítással védett."; /* E2EE info chat item */ -"This chat is protected by quantum resistant end-to-end encryption." = "Ez a csevegés végpontok közötti kvantumálló titkosítással védett."; +"This chat is protected by quantum resistant end-to-end encryption." = "Ez a csevegés végpontok közötti kvantumbiztos titkosítással védett."; /* notification title */ "this contact" = "ez a partner"; @@ -5181,6 +5178,9 @@ report reason */ /* No comment provided by engineer. */ "This is your own SimpleX address!" = "Ez a saját SimpleX-címe!"; +/* No comment provided by engineer. */ +"This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." = "Ez a hivatkozás újabb alkalmazásverziót igényel. Frissítse az alkalmazást vagy kérjen egy kompatibilis hivatkozást a partnerétől."; + /* No comment provided by engineer. */ "This link was used with another mobile device, please create a new link on the desktop." = "Ezt a hivatkozást egy másik hordozható eszközön már használták, hozzon létre egy új hivatkozást a számítógépén."; @@ -5373,6 +5373,9 @@ report reason */ /* swipe action */ "Unread" = "Olvasatlan"; +/* No comment provided by engineer. */ +"Unsupported connection link" = "Nem támogatott kapcsolattartási hivatkozás"; + /* No comment provided by engineer. */ "Up to 100 last messages are sent to new members." = "Legfeljebb az utolsó 100 üzenet lesz elküldve az új tagok számára."; @@ -5466,6 +5469,9 @@ report reason */ /* No comment provided by engineer. */ "Use servers" = "Kiszolgálók használata"; +/* No comment provided by engineer. */ +"Use short links (BETA)" = "Rövid hivatkozások használata (béta)"; + /* No comment provided by engineer. */ "Use SimpleX Chat servers?" = "SimpleX Chat-kiszolgálók használata?"; @@ -5475,6 +5481,9 @@ report reason */ /* No comment provided by engineer. */ "Use TCP port %@ when no port is specified." = "A következő TCP-port használata, amikor nincs port megadva: %@."; +/* No comment provided by engineer. */ +"Use TCP port 443 for preset servers only." = "A 443-as TCP-port használata kizárólag az előre beállított kiszolgálokhoz."; + /* No comment provided by engineer. */ "Use the app while in the call." = "Használja az alkalmazást hívás közben."; @@ -5536,7 +5545,7 @@ report reason */ "via relay" = "egy továbbítókiszolgálón keresztül"; /* No comment provided by engineer. */ -"Via secure quantum resistant protocol." = "Biztonságos kvantumálló-protokollon keresztül."; +"Via secure quantum resistant protocol." = "Biztonságos kvantumbiztos protokollon keresztül."; /* No comment provided by engineer. */ "video" = "videó"; @@ -5694,9 +5703,6 @@ report reason */ /* pref value */ "yes" = "igen"; -/* No comment provided by engineer. */ -"Yes" = "Igen"; - /* No comment provided by engineer. */ "you" = "Ön"; diff --git a/apps/ios/it.lproj/Localizable.strings b/apps/ios/it.lproj/Localizable.strings index 3988b33531..f67a492cc4 100644 --- a/apps/ios/it.lproj/Localizable.strings +++ b/apps/ios/it.lproj/Localizable.strings @@ -505,6 +505,9 @@ swipe action */ /* No comment provided by engineer. */ "All reports will be archived for you." = "Tutte le segnalazioni verranno archiviate per te."; +/* No comment provided by engineer. */ +"All servers" = "Tutti i server"; + /* No comment provided by engineer. */ "All your contacts will remain connected." = "Tutti i tuoi contatti resteranno connessi."; @@ -688,9 +691,6 @@ swipe action */ /* No comment provided by engineer. */ "Archiving database" = "Archiviazione del database"; -/* No comment provided by engineer. */ -"Ask" = "Chiedi"; - /* No comment provided by engineer. */ "Attach" = "Allega"; @@ -3677,7 +3677,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Solo il tuo contatto può inviare messaggi vocali."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Apri"; /* No comment provided by engineer. */ @@ -3695,21 +3695,12 @@ time to disappear */ /* No comment provided by engineer. */ "Open group" = "Apri gruppo"; -/* No comment provided by engineer. */ -"Open link" = "Apri link"; - -/* No comment provided by engineer. */ -"Open links from chat list" = "Apri i link dall'elenco delle chat"; - /* authentication reason */ "Open migration to another device" = "Apri migrazione ad un altro dispositivo"; /* No comment provided by engineer. */ "Open Settings" = "Apri le impostazioni"; -/* No comment provided by engineer. */ -"Open web link?" = "Aprire il link?"; - /* No comment provided by engineer. */ "Opening app…" = "Apertura dell'app…"; @@ -4751,6 +4742,9 @@ chat item action */ /* No comment provided by engineer. */ "Share with contacts" = "Condividi con i contatti"; +/* No comment provided by engineer. */ +"Short link" = "Link breve"; + /* No comment provided by engineer. */ "Show → on messages sent via private routing." = "Mostra → nei messaggi inviati via instradamento privato."; @@ -4793,6 +4787,9 @@ chat item action */ /* No comment provided by engineer. */ "SimpleX address or 1-time link?" = "Indirizzo SimpleX o link una tantum?"; +/* simplex link type */ +"SimpleX channel link" = "Link del canale SimpleX"; + /* No comment provided by engineer. */ "SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "SimpleX Chat e Flux hanno concluso un accordo per includere server gestiti da Flux nell'app."; @@ -5181,6 +5178,9 @@ report reason */ /* No comment provided by engineer. */ "This is your own SimpleX address!" = "Questo è il tuo indirizzo SimpleX!"; +/* No comment provided by engineer. */ +"This link requires a newer app version. Please upgrade the app or ask your contact to send a compatible link." = "Questo link richiede una versione più recente dell'app. Aggiornala o chiedi al tuo contatto di inviare un link compatibile."; + /* No comment provided by engineer. */ "This link was used with another mobile device, please create a new link on the desktop." = "Questo link è stato usato con un altro dispositivo mobile, creane uno nuovo sul desktop."; @@ -5373,6 +5373,9 @@ report reason */ /* swipe action */ "Unread" = "Non letto"; +/* No comment provided by engineer. */ +"Unsupported connection link" = "Link di connessione non supportato"; + /* No comment provided by engineer. */ "Up to 100 last messages are sent to new members." = "Vengono inviati ai nuovi membri fino a 100 ultimi messaggi."; @@ -5466,6 +5469,9 @@ report reason */ /* No comment provided by engineer. */ "Use servers" = "Usa i server"; +/* No comment provided by engineer. */ +"Use short links (BETA)" = "Usa link brevi (BETA)"; + /* No comment provided by engineer. */ "Use SimpleX Chat servers?" = "Usare i server di SimpleX Chat?"; @@ -5475,6 +5481,9 @@ report reason */ /* No comment provided by engineer. */ "Use TCP port %@ when no port is specified." = "Usa la porta TCP %@ quando non è specificata alcuna porta."; +/* No comment provided by engineer. */ +"Use TCP port 443 for preset servers only." = "Usa la porta TCP 443 solo per i server preimpostati."; + /* No comment provided by engineer. */ "Use the app while in the call." = "Usa l'app mentre sei in chiamata."; @@ -5694,9 +5703,6 @@ report reason */ /* pref value */ "yes" = "sì"; -/* No comment provided by engineer. */ -"Yes" = "Sì"; - /* No comment provided by engineer. */ "you" = "tu"; diff --git a/apps/ios/ja.lproj/Localizable.strings b/apps/ios/ja.lproj/Localizable.strings index 89934d67ce..9d0cccf591 100644 --- a/apps/ios/ja.lproj/Localizable.strings +++ b/apps/ios/ja.lproj/Localizable.strings @@ -2367,7 +2367,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "音声メッセージを送れるのはあなたの連絡相手だけです。"; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "開く"; /* No comment provided by engineer. */ diff --git a/apps/ios/nl.lproj/Localizable.strings b/apps/ios/nl.lproj/Localizable.strings index cd026361e0..d2cfcba0de 100644 --- a/apps/ios/nl.lproj/Localizable.strings +++ b/apps/ios/nl.lproj/Localizable.strings @@ -688,9 +688,6 @@ swipe action */ /* No comment provided by engineer. */ "Archiving database" = "Database archiveren"; -/* No comment provided by engineer. */ -"Ask" = "Vragen"; - /* No comment provided by engineer. */ "Attach" = "Bijvoegen"; @@ -3677,7 +3674,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Alleen uw contact kan spraak berichten verzenden."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Open"; /* No comment provided by engineer. */ @@ -3695,21 +3692,12 @@ time to disappear */ /* No comment provided by engineer. */ "Open group" = "Open groep"; -/* No comment provided by engineer. */ -"Open link" = "Link openen"; - -/* No comment provided by engineer. */ -"Open links from chat list" = "Open links van chatlijst"; - /* authentication reason */ "Open migration to another device" = "Open de migratie naar een ander apparaat"; /* No comment provided by engineer. */ "Open Settings" = "Open instellingen"; -/* No comment provided by engineer. */ -"Open web link?" = "Weblink openen?"; - /* No comment provided by engineer. */ "Opening app…" = "App openen…"; @@ -5694,9 +5682,6 @@ report reason */ /* pref value */ "yes" = "Ja"; -/* No comment provided by engineer. */ -"Yes" = "Ja"; - /* No comment provided by engineer. */ "you" = "jij"; diff --git a/apps/ios/pl.lproj/Localizable.strings b/apps/ios/pl.lproj/Localizable.strings index 82730db52a..867f3beff4 100644 --- a/apps/ios/pl.lproj/Localizable.strings +++ b/apps/ios/pl.lproj/Localizable.strings @@ -682,9 +682,6 @@ swipe action */ /* No comment provided by engineer. */ "Archiving database" = "Archiwizowanie bazy danych"; -/* No comment provided by engineer. */ -"Ask" = "Zapytaj"; - /* No comment provided by engineer. */ "Attach" = "Dołącz"; @@ -3320,7 +3317,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Tylko Twój kontakt może wysyłać wiadomości głosowe."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Otwórz"; /* No comment provided by engineer. */ diff --git a/apps/ios/ru.lproj/Localizable.strings b/apps/ios/ru.lproj/Localizable.strings index 45a2d6db4f..b819d013b9 100644 --- a/apps/ios/ru.lproj/Localizable.strings +++ b/apps/ios/ru.lproj/Localizable.strings @@ -685,9 +685,6 @@ swipe action */ /* No comment provided by engineer. */ "Archiving database" = "Подготовка архива"; -/* No comment provided by engineer. */ -"Ask" = "Спросить"; - /* No comment provided by engineer. */ "Attach" = "Прикрепить"; @@ -3575,7 +3572,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Только Ваш контакт может отправлять голосовые сообщения."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Открыть"; /* No comment provided by engineer. */ @@ -3593,21 +3590,12 @@ time to disappear */ /* No comment provided by engineer. */ "Open group" = "Открыть группу"; -/* No comment provided by engineer. */ -"Open link" = "Открыть ссылку"; - -/* No comment provided by engineer. */ -"Open links from chat list" = "Открыть ссылку из списка чатов"; - /* authentication reason */ "Open migration to another device" = "Открытие миграции на другое устройство"; /* No comment provided by engineer. */ "Open Settings" = "Открыть Настройки"; -/* No comment provided by engineer. */ -"Open web link?" = "Открыть веб-ссылку?"; - /* No comment provided by engineer. */ "Opening app…" = "Приложение отрывается…"; @@ -5544,9 +5532,6 @@ report reason */ /* pref value */ "yes" = "да"; -/* No comment provided by engineer. */ -"Yes" = "Да"; - /* No comment provided by engineer. */ "you" = "Вы"; diff --git a/apps/ios/tr.lproj/Localizable.strings b/apps/ios/tr.lproj/Localizable.strings index 718d547c67..ab0703333e 100644 --- a/apps/ios/tr.lproj/Localizable.strings +++ b/apps/ios/tr.lproj/Localizable.strings @@ -3353,7 +3353,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Sadece karşıdaki kişi sesli mesajlar gönderebilir."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Aç"; /* No comment provided by engineer. */ diff --git a/apps/ios/uk.lproj/Localizable.strings b/apps/ios/uk.lproj/Localizable.strings index f54ecec21d..8e2b514ed4 100644 --- a/apps/ios/uk.lproj/Localizable.strings +++ b/apps/ios/uk.lproj/Localizable.strings @@ -3401,7 +3401,7 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "Тільки ваш контакт може надсилати голосові повідомлення."; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "Відкрито"; /* No comment provided by engineer. */ diff --git a/apps/ios/zh-Hans.lproj/Localizable.strings b/apps/ios/zh-Hans.lproj/Localizable.strings index b363d25a4c..6ceeeb22d0 100644 --- a/apps/ios/zh-Hans.lproj/Localizable.strings +++ b/apps/ios/zh-Hans.lproj/Localizable.strings @@ -61,6 +61,9 @@ /* No comment provided by engineer. */ "**Recommended**: device token and end-to-end encrypted notifications are sent to SimpleX Chat push server, but it does not see the message content, size or who it is from." = "**推荐**:设备令牌和通知会发送至 SimpleX Chat 通知服务器,但是消息内容、大小或者发送人不会。"; +/* No comment provided by engineer. */ +"**Scan / Paste link**: to connect via a link you received." = "**扫描/粘贴链接**:用您收到的链接连接。"; + /* No comment provided by engineer. */ "**Warning**: Instant push notifications require passphrase saved in Keychain." = "**警告**:及时推送通知需要保存在钥匙串的密码。"; @@ -133,6 +136,9 @@ /* notification title */ "%@ wants to connect!" = "%@ 要连接!"; +/* format for date separator in chat */ +"%@, %@" = "%1$@, %2$@"; + /* No comment provided by engineer. */ "%@, %@ and %lld members" = "%@, %@ 和 %lld 成员"; @@ -145,9 +151,24 @@ /* time interval */ "%d days" = "%d 天"; +/* forward confirmation reason */ +"%d file(s) are still being downloaded." = "仍在下载 %d 个文件。"; + +/* forward confirmation reason */ +"%d file(s) failed to download." = "%d 个文件下载失败。"; + +/* forward confirmation reason */ +"%d file(s) were deleted." = "已刪除 %d 个文件。"; + +/* forward confirmation reason */ +"%d file(s) were not downloaded." = "未能下载 %d 个文件。"; + /* time interval */ "%d hours" = "%d 小时"; +/* alert title */ +"%d messages not forwarded" = "未转发 %d 条消息"; + /* time interval */ "%d min" = "%d 分钟"; @@ -157,8 +178,11 @@ /* time interval */ "%d sec" = "%d 秒"; +/* delete after time */ +"%d seconds(s)" = "%d 秒"; + /* integrity error chat item */ -"%d skipped message(s)" = "%d 跳过消息"; +"%d skipped message(s)" = "跳过的 %d 条消息"; /* time interval */ "%d weeks" = "%d 星期"; @@ -262,6 +286,15 @@ time interval */ time interval */ "1 week" = "1周"; +/* delete after time */ +"1 year" = "1 年"; + +/* No comment provided by engineer. */ +"1-time link" = "一次性链接"; + +/* No comment provided by engineer. */ +"1-time link can be used *with one contact only* - share in person or via any messenger." = "一次性链接*只能给一名联系人*使用。当面或使用聊天应用分享链接。"; + /* No comment provided by engineer. */ "5 minutes" = "5分钟"; @@ -295,6 +328,9 @@ time interval */ /* No comment provided by engineer. */ "Abort changing address?" = "中止地址更改?"; +/* No comment provided by engineer. */ +"About operators" = "关于运营方"; + /* No comment provided by engineer. */ "About SimpleX Chat" = "关于SimpleX Chat"; @@ -309,6 +345,9 @@ accept incoming call via notification swipe action */ "Accept" = "接受"; +/* No comment provided by engineer. */ +"Accept conditions" = "接受条款"; + /* No comment provided by engineer. */ "Accept connection request?" = "接受联系人?"; @@ -322,18 +361,30 @@ swipe action */ /* call status */ "accepted call" = "已接受通话"; +/* No comment provided by engineer. */ +"Accepted conditions" = "已接受的条款"; + /* No comment provided by engineer. */ "Acknowledged" = "确认"; /* No comment provided by engineer. */ "Acknowledgement errors" = "确认错误"; +/* token status text */ +"Active" = "活跃"; + /* No comment provided by engineer. */ "Active connections" = "活动连接"; /* No comment provided by engineer. */ "Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts." = "将地址添加到您的个人资料,以便您的联系人可以与其他人共享。个人资料更新将发送给您的联系人。"; +/* No comment provided by engineer. */ +"Add friends" = "添加好友"; + +/* No comment provided by engineer. */ +"Add list" = "添加列表"; + /* No comment provided by engineer. */ "Add profile" = "添加个人资料"; @@ -343,12 +394,27 @@ swipe action */ /* No comment provided by engineer. */ "Add servers by scanning QR codes." = "扫描二维码来添加服务器。"; +/* No comment provided by engineer. */ +"Add team members" = "添加团队成员"; + /* No comment provided by engineer. */ "Add to another device" = "添加另一设备"; +/* No comment provided by engineer. */ +"Add to list" = "添加到列表"; + /* No comment provided by engineer. */ "Add welcome message" = "添加欢迎信息"; +/* No comment provided by engineer. */ +"Add your team members to the conversations." = "将你的团队成员加入对话。"; + +/* No comment provided by engineer. */ +"Added media & file servers" = "已添加媒体和文件服务器"; + +/* No comment provided by engineer. */ +"Added message servers" = "已添加消息服务器"; + /* No comment provided by engineer. */ "Additional accent" = "附加重音"; @@ -364,6 +430,12 @@ swipe action */ /* No comment provided by engineer. */ "Address change will be aborted. Old receiving address will be used." = "将中止地址更改。将使用旧接收地址。"; +/* No comment provided by engineer. */ +"Address or 1-time link?" = "地址还是一次性链接?"; + +/* No comment provided by engineer. */ +"Address settings" = "地址设置"; + /* member role */ "admin" = "管理员"; @@ -388,12 +460,18 @@ swipe action */ /* chat item text */ "agreeing encryption…" = "同意加密…"; +/* No comment provided by engineer. */ +"All" = "全部"; + /* No comment provided by engineer. */ "All app data is deleted." = "已删除所有应用程序数据。"; /* No comment provided by engineer. */ "All chats and messages will be deleted - this cannot be undone!" = "所有聊天记录和消息将被删除——这一行为无法撤销!"; +/* alert message */ +"All chats will be removed from the list %@, and the list deleted." = "列表 %@ 和其中全部聊天将被删除。"; + /* No comment provided by engineer. */ "All data is erased when it is entered." = "所有数据在输入后将被删除。"; @@ -406,6 +484,9 @@ swipe action */ /* feature role */ "all members" = "所有成员"; +/* No comment provided by engineer. */ +"All messages and files are sent **end-to-end encrypted**, with post-quantum security in direct messages." = "所有消息和文件均通过**端到端加密**发送;私信以量子安全方式发送。"; + /* No comment provided by engineer. */ "All messages will be deleted - this cannot be undone!" = "所有消息都将被删除 - 这无法被撤销!"; @@ -418,6 +499,12 @@ swipe action */ /* profile dropdown */ "All profiles" = "所有配置文件"; +/* No comment provided by engineer. */ +"All reports will be archived for you." = "将为你存档所有举报。"; + +/* No comment provided by engineer. */ +"All servers" = "全部服务器"; + /* No comment provided by engineer. */ "All your contacts will remain connected." = "所有联系人会保持连接。"; @@ -463,6 +550,9 @@ swipe action */ /* No comment provided by engineer. */ "Allow to irreversibly delete sent messages. (24 hours)" = "允许不可撤回地删除已发送消息"; +/* No comment provided by engineer. */ +"Allow to report messsages to moderators." = "允许向 moderators 举报消息。"; + /* No comment provided by engineer. */ "Allow to send files and media." = "允许发送文件和媒体。"; @@ -517,6 +607,9 @@ swipe action */ /* No comment provided by engineer. */ "and %lld other events" = "和 %lld 其他事件"; +/* report reason */ +"Another reason" = "另一个理由"; + /* No comment provided by engineer. */ "Answer call" = "接听来电"; @@ -532,6 +625,9 @@ swipe action */ /* No comment provided by engineer. */ "App encrypts new local files (except videos)." = "应用程序为新的本地文件(视频除外)加密。"; +/* No comment provided by engineer. */ +"App group:" = "应用组:"; + /* No comment provided by engineer. */ "App icon" = "应用程序图标"; @@ -541,6 +637,9 @@ swipe action */ /* No comment provided by engineer. */ "App passcode is replaced with self-destruct passcode." = "应用程序密码被替换为自毁密码。"; +/* No comment provided by engineer. */ +"App session" = "应用会话"; + /* No comment provided by engineer. */ "App version" = "应用程序版本"; @@ -556,12 +655,30 @@ swipe action */ /* No comment provided by engineer. */ "Apply to" = "应用于"; +/* No comment provided by engineer. */ +"Archive" = "存档"; + +/* No comment provided by engineer. */ +"Archive %lld reports?" = "存档 %lld 个举报?"; + +/* No comment provided by engineer. */ +"Archive all reports?" = "存档所有举报?"; + /* No comment provided by engineer. */ "Archive and upload" = "存档和上传"; /* No comment provided by engineer. */ "Archive contacts to chat later." = "存档联系人以便稍后聊天."; +/* No comment provided by engineer. */ +"Archive report" = "存档举报"; + +/* No comment provided by engineer. */ +"Archive report?" = "存档举报?"; + +/* swipe action */ +"Archive reports" = "存档举报"; + /* No comment provided by engineer. */ "Archived contacts" = "已存档的联系人"; @@ -613,6 +730,9 @@ swipe action */ /* No comment provided by engineer. */ "Auto-accept images" = "自动接受图片"; +/* alert title */ +"Auto-accept settings" = "自动接受设置"; + /* No comment provided by engineer. */ "Back" = "返回"; @@ -634,15 +754,36 @@ swipe action */ /* No comment provided by engineer. */ "Bad message ID" = "错误消息 ID"; +/* No comment provided by engineer. */ +"Better calls" = "更佳的通话"; + /* No comment provided by engineer. */ "Better groups" = "更佳的群组"; +/* No comment provided by engineer. */ +"Better groups performance" = "更好的群性能"; + +/* No comment provided by engineer. */ +"Better message dates." = "更好的消息日期。"; + /* No comment provided by engineer. */ "Better messages" = "更好的消息"; /* No comment provided by engineer. */ "Better networking" = "更好的网络"; +/* No comment provided by engineer. */ +"Better notifications" = "更佳的通知"; + +/* No comment provided by engineer. */ +"Better privacy and security" = "更好的隐私和安全"; + +/* No comment provided by engineer. */ +"Better security ✅" = "更佳的安全性✅"; + +/* No comment provided by engineer. */ +"Better user experience" = "更佳的使用体验"; + /* No comment provided by engineer. */ "Black" = "黑色"; @@ -704,6 +845,15 @@ marked deleted chat item preview text */ /* No comment provided by engineer. */ "Bulgarian, Finnish, Thai and Ukrainian - thanks to the users and [Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!" = "保加利亚语、芬兰语、泰语和乌克兰语——感谢用户和[Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!"; +/* No comment provided by engineer. */ +"Business address" = "企业地址"; + +/* No comment provided by engineer. */ +"Business chats" = "企业聊天"; + +/* No comment provided by engineer. */ +"Businesses" = "企业"; + /* No comment provided by engineer. */ "By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA)." = "通过聊天资料(默认)或者[通过连接](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA)。"; @@ -777,6 +927,12 @@ alert button */ /* No comment provided by engineer. */ "Change" = "更改"; +/* alert title */ +"Change automatic message deletion?" = "更改消息自动删除设置?"; + +/* authentication reason */ +"Change chat profiles" = "更改聊天资料"; + /* No comment provided by engineer. */ "Change database passphrase?" = "更改数据库密码?"; @@ -820,6 +976,15 @@ set passcode view */ /* chat item text */ "changing address…" = "更改地址…"; +/* No comment provided by engineer. */ +"Chat" = "聊天"; + +/* No comment provided by engineer. */ +"Chat already exists" = "聊天已存在"; + +/* No comment provided by engineer. */ +"Chat already exists!" = "聊天已存在!"; + /* No comment provided by engineer. */ "Chat colors" = "聊天颜色"; @@ -856,15 +1021,30 @@ set passcode view */ /* No comment provided by engineer. */ "Chat preferences" = "聊天偏好设置"; +/* alert message */ +"Chat preferences were changed." = "聊天偏好设置已修改。"; + /* No comment provided by engineer. */ "Chat profile" = "用户资料"; /* No comment provided by engineer. */ "Chat theme" = "聊天主题"; +/* No comment provided by engineer. */ +"Chat will be deleted for all members - this cannot be undone!" = "将为所有成员删除聊天 - 此操作无法撤销!"; + +/* No comment provided by engineer. */ +"Chat will be deleted for you - this cannot be undone!" = "将为你删除聊天 - 此操作无法撤销!"; + /* No comment provided by engineer. */ "Chats" = "聊天"; +/* No comment provided by engineer. */ +"Check messages every 20 min." = "每 20 分钟检查消息。"; + +/* No comment provided by engineer. */ +"Check messages when allowed." = "在被允许时检查消息。"; + /* alert title */ "Check server address and try again." = "检查服务器地址并再试一次。"; @@ -898,6 +1078,12 @@ set passcode view */ /* No comment provided by engineer. */ "Clear conversation?" = "清除对话吗?"; +/* No comment provided by engineer. */ +"Clear group?" = "清除群?"; + +/* No comment provided by engineer. */ +"Clear or delete group?" = "清除还是删除群?"; + /* No comment provided by engineer. */ "Clear private notes?" = "清除私密笔记?"; @@ -913,6 +1099,9 @@ set passcode view */ /* No comment provided by engineer. */ "colored" = "彩色"; +/* report reason */ +"Community guidelines violation" = "违反社区指导方针"; + /* server test step */ "Compare file" = "对比文件"; @@ -925,9 +1114,27 @@ set passcode view */ /* No comment provided by engineer. */ "Completed" = "已完成"; +/* No comment provided by engineer. */ +"Conditions accepted on: %@." = "已于 %@ 接受条款。"; + +/* No comment provided by engineer. */ +"Conditions are accepted for the operator(s): **%@**." = "已接受运营方 **%@** 的条款。"; + +/* No comment provided by engineer. */ +"Conditions are already accepted for these operator(s): **%@**." = "已经接受下列运营方的条款:**%@**。"; + /* No comment provided by engineer. */ "Conditions of use" = "使用条款"; +/* No comment provided by engineer. */ +"Conditions will be accepted for the operator(s): **%@**." = "将接受下列运营方的条款:**%@**。"; + +/* No comment provided by engineer. */ +"Conditions will be accepted on: %@." = "将于 %@ 接受条款。"; + +/* No comment provided by engineer. */ +"Conditions will be automatically accepted for enabled operators on: %@." = "将在 %@ 自动接受启用的运营方的条款。"; + /* No comment provided by engineer. */ "Configure ICE servers" = "配置 ICE 服务器"; @@ -964,6 +1171,9 @@ set passcode view */ /* No comment provided by engineer. */ "Confirm upload" = "确认上传"; +/* token status text */ +"Confirmed" = "已确定"; + /* server test step */ "Connect" = "连接"; @@ -1063,6 +1273,9 @@ set passcode view */ /* No comment provided by engineer. */ "Connection and servers status." = "连接和服务器状态。"; +/* No comment provided by engineer. */ +"Connection blocked" = "连接被阻止"; + /* No comment provided by engineer. */ "Connection error" = "连接错误"; @@ -1072,12 +1285,24 @@ set passcode view */ /* chat list item title (it should not be shown */ "connection established" = "连接已建立"; +/* No comment provided by engineer. */ +"Connection is blocked by server operator:\n%@" = "连接被运营方 %@ 阻止"; + +/* No comment provided by engineer. */ +"Connection not ready." = "连接未就绪。"; + /* No comment provided by engineer. */ "Connection notifications" = "连接通知"; /* No comment provided by engineer. */ "Connection request sent!" = "已发送连接请求!"; +/* No comment provided by engineer. */ +"Connection requires encryption renegotiation." = "连接需要加密重协商。"; + +/* No comment provided by engineer. */ +"Connection security" = "连接安全性"; + /* No comment provided by engineer. */ "Connection terminated" = "连接被终止"; @@ -1135,6 +1360,9 @@ set passcode view */ /* No comment provided by engineer. */ "Contacts can mark messages for deletion; you will be able to view them." = "联系人可以将信息标记为删除;您将可以查看这些信息。"; +/* blocking reason */ +"Content violates conditions of use" = "内容违反使用条款"; + /* No comment provided by engineer. */ "Continue" = "继续"; @@ -1150,12 +1378,18 @@ set passcode view */ /* No comment provided by engineer. */ "Core version: v%@" = "核心版本: v%@"; +/* No comment provided by engineer. */ +"Corner" = "拐角"; + /* No comment provided by engineer. */ "Correct name to %@?" = "将名称更正为 %@?"; /* No comment provided by engineer. */ "Create" = "创建"; +/* No comment provided by engineer. */ +"Create 1-time link" = "创建一次性链接"; + /* No comment provided by engineer. */ "Create a group using a random profile." = "使用随机身份创建群组."; @@ -1171,6 +1405,9 @@ set passcode view */ /* No comment provided by engineer. */ "Create link" = "创建链接"; +/* No comment provided by engineer. */ +"Create list" = "创建列表"; + /* No comment provided by engineer. */ "Create new profile in [desktop app](https://simplex.chat/downloads/). 💻" = "在[桌面应用程序](https://simplex.chat/downloads/)中创建新的个人资料。 💻"; @@ -1207,6 +1444,9 @@ set passcode view */ /* No comment provided by engineer. */ "creator" = "创建者"; +/* No comment provided by engineer. */ +"Current conditions text couldn't be loaded, you can review conditions via this link:" = "无法加载当前条款文本,你可以通过此链接审阅条款:"; + /* No comment provided by engineer. */ "Current Passcode" = "当前密码"; @@ -1225,6 +1465,9 @@ set passcode view */ /* No comment provided by engineer. */ "Custom time" = "自定义时间"; +/* No comment provided by engineer. */ +"Customizable message shape." = "可自定义消息形状。"; + /* No comment provided by engineer. */ "Customize theme" = "自定义主题"; @@ -1341,12 +1584,21 @@ swipe action */ /* No comment provided by engineer. */ "Delete and notify contact" = "删除并通知联系人"; +/* No comment provided by engineer. */ +"Delete chat" = "删除聊天"; + +/* No comment provided by engineer. */ +"Delete chat messages from your device." = "从你的设备删除聊天消息。"; + /* No comment provided by engineer. */ "Delete chat profile" = "删除聊天资料"; /* No comment provided by engineer. */ "Delete chat profile?" = "删除聊天资料?"; +/* No comment provided by engineer. */ +"Delete chat?" = "删除聊天?"; + /* No comment provided by engineer. */ "Delete connection" = "删除连接"; @@ -1392,6 +1644,9 @@ swipe action */ /* No comment provided by engineer. */ "Delete link?" = "删除链接?"; +/* alert title */ +"Delete list?" = "删除列表?"; + /* No comment provided by engineer. */ "Delete member message?" = "删除成员消息?"; @@ -1410,6 +1665,9 @@ swipe action */ /* No comment provided by engineer. */ "Delete old database?" = "删除旧数据库吗?"; +/* No comment provided by engineer. */ +"Delete or moderate up to 200 messages." = "允许自行删除或管理员移除最多200条消息。"; + /* No comment provided by engineer. */ "Delete pending connection?" = "删除待定连接?"; @@ -1419,6 +1677,9 @@ swipe action */ /* server test step */ "Delete queue" = "删除队列"; +/* No comment provided by engineer. */ +"Delete report" = "删除举报"; + /* No comment provided by engineer. */ "Delete up to 20 messages at once." = "一次最多删除 20 条信息。"; @@ -1449,6 +1710,9 @@ swipe action */ /* No comment provided by engineer. */ "Deletion errors" = "删除错误"; +/* No comment provided by engineer. */ +"Delivered even when Apple drops them." = "已送达,即使苹果已将其删除。"; + /* No comment provided by engineer. */ "Delivery" = "传送"; @@ -1498,7 +1762,7 @@ swipe action */ "Device" = "设备"; /* No comment provided by engineer. */ -"Device authentication is disabled. Turning off SimpleX Lock." = "设备验证被禁用。关闭 SimpleX 锁定。"; +"Device authentication is disabled. Turning off SimpleX Lock." = "设备验证已禁用。 SimpleX 已解锁。"; /* No comment provided by engineer. */ "Device authentication is not enabled. You can turn on SimpleX Lock via Settings, once you enable device authentication." = "没有启用设备验证。一旦启用设备验证,您可以通过设置打开 SimpleX 锁定。"; @@ -1516,11 +1780,20 @@ swipe action */ "Direct messages" = "私信"; /* No comment provided by engineer. */ -"Direct messages between members are prohibited." = "此群中禁止成员之间私信。"; +"Direct messages between members are prohibited in this chat." = "此群禁止成员间私信。"; + +/* No comment provided by engineer. */ +"Direct messages between members are prohibited." = "此群禁止成员间私信。"; /* No comment provided by engineer. */ "Disable (keep overrides)" = "禁用(保留覆盖)"; +/* alert title */ +"Disable automatic message deletion?" = "禁用消息自动销毁?"; + +/* alert button */ +"Disable delete messages" = "停用消息删除"; + /* No comment provided by engineer. */ "Disable for all" = "全部禁用"; @@ -1572,21 +1845,33 @@ swipe action */ /* No comment provided by engineer. */ "Do NOT send messages directly, even if your or destination server does not support private routing." = "请勿直接发送消息,即使您的服务器或目标服务器不支持私有路由。"; +/* No comment provided by engineer. */ +"Do not use credentials with proxy." = "代理不使用身份验证凭据。"; + /* No comment provided by engineer. */ "Do NOT use private routing." = "不要使用私有路由。"; /* No comment provided by engineer. */ "Do NOT use SimpleX for emergency calls." = "请勿使用 SimpleX 进行紧急通话。"; +/* No comment provided by engineer. */ +"Documents:" = "文档:"; + /* No comment provided by engineer. */ "Don't create address" = "不创建地址"; /* No comment provided by engineer. */ "Don't enable" = "不要启用"; +/* No comment provided by engineer. */ +"Don't miss important messages." = "不错过重要消息。"; + /* No comment provided by engineer. */ "Don't show again" = "不再显示"; +/* No comment provided by engineer. */ +"Done" = "完成"; + /* No comment provided by engineer. */ "Downgrade and open chat" = "降级并打开聊天"; @@ -1603,6 +1888,9 @@ chat item action */ /* server test step */ "Download file" = "下载文件"; +/* alert action */ +"Download files" = "下载文件"; + /* No comment provided by engineer. */ "Downloaded" = "已下载"; @@ -1622,7 +1910,7 @@ chat item action */ "duplicate message" = "重复的消息"; /* No comment provided by engineer. */ -"duplicates" = "复本"; +"duplicates" = "副本"; /* No comment provided by engineer. */ "Duration" = "时长"; @@ -1630,6 +1918,9 @@ chat item action */ /* No comment provided by engineer. */ "e2e encrypted" = "端到端加密"; +/* No comment provided by engineer. */ +"E2E encrypted notifications." = "端到端加密的通知。"; + /* chat item action */ "Edit" = "编辑"; @@ -1648,6 +1939,9 @@ chat item action */ /* No comment provided by engineer. */ "Enable camera access" = "启用相机访问"; +/* No comment provided by engineer. */ +"Enable Flux in Network & servers settings for better metadata privacy." = "在“网络&服务器”设置中启用 Flux,更好地保护元数据隐私。"; + /* No comment provided by engineer. */ "Enable for all" = "全部启用"; @@ -1759,6 +2053,9 @@ chat item action */ /* chat item text */ "encryption re-negotiation required for %@" = "需要为 %@ 重新进行加密协商"; +/* No comment provided by engineer. */ +"Encryption renegotiation in progress." = "正进行加密重协商。"; + /* No comment provided by engineer. */ "ended" = "已结束"; @@ -1807,21 +2104,33 @@ chat item action */ /* No comment provided by engineer. */ "Error aborting address change" = "中止地址更改错误"; +/* alert title */ +"Error accepting conditions" = "接受条款出错"; + /* No comment provided by engineer. */ "Error accepting contact request" = "接受联系人请求错误"; /* No comment provided by engineer. */ "Error adding member(s)" = "添加成员错误"; +/* alert title */ +"Error adding server" = "添加服务器出错"; + /* No comment provided by engineer. */ "Error changing address" = "更改地址错误"; +/* No comment provided by engineer. */ +"Error changing connection profile" = "更改连接资料出错"; + /* No comment provided by engineer. */ "Error changing role" = "更改角色错误"; /* No comment provided by engineer. */ "Error changing setting" = "更改设置错误"; +/* No comment provided by engineer. */ +"Error changing to incognito!" = "切换至隐身聊天出错!"; + /* No comment provided by engineer. */ "Error connecting to forwarding server %@. Please try later." = "连接到转发服务器 %@ 时出错。请稍后尝试。"; @@ -1834,6 +2143,9 @@ chat item action */ /* No comment provided by engineer. */ "Error creating group link" = "创建群组链接错误"; +/* alert title */ +"Error creating list" = "创建列表出错"; + /* No comment provided by engineer. */ "Error creating member contact" = "创建成员联系人时出错"; @@ -1843,6 +2155,9 @@ chat item action */ /* No comment provided by engineer. */ "Error creating profile!" = "创建资料错误!"; +/* No comment provided by engineer. */ +"Error creating report" = "创建举报出错"; + /* No comment provided by engineer. */ "Error decrypting file" = "解密文件时出错"; @@ -1891,6 +2206,12 @@ chat item action */ /* No comment provided by engineer. */ "Error joining group" = "加入群组错误"; +/* alert title */ +"Error loading servers" = "加载服务器出错"; + +/* No comment provided by engineer. */ +"Error migrating settings" = "迁移设置出错"; + /* No comment provided by engineer. */ "Error opening chat" = "打开聊天时出错"; @@ -1903,12 +2224,21 @@ chat item action */ /* No comment provided by engineer. */ "Error reconnecting servers" = "重新连接服务器时出错"; +/* alert title */ +"Error registering for notifications" = "注册消息推送出错"; + /* No comment provided by engineer. */ "Error removing member" = "删除成员错误"; +/* alert title */ +"Error reordering lists" = "重排列表出错"; + /* No comment provided by engineer. */ "Error resetting statistics" = "重置统计信息时出错"; +/* alert title */ +"Error saving chat list" = "保存聊天列表出错"; + /* No comment provided by engineer. */ "Error saving group profile" = "保存群组资料错误"; @@ -1921,6 +2251,9 @@ chat item action */ /* No comment provided by engineer. */ "Error saving passphrase to keychain" = "保存密码到钥匙串错误"; +/* alert title */ +"Error saving servers" = "保存服务器出错"; + /* when migrating */ "Error saving settings" = "保存设置出错"; @@ -1948,18 +2281,27 @@ chat item action */ /* No comment provided by engineer. */ "Error stopping chat" = "停止聊天错误"; +/* No comment provided by engineer. */ +"Error switching profile" = "切换配置文件出错"; + /* alertTitle */ "Error switching profile!" = "切换资料错误!"; /* No comment provided by engineer. */ "Error synchronizing connection" = "同步连接错误"; +/* No comment provided by engineer. */ +"Error testing server connection" = "检验服务器连接出错"; + /* No comment provided by engineer. */ "Error updating group link" = "更新群组链接错误"; /* No comment provided by engineer. */ "Error updating message" = "更新消息错误"; +/* alert title */ +"Error updating server" = "更新服务器出错"; + /* No comment provided by engineer. */ "Error updating settings" = "更新设置错误"; @@ -1989,6 +2331,9 @@ snd error text */ /* No comment provided by engineer. */ "Errors" = "错误"; +/* servers error */ +"Errors in servers configuration." = "服务器配置有错误。"; + /* No comment provided by engineer. */ "Even when disabled in the conversation." = "即使在对话中被禁用。"; @@ -2001,6 +2346,9 @@ snd error text */ /* No comment provided by engineer. */ "expired" = "过期"; +/* token status text */ +"Expired" = "已过期"; + /* No comment provided by engineer. */ "Export database" = "导出数据库"; @@ -2025,15 +2373,30 @@ snd error text */ /* No comment provided by engineer. */ "Fast and no wait until the sender is online!" = "快速且无需等待发件人在线!"; +/* No comment provided by engineer. */ +"Faster deletion of groups." = "更快地删除群。"; + /* No comment provided by engineer. */ "Faster joining and more reliable messages." = "加入速度更快、信息更可靠。"; +/* No comment provided by engineer. */ +"Faster sending messages." = "更快发送消息。"; + /* swipe action */ "Favorite" = "最喜欢"; +/* No comment provided by engineer. */ +"Favorites" = "收藏"; + /* file error alert title */ "File error" = "文件错误"; +/* alert message */ +"File errors:\n%@" = "文件错误:\n%@"; + +/* file error text */ +"File is blocked by server operator:\n%@." = "文件被服务器运营方阻止:\n%@。"; + /* file error text */ "File not found - most likely file was deleted or cancelled." = "找不到文件 - 很可能文件已被删除或取消。"; @@ -2109,15 +2472,45 @@ snd error text */ /* No comment provided by engineer. */ "Fix not supported by group member" = "修复群组成员不支持的问题"; +/* No comment provided by engineer. */ +"For all moderators" = "所有 moderators"; + +/* servers error */ +"For chat profile %@:" = "为聊天资料 %@:"; + /* No comment provided by engineer. */ "For console" = "用于控制台"; +/* No comment provided by engineer. */ +"For example, if your contact receives messages via a SimpleX Chat server, your app will deliver them via a Flux server." = "比如,如果你通过 SimpleX 服务器收到消息,应用会通过 Flux 服务器传送它们。"; + +/* No comment provided by engineer. */ +"For me" = "仅自己"; + +/* No comment provided by engineer. */ +"For private routing" = "用于私密路由"; + +/* No comment provided by engineer. */ +"For social media" = "用于社交媒体"; + /* chat item action */ "Forward" = "转发"; +/* alert title */ +"Forward %d message(s)?" = "转发 %d 条消息?"; + /* No comment provided by engineer. */ "Forward and save messages" = "转发并保存消息"; +/* alert action */ +"Forward messages" = "已转发的消息"; + +/* alert message */ +"Forward messages without files?" = "仅转发消息不转发文件?"; + +/* No comment provided by engineer. */ +"Forward up to 20 messages at once." = "一次转发最多20条消息。"; + /* No comment provided by engineer. */ "forwarded" = "已转发"; @@ -2127,6 +2520,9 @@ snd error text */ /* No comment provided by engineer. */ "Forwarded from" = "转发自"; +/* No comment provided by engineer. */ +"Forwarding %lld messages" = "正在转发 %lld 条消息"; + /* No comment provided by engineer. */ "Forwarding server %@ failed to connect to destination server %@. Please try later." = "转发服务器 %@ 无法连接到目标服务器 %@。请稍后尝试。"; @@ -2163,6 +2559,9 @@ snd error text */ /* No comment provided by engineer. */ "Further reduced battery usage" = "进一步减少电池使用"; +/* No comment provided by engineer. */ +"Get notified when mentioned." = "被提及时收到通知。"; + /* No comment provided by engineer. */ "GIFs and stickers" = "GIF 和贴纸"; @@ -2235,9 +2634,15 @@ snd error text */ /* No comment provided by engineer. */ "Group will be deleted for you - this cannot be undone!" = "将为您删除群组——此操作无法撤消!"; +/* No comment provided by engineer. */ +"Groups" = "群"; + /* No comment provided by engineer. */ "Help" = "帮助"; +/* No comment provided by engineer. */ +"Help admins moderating their groups." = "帮助管理员管理群组。"; + /* No comment provided by engineer. */ "Hidden" = "隐藏"; @@ -2268,6 +2673,15 @@ snd error text */ /* time unit */ "hours" = "小时"; +/* No comment provided by engineer. */ +"How it affects privacy" = "它如何影响隐私"; + +/* No comment provided by engineer. */ +"How it helps privacy" = "它如何帮助隐私"; + +/* alert button */ +"How it works" = "工作原理"; + /* No comment provided by engineer. */ "How SimpleX works" = "SimpleX的工作原理"; @@ -2331,6 +2745,9 @@ snd error text */ /* No comment provided by engineer. */ "Importing archive" = "正在导入存档"; +/* No comment provided by engineer. */ +"Improved delivery, reduced traffic usage.\nMore improvements are coming soon!" = "改善传送,降低流量使用。\n更多改进即将推出!"; + /* No comment provided by engineer. */ "Improved message delivery" = "改进了消息传递"; @@ -2352,6 +2769,12 @@ snd error text */ /* No comment provided by engineer. */ "inactive" = "无效"; +/* report reason */ +"Inappropriate content" = "不当内容"; + +/* report reason */ +"Inappropriate profile" = "不当个人资料"; + /* No comment provided by engineer. */ "Incognito" = "隐身聊天"; @@ -2418,6 +2841,21 @@ snd error text */ /* No comment provided by engineer. */ "Interface colors" = "界面颜色"; +/* token status text */ +"Invalid" = "无效"; + +/* token status text */ +"Invalid (bad token)" = "Token 无效"; + +/* token status text */ +"Invalid (expired)" = "无效(已过期)"; + +/* token status text */ +"Invalid (unregistered)" = "无效(未注册)"; + +/* token status text */ +"Invalid (wrong topic)" = "无效(话题有误)"; + /* invalid chat data */ "invalid chat" = "无效聊天"; @@ -2469,6 +2907,9 @@ snd error text */ /* No comment provided by engineer. */ "Invite members" = "邀请成员"; +/* No comment provided by engineer. */ +"Invite to chat" = "邀请加入聊天"; + /* No comment provided by engineer. */ "Invite to group" = "邀请加入群组"; @@ -2490,6 +2931,9 @@ snd error text */ /* No comment provided by engineer. */ "iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications." = "在您重启应用或改变密码后,iOS钥匙串将被用来安全地存储密码——它将允许接收推送通知。"; +/* No comment provided by engineer. */ +"IP address" = "IP 地址"; + /* No comment provided by engineer. */ "Irreversible message deletion" = "不可撤回消息移除"; @@ -2580,6 +3024,12 @@ snd error text */ /* swipe action */ "Leave" = "离开"; +/* No comment provided by engineer. */ +"Leave chat" = "离开聊天"; + +/* No comment provided by engineer. */ +"Leave chat?" = "离开聊天?"; + /* No comment provided by engineer. */ "Leave group" = "离开群组"; @@ -2607,6 +3057,15 @@ snd error text */ /* No comment provided by engineer. */ "Linked desktops" = "已链接桌面"; +/* swipe action */ +"List" = "列表"; + +/* No comment provided by engineer. */ +"List name and emoji should be different for all lists." = "所有列表的名称和表情符号都应不同。"; + +/* No comment provided by engineer. */ +"List name..." = "列表名…"; + /* No comment provided by engineer. */ "LIVE" = "实时"; @@ -2676,12 +3135,21 @@ snd error text */ /* item status text */ "Member inactive" = "成员不活跃"; +/* chat feature */ +"Member reports" = "成员举报"; + +/* No comment provided by engineer. */ +"Member role will be changed to \"%@\". All chat members will be notified." = "将变更成员角色为“%@”。所有成员都会收到通知。"; + /* No comment provided by engineer. */ "Member role will be changed to \"%@\". All group members will be notified." = "成员角色将更改为 \"%@\"。所有群成员将收到通知。"; /* No comment provided by engineer. */ "Member role will be changed to \"%@\". The member will receive a new invitation." = "成员角色将更改为 \"%@\"。该成员将收到一份新的邀请。"; +/* No comment provided by engineer. */ +"Member will be removed from chat - this cannot be undone!" = "将从聊天中删除成员 - 此操作无法撤销!"; + /* No comment provided by engineer. */ "Member will be removed from group - this cannot be undone!" = "成员将被移出群组——此操作无法撤消!"; @@ -2691,6 +3159,9 @@ snd error text */ /* No comment provided by engineer. */ "Members can irreversibly delete sent messages. (24 hours)" = "群组成员可以不可撤回地删除已发送的消息"; +/* No comment provided by engineer. */ +"Members can report messsages to moderators." = "成员可以向 moderators 举报消息。"; + /* No comment provided by engineer. */ "Members can send direct messages." = "群组成员可以私信。"; @@ -2706,6 +3177,9 @@ snd error text */ /* No comment provided by engineer. */ "Members can send voice messages." = "群组成员可以发送语音消息。"; +/* No comment provided by engineer. */ +"Mention members 👋" = "提及成员👋"; + /* No comment provided by engineer. */ "Menus" = "菜单"; @@ -2751,6 +3225,9 @@ snd error text */ /* No comment provided by engineer. */ "Message servers" = "消息服务器"; +/* No comment provided by engineer. */ +"Message shape" = "消息形状"; + /* No comment provided by engineer. */ "Message source remains private." = "消息来源保持私密。"; @@ -2775,12 +3252,18 @@ snd error text */ /* No comment provided by engineer. */ "Messages from %@ will be shown!" = "将显示来自 %@ 的消息!"; +/* alert message */ +"Messages in this chat will never be deleted." = "此聊天中的消息永远不会被删除。"; + /* No comment provided by engineer. */ "Messages received" = "收到的消息"; /* No comment provided by engineer. */ "Messages sent" = "已发送的消息"; +/* alert message */ +"Messages were deleted after you selected them." = "在你选中消息后这些消息已被删除。"; + /* No comment provided by engineer. */ "Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." = "消息、文件和通话受到 **端到端加密** 的保护,具有完全正向保密、否认和闯入恢复。"; @@ -2847,12 +3330,18 @@ snd error text */ /* time unit */ "months" = "月"; +/* swipe action */ +"More" = "更多"; + /* No comment provided by engineer. */ "More improvements are coming soon!" = "更多改进即将推出!"; /* No comment provided by engineer. */ "More reliable network connection." = "更可靠的网络连接。"; +/* No comment provided by engineer. */ +"More reliable notifications" = "更可靠的通知"; + /* item status description */ "Most likely this connection is deleted." = "此连接很可能已被删除。"; @@ -2862,6 +3351,9 @@ snd error text */ /* notification label action */ "Mute" = "静音"; +/* notification label action */ +"Mute all" = "全部静音"; + /* No comment provided by engineer. */ "Muted when inactive!" = "不活动时静音!"; @@ -2874,12 +3366,18 @@ snd error text */ /* No comment provided by engineer. */ "Network connection" = "网络连接"; +/* No comment provided by engineer. */ +"Network decentralization" = "网络去中心化"; + /* snd error text */ "Network issues - message expired after many attempts to send it." = "网络问题 - 消息在多次尝试发送后过期。"; /* No comment provided by engineer. */ "Network management" = "网络管理"; +/* No comment provided by engineer. */ +"Network operator" = "网络运营方"; + /* No comment provided by engineer. */ "Network settings" = "网络设置"; @@ -2889,6 +3387,9 @@ snd error text */ /* delete after time */ "never" = "从不"; +/* token status text */ +"New" = "新"; + /* No comment provided by engineer. */ "New chat" = "新聊天"; @@ -2907,6 +3408,9 @@ snd error text */ /* No comment provided by engineer. */ "New display name" = "新显示名"; +/* notification */ +"New events" = "新事件"; + /* No comment provided by engineer. */ "New in %@" = "%@ 的新内容"; @@ -2928,6 +3432,15 @@ snd error text */ /* No comment provided by engineer. */ "New passphrase…" = "新密码……"; +/* No comment provided by engineer. */ +"New server" = "新服务器"; + +/* No comment provided by engineer. */ +"New SOCKS credentials will be used every time you start the app." = "每次启动应用都会使用新的 SOCKS 凭据。"; + +/* No comment provided by engineer. */ +"New SOCKS credentials will be used for each server." = "每个服务器都会使用新的 SOCKS 凭据。"; + /* pref value */ "no" = "否"; @@ -2937,6 +3450,15 @@ snd error text */ /* Authentication unavailable */ "No app password" = "没有应用程序密码"; +/* No comment provided by engineer. */ +"No chats" = "无聊天"; + +/* No comment provided by engineer. */ +"No chats found" = "找不到聊天"; + +/* No comment provided by engineer. */ +"No chats in list %@" = "列表 %@ 中无聊天"; + /* No comment provided by engineer. */ "No contacts selected" = "未选择联系人"; @@ -2967,9 +3489,24 @@ snd error text */ /* No comment provided by engineer. */ "No info, try to reload" = "无信息,尝试重新加载"; +/* servers error */ +"No media & file servers." = "无媒体和文件服务器。"; + +/* No comment provided by engineer. */ +"No message" = "无消息"; + +/* servers error */ +"No message servers." = "无消息服务器。"; + /* No comment provided by engineer. */ "No network connection" = "无网络连接"; +/* No comment provided by engineer. */ +"No permission to record speech" = "无录音权限"; + +/* No comment provided by engineer. */ +"No permission to record video" = "无录像权限"; + /* No comment provided by engineer. */ "No permission to record voice message" = "没有录制语音消息的权限"; @@ -2979,24 +3516,57 @@ snd error text */ /* No comment provided by engineer. */ "No received or sent files" = "未收到或发送文件"; +/* servers error */ +"No servers for private message routing." = "无私密消息路由服务器。"; + +/* servers error */ +"No servers to receive files." = "无文件接收服务器。"; + +/* servers error */ +"No servers to receive messages." = "无消息接收服务器。"; + +/* servers error */ +"No servers to send files." = "无文件发送服务器。"; + /* copied message info in history */ "no text" = "无文本"; +/* alert title */ +"No token!" = "无 token!"; + +/* No comment provided by engineer. */ +"No unread chats" = "没有未读聊天"; + /* No comment provided by engineer. */ "No user identifiers." = "没有用户标识符。"; /* No comment provided by engineer. */ "Not compatible!" = "不兼容!"; +/* No comment provided by engineer. */ +"Notes" = "附注"; + /* No comment provided by engineer. */ "Nothing selected" = "未选中任何内容"; +/* alert title */ +"Nothing to forward!" = "无可转发!"; + /* No comment provided by engineer. */ "Notifications" = "通知"; /* No comment provided by engineer. */ "Notifications are disabled!" = "通知被禁用!"; +/* alert title */ +"Notifications error" = "通知错误"; + +/* No comment provided by engineer. */ +"Notifications privacy" = "通知隐私"; + +/* alert title */ +"Notifications status" = "通知状态"; + /* No comment provided by engineer. */ "Now admins can:\n- delete members' messages.\n- disable members (\"observer\" role)" = "现在管理员可以:\n- 删除成员的消息。\n- 禁用成员(“观察员”角色)"; @@ -3041,6 +3611,9 @@ time to disappear */ /* No comment provided by engineer. */ "Onion hosts will not be used." = "将不会使用 Onion 主机。"; +/* No comment provided by engineer. */ +"Only chat owners can change preferences." = "仅聊天所有人可更改首选项。"; + /* No comment provided by engineer. */ "Only client devices store user profiles, contacts, groups, and messages." = "只有客户端设备存储用户资料、联系人、群组和**双层端到端加密**发送的消息。"; @@ -3056,6 +3629,12 @@ time to disappear */ /* No comment provided by engineer. */ "Only group owners can enable voice messages." = "只有群主可以启用语音信息。"; +/* No comment provided by engineer. */ +"Only sender and moderators see it" = "仅发送人和moderators能看到"; + +/* No comment provided by engineer. */ +"Only you and moderators see it" = "只有你和moderators能看到"; + /* No comment provided by engineer. */ "Only you can add message reactions." = "只有您可以添加消息回应。"; @@ -3086,15 +3665,21 @@ time to disappear */ /* No comment provided by engineer. */ "Only your contact can send voice messages." = "只有您的联系人可以发送语音消息。"; -/* No comment provided by engineer. */ +/* alert action */ "Open" = "打开"; +/* No comment provided by engineer. */ +"Open changes" = "打开更改"; + /* No comment provided by engineer. */ "Open chat" = "打开聊天"; /* authentication reason */ "Open chat console" = "打开聊天控制台"; +/* No comment provided by engineer. */ +"Open conditions" = "打开条款"; + /* No comment provided by engineer. */ "Open group" = "打开群"; @@ -3107,6 +3692,15 @@ time to disappear */ /* No comment provided by engineer. */ "Opening app…" = "正在打开应用程序…"; +/* No comment provided by engineer. */ +"Operator" = "运营方"; + +/* alert title */ +"Operator server" = "运营方服务器"; + +/* No comment provided by engineer. */ +"Or import archive file" = "或者导入或者导入压缩文件"; + /* No comment provided by engineer. */ "Or paste archive link" = "或粘贴存档链接"; @@ -3119,6 +3713,12 @@ time to disappear */ /* No comment provided by engineer. */ "Or show this code" = "或者显示此码"; +/* No comment provided by engineer. */ +"Or to share privately" = "或者私下分享"; + +/* No comment provided by engineer. */ +"Organize chats into lists" = "将聊天组织到列表"; + /* No comment provided by engineer. */ "other" = "其他"; @@ -3149,6 +3749,9 @@ time to disappear */ /* No comment provided by engineer. */ "Passcode set!" = "密码已设置!"; +/* No comment provided by engineer. */ +"Password" = "密码"; + /* No comment provided by engineer. */ "Password to show" = "显示密码"; @@ -3604,19 +4207,22 @@ swipe action */ "Reveal" = "揭示"; /* No comment provided by engineer. */ -"Revoke" = "撤销"; - -/* cancel file action */ -"Revoke file" = "撤销文件"; +"Review conditions" = "审阅条款"; /* No comment provided by engineer. */ -"Revoke file?" = "撤销文件?"; +"Revoke" = "吊销"; + +/* cancel file action */ +"Revoke file" = "吊销文件"; + +/* No comment provided by engineer. */ +"Revoke file?" = "吊销文件?"; /* No comment provided by engineer. */ "Role" = "角色"; /* No comment provided by engineer. */ -"Run chat" = "运行聊天程序"; +"Run chat" = "运行聊天"; /* No comment provided by engineer. */ "Safely receive files" = "安全接收文件"; @@ -3646,6 +4252,9 @@ chat item action */ /* No comment provided by engineer. */ "Save group profile" = "保存群组资料"; +/* No comment provided by engineer. */ +"Save list" = "保存列表"; + /* No comment provided by engineer. */ "Save passphrase and open chat" = "保存密码并打开聊天"; @@ -3667,6 +4276,9 @@ chat item action */ /* No comment provided by engineer. */ "Save welcome message?" = "保存欢迎信息?"; +/* alert title */ +"Save your profile?" = "保存您的个人资料?"; + /* No comment provided by engineer. */ "saved" = "已保存"; @@ -3685,6 +4297,9 @@ chat item action */ /* No comment provided by engineer. */ "Saved WebRTC ICE servers will be removed" = "已保存的WebRTC ICE服务器将被删除"; +/* No comment provided by engineer. */ +"Saving %lld messages" = "正在保存 %lld 条消息"; + /* No comment provided by engineer. */ "Scale" = "规模"; @@ -4025,6 +4640,18 @@ chat item action */ /* No comment provided by engineer. */ "SimpleX Address" = "SimpleX 地址"; +/* No comment provided by engineer. */ +"SimpleX address and 1-time links are safe to share via any messenger." = "可以通过任何消息应用安全分享 SimpleX 地址和一次性链接。"; + +/* No comment provided by engineer. */ +"SimpleX address or 1-time link?" = "SimpleX 地址或一次性链接?"; + +/* simplex link type */ +"SimpleX channel link" = "SimpleX 频道链接"; + +/* No comment provided by engineer. */ +"SimpleX Chat and Flux made an agreement to include Flux-operated servers into the app." = "SimpleX Chat 与 Flux 达成了协议,将由 Flux 控制的服务器纳入 SimpleX 应用。"; + /* No comment provided by engineer. */ "SimpleX Chat security was audited by Trail of Bits." = "SimpleX Chat 的安全性 由 Trail of Bits 审核。"; @@ -4032,10 +4659,10 @@ chat item action */ "SimpleX contact address" = "SimpleX 联系地址"; /* notification */ -"SimpleX encrypted message or connection event" = "SimpleX 加密消息或连接项目"; +"SimpleX encrypted message or connection event" = "SimpleX 加密的消息或连接事件"; /* simplex link type */ -"SimpleX group link" = "SimpleX 群组链接"; +"SimpleX group link" = "SimpleX 群链接"; /* chat feature */ "SimpleX links" = "SimpleX 链接"; @@ -4061,6 +4688,9 @@ chat item action */ /* simplex link type */ "SimpleX one-time invitation" = "SimpleX 一次性邀请"; +/* No comment provided by engineer. */ +"SimpleX protocols reviewed by Trail of Bits." = "SimpleX 协议由 Trail of Bits 审阅。"; + /* No comment provided by engineer. */ "Simplified incognito mode" = "简化的隐身模式"; @@ -4082,6 +4712,9 @@ chat item action */ /* blur media */ "Soft" = "软"; +/* No comment provided by engineer. */ +"Some app settings were not migrated." = "部分应用设置未被迁移。"; + /* No comment provided by engineer. */ "Some file(s) were not exported:" = "某些文件未导出:"; diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index 6660cbbb93..6ee609020a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt @@ -3902,7 +3902,7 @@ enum class MsgContentTag { class FormattedText(val text: String, val format: Format? = null) { // TODO make it dependent on simplexLinkMode preference fun link(mode: SimplexLinkMode): String? = when (format) { - is Format.Uri -> text + is Format.Uri -> if (text.startsWith("http://", ignoreCase = true) || text.startsWith("https://", ignoreCase = true)) text else "https://$text" is Format.SimplexLink -> if (mode == SimplexLinkMode.BROWSER) text else format.simplexUri is Format.Email -> "mailto:$text" is Format.Phone -> "tel:$text" diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index dc1c0b71a5..b3fdcf79c0 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -833,7 +833,7 @@ fun ChatLayout( } val reportsCount = reportsCount(chatInfo?.id) if (oneHandUI.value && chatBottomBar.value) { - if (chatsCtx.contentTag == null && reportsCount > 0) { + if (chatInfo is ChatInfo.Group && chatInfo.groupInfo.canModerate && chatsCtx.contentTag == null && reportsCount > 0) { ReportedCountToolbar(reportsCount, withStatusBar = true, showGroupReports) } else { StatusBarBackground() @@ -865,7 +865,7 @@ fun ChatLayout( SelectedItemsCounterToolbar(selectedChatItems, !oneHandUI.value || !chatBottomBar.value) } } - if (chatsCtx.contentTag == null && reportsCount > 0 && (!oneHandUI.value || !chatBottomBar.value)) { + if (chatInfo is ChatInfo.Group && chatInfo.groupInfo.canModerate && chatsCtx.contentTag == null && reportsCount > 0 && (!oneHandUI.value || !chatBottomBar.value)) { ReportedCountToolbar(reportsCount, withStatusBar = false, showGroupReports) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMentions.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMentions.kt index 1a63375432..91f4f5173c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMentions.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMentions.kt @@ -23,6 +23,12 @@ import chat.simplex.common.views.chatlist.setGroupMembers import chat.simplex.common.views.helpers.* import chat.simplex.res.MR import kotlinx.coroutines.launch +import kotlin.text.CharCategory.* + +val punctuation = setOf( + DASH_PUNCTUATION, START_PUNCTUATION, END_PUNCTUATION, + CONNECTOR_PUNCTUATION, OTHER_PUNCTUATION +) private val PICKER_ROW_SIZE = MEMBER_ROW_AVATAR_SIZE + (MEMBER_ROW_VERTICAL_PADDING * 2f) private val MAX_PICKER_HEIGHT = (PICKER_ROW_SIZE * 4) + (MEMBER_ROW_AVATAR_SIZE + MEMBER_ROW_VERTICAL_PADDING - 4.dp) @@ -126,7 +132,9 @@ fun GroupMentions( } val newName = existingMention?.key ?: composeState.value.mentionMemberName(member.memberProfile.displayName) mentions[newName] = CIMention(member) - var msgMention = "@" + if (newName.contains(" ")) "'$newName'" else newName + var msgMention = if (newName.contains(" ") || (newName.lastOrNull()?.category in punctuation)) + "@'$newName'" + else "@$newName" var newPos = range.start + msgMention.length val newMsgLength = composeState.value.message.text.length + msgMention.length - range.length if (newPos == newMsgLength) { diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml index a804d48dfb..4bb2244785 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml @@ -2372,4 +2372,8 @@ رابط قصير رابط قناة SimpleX رابط اتصال غير مدعوم + استخدم منفذ TCP 443 للخوادم المُعدة مسبقًا فقط. + إيقاف التشغيل + الخوادم المُعدة مسبقًا + جميع الخوادم diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ca/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ca/strings.xml index 77c2a6ef65..0e179fadd4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ca/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ca/strings.xml @@ -2349,4 +2349,8 @@ Emprar enllaços curts (BETA) Enllaç complet Enllaç curt + Tots els servidors + Apagat + Feu servir el port TCP 443 només per a servidors predefinits. + Servidors predefinits diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml index e262a59214..439b9df18d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml @@ -446,7 +446,7 @@ špatné ID zprávy duplicitní zpráva Přeskočené zprávy - Ochrana osobních údajů a zabezpečení + Soukromí a zabezpečení Vaše soukromí Skrývat aplikaci Odesílat náhledy odkazů @@ -2251,7 +2251,7 @@ Přepnout chat seznam: Tuto akci nelze zrušit - zprávy odeslané a přijaté v tomto chatu dříve než vybraná, budou smazány. Statistiky serverů budou obnoveny - nemůže být vráceno! - Odeslat soukromý report + Odešlete soukromý report Pomozte administrátorům moderovat své skupiny. Rychlejší mazání skupin. Od %s. @@ -2335,7 +2335,7 @@ Zprávy budou smazány pro všechny členy. Aplikace vyžaduje potvrzení stahování z neznámých serverů (s výjimkou .onion nebo při aktivaci SOCKS proxy). Musíte povolit kontaktům volání, abyste jim mohli zavolat. - Nastavit expirace zpráv. + Nastavení expirace zpráv. Zobrazit procenta Nahraný archiv databáze bude ze serverů trvale odstraněn. Pro ochranu před záměnou odkazů, můžete porovnat bezpečnostní kódy. @@ -2370,4 +2370,14 @@ Nastavit operátora serveru Zásady ochrany soukromí a podmínky používání. Soukromé konverzace, skupiny a kontakty nejsou přístupné provozovatelům serverů. + Nepodporovaný odkaz k připojení + Používejte krátké odkazy (BETA) + Tento odkaz vyžaduje novější verzi aplikace. Prosím aktualizujte aplikaci nebo požádejte kontakt o odeslání kompatibilního odkazu. + odkaz SimpleX kanálu + Úplný odkaz + Krátký odkaz + Všechny servery + Vypnut + Přednastavené servery + Použít TCP port 443 jen pro přednastavené servery. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml index 089ef06827..6646720c5c 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml @@ -1145,7 +1145,7 @@ Die ID der nächsten Nachricht ist falsch (kleiner oder gleich der vorherigen). \nDies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompromittiert wurde. %1$d Nachrichten konnten nicht entschlüsselt werden. - Der Hash der vorherigen Nachricht unterscheidet sich.\" + Der Hash der vorherigen Nachricht unterscheidet sich. Sie können die SimpleX-Sperre über die Einstellungen aktivieren. SOCKS-Proxy-Einstellungen System-Authentifizierung @@ -2453,9 +2453,13 @@ Server-Betreiber konfigurieren Private Chats, Gruppen und Ihre Kontakte sind für Server-Betreiber nicht zugänglich. Verbindungs-Link wird nicht unterstützt - Verkürzte Links verwenden (BETA) + Kurze Links verwenden (BETA) Verkürzter Link Vollständiger Link SimpleX-Kanal-Link Für diesen Link wird eine neuere App-Version benötigt. Bitte aktualisieren Sie die App oder bitten Sie Ihren Kontakt einen kompatiblen Link zu senden. + Alle Server + Aus + TCP-Port 443 nur für voreingestellte Server verwenden. + Voreingestellte Server diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml index 6ba4c15afb..5667c42d2d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml @@ -1068,7 +1068,7 @@ Hash de mensaje incorrecto ID de mensaje incorrecto Puede ocurrir si tu contacto o tu usáis una copia de seguridad antigua de la base de datos. - El hash del mensaje anterior es diferente.\" + El hash del mensaje anterior es diferente. %1$d mensaje(s) no ha(n) podido ser descifrado(s). Detener archivo El archivo será eliminado de los servidores. @@ -1552,7 +1552,7 @@ ¿Bloqear miembro para todos? Creado: %s Bloquear para todos - ¿Desbloquear miembro para todos? + ¿Desbloquear el miembro para todos? Desbloquear para todos bloqueado bloqueado por administrador @@ -2360,7 +2360,7 @@ rechazado ¿Expulsar miembros? ¡Los mensajes de estos miembros serán mostrados! - ¿Desbloquear miembros para todos? + ¿Desbloquear los miembros para todos? ¡Todos los mensajes nuevos de estos miembros estarán ocultos! ¿Bloquear miembros para todos? Los miembros serán expulsados del chat. ¡No puede deshacerse! @@ -2383,4 +2383,8 @@ Este enlace requiere una versión más reciente de la aplicación. Por favor, actualiza la aplicación o pide a tu contacto un enlace compatible. Enlace de conexión no compatible Usar enlaces cortos (BETA) + Usar puerto TCP 443 solo en servidores predefinidos. + Todos los servidores + Servidores predefinidos + No diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml index 6d62d3f5b8..c8897c4063 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/hu/strings.xml @@ -141,7 +141,7 @@ Engedélyezés Érvénytelen számítógépcím Profil hozzáadása - Csatolás + Mellékelés Alkalmazás jelkód Felkérték a kép fogadására Kamera @@ -658,7 +658,7 @@ Kép A fájlok- és a médiatartalmak küldése le van tiltva. Hogyan működik - Elrejtés: + Elrejtve: Hiba történt a partnerrel történő kapcsolat létrehozásában ICE-kiszolgálók (soronként egy) beolvashatja a QR-kódot a videohívásban, vagy a partnere megoszthat egy meghívási hivatkozást.]]> @@ -1122,7 +1122,7 @@ Biztonsági kód hitelesítése eltávolította Önt SimpleX-cím - Megjelenítés: + Megjelenítve: válasz fogadása… Visszaállítja az adatbázismentést? Üzenetek fogadása… @@ -1175,7 +1175,7 @@ elküldve SOCKS-proxy használata Élő üzenet küldése - Adatvédelem újraértelmezve + Újraértelmezett adatvédelem Hangüzenet… Alkalmazás képernyőjének védelme QR-kód megjelenítése @@ -1349,7 +1349,7 @@ Akkor lesz kapcsolódva, ha a meghívási kérése el lesz fogadva, várjon, vagy ellenőrizze később! A hangüzenetek küldése le van tiltva. Alkalmazás akkumulátor-használata / Korlátlan módot az alkalmazás beállításaiban.]]> - Biztonságos kvantumálló-protokollon keresztül. + Biztonságos kvantumbiztos protokollon keresztül. - legfeljebb 5 perc hosszúságú hangüzenetek.\n- egyéni üzenet-eltűnési időkorlát.\n- előzmények szerkesztése. Társítás számítógéppel menüt a hordozható eszköz alkalmazásban és olvassa be a QR-kódot.]]> %s ekkor: %s @@ -1652,7 +1652,7 @@ Átköltöztetés egy másik eszközre Figyelmeztetés: az archívum törölve lesz.]]> Átköltöztetés egy másik eszközről - Kvantumálló titkosítás + Kvantumbiztos titkosítás Megpróbálhatja még egyszer. Átköltöztetés befejezve Átköltöztetés egy másik eszközre QR-kód használatával. @@ -1660,12 +1660,12 @@ Megjegyzés: ha két eszközön is ugyanazt az adatbázist használja, akkor biztonsági védelemként megszakítja a partnereitől érkező üzenetek visszafejtését.]]> Megpróbálhatja még egyszer. Érvénytelen hivatkozás - végpontok közötti kvantumálló titkosítás + végpontok közötti kvantumbiztos titkosítás Ez a csevegés végpontok közötti titkosítással védett. Átköltöztetési párbeszédablak megnyitása - Ez a csevegés végpontok közötti kvantumálló titkosítással védett. - végpontok közötti titkosítással, sérülés utáni titkosság-védelemmel és -helyreállítással, továbbá visszautasítással védi.]]> - végpontok közötti kvantumálló titkosítással sérülés utáni titkosságvédelemmel, visszautasítással és feltörés utáni helyreállítással vannak védve.]]> + Ez a csevegés végpontok közötti kvantumbiztos titkosítással védett. + végpontok közötti titkosítással, sérülés utáni titkosságvédelemmel és -helyreállítással, továbbá letagadhatósággal vannak védve.]]> + végpontok közötti kvantumbiztos titkosítással, sérülés utáni titkosságvédelemmel és -helyreállítással, továbbá letagadhatósággal vannak védve.]]> Hiba történt az értesítés megjelenítésekor, lépjen kapcsolatba a fejlesztőkkel. Keresse meg ezt az engedélyt az Android beállításaiban, és adja meg kézzel. Engedélyezés a beállításokban @@ -2172,7 +2172,7 @@ A küldéshez másolhatja és csökkentheti az üzenet méretét. Adja hozzá a munkatársait a beszélgetésekhez. Üzleti cím - végpontok közötti titkosítással, a közvetlen üzenetek továbbá kvantumálló titkosítással is rendelkeznek.]]> + végpontok közötti titkosítással, a közvetlen üzenetek továbbá kvantumbiztos titkosítással is rendelkeznek.]]> Hogyan segíti az adatvédelmet Nincs háttérszolgáltatás Értesítések és akkumulátor @@ -2350,4 +2350,8 @@ Teljes hivatkozás Ez a hivatkozás újabb alkalmazásverziót igényel. Frissítse az alkalmazást vagy kérjen egy kompatibilis hivatkozást a partnerétől. SimpleX-csatornahivatkozás + Összes kiszolgáló + Kikapcsolva + Előre beállított kiszolgálók + A 443-as TCP-port használata kizárólag az előre beállított kiszolgálokhoz. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/in/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/in/strings.xml index 95b60a3394..a269149e99 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/in/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/in/strings.xml @@ -2349,4 +2349,14 @@ Kebijakan privasi dan ketentuan penggunaan. Obrolan pribadi, grup, dan kontak Anda tidak dapat diakses oleh operator server. Frasa sandi di Keystore tidak dapat dibaca, silakan masukkan secara manual. Hal ini mungkin terjadi setelah pembaruan sistem yang tidak kompatibel dengan aplikasi. Jika tidak demikian, silakan hubungi pengembang. + Gunakan port TCP 443 hanya untuk presetel server. + Semua server + Mati + Presetel server + Tautan lengkap + Tautan ini perlu versi aplikasi yang baru. Harap perbarui aplikasi atau minta kontak untuk kirim tautan kompatibel. + Tautan saluran SimpleX + Gunakan tautan singkat (BETA) + Tautan koneksi tidak didukung + Tautan singkat diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml index 4373091266..6c086835ea 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml @@ -1069,7 +1069,7 @@ \nPuò accadere a causa di qualche bug o quando la connessione è compromessa. %1$d messaggi non decifrati. Hash del messaggio errato - L\'hash del messaggio precedente è diverso.\" + L\'hash del messaggio precedente è diverso. Si prega di segnalarlo agli sviluppatori. L\'invio del file verrà interrotto. Ferma file @@ -2387,4 +2387,8 @@ Link del canale SimpleX Link di connessione non supportato Usa link brevi (BETA) + Tutti i server + Off + Server preimpostati + Usa la porta TCP 443 solo per i server preimpostati. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml index ad2a7e67be..549cb01b63 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml @@ -18,7 +18,7 @@ 1-разове посилання Про SimpleX Chat Додавайте сервери, скануючи QR-коди. - Всі чати і повідомлення будуть видалені - цю дію неможливо скасувати! + Усі чати та повідомлення будуть видалені - цю дію неможливо скасувати! Дозволити дзвінки тільки за умови, що ваш контакт дозволяє їх. Дозволити безповоротне видалення повідомлень, тільки якщо ваш контакт дозволяє вам. (24 години) Дозволити голосові повідомлення\? @@ -50,20 +50,20 @@ Дозволити Розширені налаштування мережі Отримувати доступ до серверів через SOCKS-проксі на порті %d? Проксі має бути запущено до активації цієї опції. - Всі ваші контакти залишаться підключеними. - Всі дані застосунку буде видалено. + Усі ваші контакти залишаться підключеними. + Усі дані застосунку буде видалено. Після перезапуску додатка або зміни ключової фрази буде використано сховище ключів Android для безпечного збереження ключової фрази - це дозволить отримувати сповіщення. Дозвольте вашим контактам надсилати голосові повідомлення. Прийняти інкогніто Додати сервер адміністратор Додати привітання - Всі учасники групи залишаться підключеними. + Усі учасники групи залишаться підключеними. Дозвольте вашим контактам надсилати повідомлення, які зникають. - Всі повідомлення будуть видалені - цю дію неможливо скасувати! Повідомлення будуть видалені ЛИШЕ для вас. + Усі повідомлення будуть видалені - цю дію неможливо скасувати! Повідомлення будуть видалені ЛИШЕ для вас. Версія додатку Додайте адресу до свого профілю, щоб ваші контакти могли поділитися нею з іншими людьми. Оновлення профілю буде відправлено вашим контактам. - Всі ваші контакти залишаться підключеними. Оновлення профілю буде відправлено вашим контактам. + Усі ваші контакти залишаться підключеними. Оновлення профілю буде відправлено вашим контактам. Відповісти на виклик Адреса Додати профіль @@ -717,7 +717,7 @@ Зникає о: %s (поточне) Вилучити учасника - Роль буде змінено на "%s". Всі учасники групи будуть сповіщені. + Роль буде змінено на %s. Усі учасники групи будуть сповіщені. Роль буде змінено на "%s". Учасник отримає нове запрошення. Група Привітальне повідомлення @@ -1428,7 +1428,7 @@ Ви вже подали запит на підключення за цією адресою! надіслати приватне повідомлення Показувати консоль в новому вікні - Всі нові повідомлення від %s будуть приховані! + Усі нові повідомлення від %s будуть приховані! підключив(лась) безпосередньо заблоковано Блокувати учасників групи @@ -1674,7 +1674,7 @@ Перевірте підключення до Інтернету та спробуйте ще раз Переконайтеся, що ви пам\'ятаєте пароль до бази даних для її перенесення. Помилка при перевірці парольної фрази: - Всі ваші контакти, розмови та файли будуть надійно зашифровані та завантажені частинами на налаштовані XFTP-реле. + Усі ваші контакти, розмови та файли будуть надійно зашифровані та завантажені частинами на налаштовані XFTP-реле. Please note: використання однієї і тієї ж бази даних на двох пристроях порушить розшифровку повідомлень з ваших з\'єднань, як захист безпеки.]]> Скасувати міграцію Чат перемістився! @@ -2025,7 +2025,7 @@ Проксірований Надіслати помилки Завершено - Всі профілі + Усі профілі Скинути Вивантажено Видалити %d повідомлень учасників? @@ -2384,4 +2384,8 @@ Коротке посилання Посилання на канал SimpleX Несумісне посилання для підключення + Усі сервери + Ні + Типові сервери + Використовуйте TCP порт 443 лише для попередньо налаштованих серверів. diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/vi/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/vi/strings.xml index 99931215e7..3cbc54f652 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/vi/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/vi/strings.xml @@ -1263,7 +1263,7 @@ Đang chờ xử lý Đang chờ xử lý Không tìm thấy mật khẩu trong Keystore, vui lòng nhập thủ công. Điều này có thể xảy ra nếu bạn khôi phục dữ liệu ứng dụng bằng một công cụ sao lưu. Nếu không phải như vậy, xin vui lòng liên hệ với nhà phát triển. - Thành viên cũ %1$s + Thành viên trước đây %1$s Dán đường dẫn để kết nối! Thông báo định kỳ Dán đường dẫn mà bạn nhận được @@ -2358,4 +2358,8 @@ Sử dụng đường dẫn ngắn (BETA) Toàn bộ đường dẫn Đường dẫn ngắn + Tắt + Các máy chủ cài sẵn + Chỉ sử dụng cổng TCP 443 cho các máy chủ cài sẵn. + Tất cả máy chủ diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml index 1958885843..28a5f6f50d 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml @@ -1059,7 +1059,7 @@ 当你或你的连接使用旧数据库备份时,可能会发生这种情况。 解密错误 请向开发者报告。 - 上一条消息的散列不同。\" + 上条消息的哈希值不同。 下一条消息的 ID 不正确(小于或等于上一条)。 \n它可能是由于某些错误或连接被破坏才发生。 停止文件 @@ -1068,10 +1068,10 @@ 停止接收文件? 即将停止接收文件。 停止 - 撤销文件 - 撤销文件? + 吊销文件 + 吊销文件? 文件将从服务器中删除。 - 撤销 + 吊销 音频/视频通话 " \n在 v5.1 版本中可用" @@ -1330,7 +1330,7 @@ 更改密码或重启应用后,密码将以明文形式保存在设置中。 粘贴你收到的链接以与你的联系人联系… 送达回执 - 没有选择聊天 + 没有选中的聊天 可以加密 重新协商加密 禁用(保留组覆盖) @@ -2061,7 +2061,7 @@ 用户名 分享配置文件 转发消息出错 - 在你选中消息后这些消息被删除。 + 在你选中消息后这些消息已被删除。 %1$d 个文件错误:\n%2$s 其他 %1$d 个文件错误。 %1$d 个文件未被下载。 @@ -2070,29 +2070,29 @@ 没什么可转发的! 仍有 %1$d 个文件在下载中。 %1$d 个文件下载失败。 - %1$d 个文件被删除了。 + 删除了 %1$d 个文件。 下载 %1$s 条消息未被转发 转发消息… 转发 %1$s 条消息 保存 %1$s 条消息 已静音 - 管理形状 + 消息形状 拐角 尾部 初始化 WebView 出错。确保你安装了 WebView 且其支持的架构为 arm64。\n错误:%s 应用会话 - 每次启动应用都会使用新的 SOCKS5 凭据。 + 每次启动应用都会使用新的 SOCKS 凭据。 服务器 打开 Safari 设置/网站/麦克风,接着在 localhost 选择“允许”。 要进行通话,请允许使用设备麦克风。结束通话并尝试再次呼叫。 单击地址栏附近的“信息”按钮允许使用麦克风。 - 每个服务器都会使用新的 SOCKS5 凭据。 + 每个服务器都会使用新的 SOCKS 凭据。 更好的消息日期。 更佳的安全性✅ 更佳的使用体验 可自定义消息形状。 - 一次性转发最多20条消息。 + 一次转发最多20条消息。 Trail of Bits 审核了 SimpleX 协议。 通话期间切换音频和视频。 对一次性邀请切换聊天配置文件。 @@ -2160,11 +2160,11 @@ 应用通过在每个对话中使用不同运营方保护你的隐私。 接受条款 模糊 - 地址或一次性链接? + 地址还是一次性链接? 已添加消息服务器 已添加媒体和文件服务器 地址设置 - 已接受条款 + 已接受的条款 应用工具栏 仅用于一名联系人 - 面对面或通过任何消息应用分享.]]> %s.]]> @@ -2192,7 +2192,7 @@ 你可以在“网络和服务器”设置中配置运营方。 接受运营方条款的日期:%s 远程移动设备 - 或者导入压缩文件 + 或者导入存档文件 小米设备:请在系统设置中开启“自动启动”让通知正常工作。]]> 消息太大! 你可以复制并减小消息大小来发送它。 @@ -2282,8 +2282,8 @@ 另一个理由 已存档的举报 违反社区指导方针 - 不恰当的内容 - 不恰当的个人资料 + 不当内容 + 不当个人资料 仅发送人和moderators能看到 只有你和moderators能看到 垃圾信息 @@ -2337,7 +2337,7 @@ 更好的隐私和安全 不错过重要消息。 更快地删除群。 - 更快死发送消息。 + 更快发送消息。 被提及时收到通知。 帮助管理员管理群组。 将聊天组织到列表 @@ -2371,4 +2371,8 @@ 短链接 此链接需要更新的应用版本。请升级应用或请求你的联系人发送相容的链接。 完整链接 + 全部服务器 + 关闭 + 预设服务器 + 仅预设服务器使用 TCP 协议 443 端口。 diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml index 3038dd3d6c..8ae414de00 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml @@ -1495,7 +1495,7 @@ %s 的版本。請檢察兩台裝置安裝的是否版本相同]]> 更可靠的網路連接 發現和加入群組 - 裝置 + 設備 新行動裝置 保存設定出錯 導出的檔案不存在 @@ -1628,7 +1628,7 @@ 找到桌面 自動連接 與PC版的連接不穩定 - 桌面 + 桌上電腦 已安裝的PC版本不支援。請確認兩台裝置所安裝的版本相同 PC版邀請碼錯誤 通過連結連接? diff --git a/apps/simplex-directory-service/src/Directory/Events.hs b/apps/simplex-directory-service/src/Directory/Events.hs index 37d2b63d2f..faaccbd2bf 100644 --- a/apps/simplex-directory-service/src/Directory/Events.hs +++ b/apps/simplex-directory-service/src/Directory/Events.hs @@ -16,7 +16,6 @@ module Directory.Events SDirectoryRole (..), crDirectoryEvent, directoryCmdTag, - viewName, ) where @@ -291,9 +290,6 @@ directoryCmdP = -- wordP = spacesP *> A.takeTill isSpace spacesP = A.takeWhile1 isSpace -viewName :: Text -> Text -viewName n = if T.any isSpace n then "'" <> n <> "'" else n - directoryCmdTag :: DirectoryCmd r -> Text directoryCmdTag = \case DCHelp _ -> "help" diff --git a/apps/simplex-directory-service/src/Directory/Service.hs b/apps/simplex-directory-service/src/Directory/Service.hs index 4b02e0b294..4517ee9c5b 100644 --- a/apps/simplex-directory-service/src/Directory/Service.hs +++ b/apps/simplex-directory-service/src/Directory/Service.hs @@ -48,7 +48,7 @@ import Simplex.Chat.Bot import Simplex.Chat.Bot.KnownContacts import Simplex.Chat.Controller import Simplex.Chat.Core -import Simplex.Chat.Markdown (FormattedText (..), Format (..), parseMaybeMarkdownList) +import Simplex.Chat.Markdown (FormattedText (..), Format (..), parseMaybeMarkdownList, viewName) import Simplex.Chat.Messages import Simplex.Chat.Options import Simplex.Chat.Protocol (MsgContent (..)) diff --git a/docs/dependencies/README.md b/docs/dependencies/README.md index 02c0623988..bec369c126 100644 --- a/docs/dependencies/README.md +++ b/docs/dependencies/README.md @@ -1,9 +1,9 @@ # SimpleX Chat and SimpleX servers dependencies -[SQLCipher](https://github.com/sqlcipher/sqlcipher): Extension of [SQLite](https://sqlite.org) with encryption ([BSD-style](./licences/build/sqlcipher/LICENSE.md)) +[SQLCipher](https://github.com/sqlcipher/sqlcipher): Extension of [SQLite](https://sqlite.org) with encryption ([BSD-style](./licences/apps/sqlcipher/LICENSE.md)) -[vlc](https://github.com/videolan/vlc): VLC media player library ([LGPLv2](./licences/build/vlc/COPYING.LIB)) +[vlc](https://github.com/videolan/vlc): VLC media player library ([LGPLv2](./licences/apps/vlc/COPYING.LIB)) -[WebRTC](https://webrtc.googlesource.com/src/): RTC for calls ([BSD-3-clause](./licences/build/webrtc/LICENSE)) +[WebRTC](https://webrtc.googlesource.com/src/): RTC for calls ([BSD-3-clause](./licences/apps/webrtc/LICENSE)) [Haskell dependencies](./HASKELL.md). diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 52e40d6c6f..a9dca273e3 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: simplex-chat -version: 6.3.4.0 +version: 6.3.4.1 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat @@ -104,6 +104,7 @@ library Simplex.Chat.Store.Postgres.Migrations Simplex.Chat.Store.Postgres.Migrations.M20241220_initial Simplex.Chat.Store.Postgres.Migrations.M20250402_short_links + Simplex.Chat.Store.Postgres.Migrations.M20250512_member_admission else exposed-modules: Simplex.Chat.Archive @@ -234,6 +235,7 @@ library Simplex.Chat.Store.SQLite.Migrations.M20250129_delete_unused_contacts Simplex.Chat.Store.SQLite.Migrations.M20250130_indexes Simplex.Chat.Store.SQLite.Migrations.M20250402_short_links + Simplex.Chat.Store.SQLite.Migrations.M20250512_member_admission other-modules: Paths_simplex_chat hs-source-dirs: diff --git a/src/Simplex/Chat/AppSettings.hs b/src/Simplex/Chat/AppSettings.hs index 23b5f2ddad..1efa69fad4 100644 --- a/src/Simplex/Chat/AppSettings.hs +++ b/src/Simplex/Chat/AppSettings.hs @@ -25,8 +25,6 @@ data NotificationPreviewMode = NPMHidden | NPMContact | NPMMessage deriving (Sho data LockScreenCalls = LSCDisable | LSCShow | LSCAccept deriving (Show) -data OpenLinksSetting = OLSYes | OLSNo | OLSAsk deriving (Show) - data AppSettings = AppSettings { appPlatform :: Maybe AppPlatform, networkConfig :: Maybe NetworkConfig, @@ -35,7 +33,6 @@ data AppSettings = AppSettings privacyAskToApproveRelays :: Maybe Bool, privacyAcceptImages :: Maybe Bool, privacyLinkPreviews :: Maybe Bool, - privacyChatListOpenLinks :: Maybe OpenLinksSetting, privacyShowChatPreviews :: Maybe Bool, privacySaveLastDraft :: Maybe Bool, privacyProtectScreen :: Maybe Bool, @@ -86,7 +83,6 @@ defaultAppSettings = privacyAskToApproveRelays = Just True, privacyAcceptImages = Just True, privacyLinkPreviews = Just True, - privacyChatListOpenLinks = Just OLSAsk, privacyShowChatPreviews = Just True, privacySaveLastDraft = Just True, privacyProtectScreen = Just False, @@ -124,7 +120,6 @@ defaultParseAppSettings = privacyAskToApproveRelays = Nothing, privacyAcceptImages = Nothing, privacyLinkPreviews = Nothing, - privacyChatListOpenLinks = Nothing, privacyShowChatPreviews = Nothing, privacySaveLastDraft = Nothing, privacyProtectScreen = Nothing, @@ -162,7 +157,6 @@ combineAppSettings platformDefaults storedSettings = privacyAskToApproveRelays = p privacyAskToApproveRelays, privacyAcceptImages = p privacyAcceptImages, privacyLinkPreviews = p privacyLinkPreviews, - privacyChatListOpenLinks = p privacyChatListOpenLinks, privacyShowChatPreviews = p privacyShowChatPreviews, privacySaveLastDraft = p privacySaveLastDraft, privacyProtectScreen = p privacyProtectScreen, @@ -203,8 +197,6 @@ $(JQ.deriveJSON (enumJSON $ dropPrefix "LSC") ''LockScreenCalls) $(JQ.deriveJSON (enumJSON $ dropPrefix "NPA") ''NetworkProxyAuth) -$(JQ.deriveJSON (enumJSON $ dropPrefix "OLS") ''OpenLinksSetting) - $(JQ.deriveJSON defaultJSON ''NetworkProxy) $(JQ.deriveToJSON defaultJSON ''AppSettings) @@ -218,7 +210,6 @@ instance FromJSON AppSettings where privacyAskToApproveRelays <- p "privacyAskToApproveRelays" privacyAcceptImages <- p "privacyAcceptImages" privacyLinkPreviews <- p "privacyLinkPreviews" - privacyChatListOpenLinks <- p "privacyChatListOpenLinks" privacyShowChatPreviews <- p "privacyShowChatPreviews" privacySaveLastDraft <- p "privacySaveLastDraft" privacyProtectScreen <- p "privacyProtectScreen" @@ -253,7 +244,6 @@ instance FromJSON AppSettings where privacyAskToApproveRelays, privacyAcceptImages, privacyLinkPreviews, - privacyChatListOpenLinks, privacyShowChatPreviews, privacySaveLastDraft, privacyProtectScreen, diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index f21c9526a5..d3b945af4f 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -4290,7 +4290,7 @@ chatCommandP = { directMessages = Just DirectMessagesGroupPreference {enable = FEOn, role = Nothing}, history = Just HistoryGroupPreference {enable = FEOn} } - pure GroupProfile {displayName = gName, fullName, description = Nothing, image = Nothing, groupPreferences} + pure GroupProfile {displayName = gName, fullName, description = Nothing, image = Nothing, groupPreferences, memberAdmission = Nothing} fullNameP = A.space *> textP <|> pure "" textP = safeDecodeUtf8 <$> A.takeByteString pwdP = jsonP <|> (UserPwd . safeDecodeUtf8 <$> A.takeTill (== ' ')) diff --git a/src/Simplex/Chat/Library/Internal.hs b/src/Simplex/Chat/Library/Internal.hs index 8158df5c94..bbefbcfde0 100644 --- a/src/Simplex/Chat/Library/Internal.hs +++ b/src/Simplex/Chat/Library/Internal.hs @@ -972,7 +972,7 @@ acceptBusinessJoinRequestAsync where businessGroupProfile :: Profile -> GroupPreferences -> GroupProfile businessGroupProfile Profile {displayName, fullName, image} groupPreferences = - GroupProfile {displayName, fullName, description = Nothing, image, groupPreferences = Just groupPreferences} + GroupProfile {displayName, fullName, description = Nothing, image, groupPreferences = Just groupPreferences, memberAdmission = Nothing} profileToSendOnAccept :: User -> Maybe IncognitoProfile -> Bool -> Profile profileToSendOnAccept user ip = userProfileToSend user (getIncognitoProfile <$> ip) Nothing diff --git a/src/Simplex/Chat/Markdown.hs b/src/Simplex/Chat/Markdown.hs index e5de9c408c..9811556fe0 100644 --- a/src/Simplex/Chat/Markdown.hs +++ b/src/Simplex/Chat/Markdown.hs @@ -4,6 +4,7 @@ {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TupleSections #-} {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} {-# HLINT ignore "Use newtype instead of data" #-} @@ -16,7 +17,7 @@ import qualified Data.Aeson as J import qualified Data.Aeson.TH as JQ import Data.Attoparsec.Text (Parser) import qualified Data.Attoparsec.Text as A -import Data.Char (isDigit, isPunctuation, isSpace) +import Data.Char (isAlpha, isAscii, isDigit, isPunctuation, isSpace) import Data.Either (fromRight) import Data.Functor (($>)) import Data.List (foldl', intercalate) @@ -204,17 +205,18 @@ markdownP = mconcat <$> A.many' fragmentP else pure $ markdown (colored clr) s mentionP = do c <- A.char '@' *> A.peekChar' - name <- displayNameTextP + (name, punct) <- displayNameTextP_ let sName = if c == '\'' then '\'' `T.cons` name `T.snoc` '\'' else name - pure $ markdown (Mention name) ('@' `T.cons` sName) + mention = markdown (Mention name) ('@' `T.cons` sName) + pure $ if T.null punct then mention else mention :|: unmarked punct colorP = A.anyChar >>= \case - 'r' -> "ed" $> Red <|> pure Red - 'g' -> "reen" $> Green <|> pure Green - 'b' -> "lue" $> Blue <|> pure Blue - 'y' -> "ellow" $> Yellow <|> pure Yellow - 'c' -> "yan" $> Cyan <|> pure Cyan - 'm' -> "agenta" $> Magenta <|> pure Magenta + 'r' -> optional "ed" $> Red + 'g' -> optional "reen" $> Green + 'b' -> optional "lue" $> Blue + 'y' -> optional "ellow" $> Yellow + 'c' -> optional "yan" $> Cyan + 'm' -> optional "agenta" $> Magenta '1' -> pure Red '2' -> pure Green '3' -> pure Blue @@ -236,12 +238,14 @@ markdownP = mconcat <$> A.many' fragmentP wordMD :: Text -> Markdown wordMD s | T.null s = unmarked s - | isUri s = - let t = T.takeWhileEnd isPunctuation' s - uri = uriMarkdown $ T.dropWhileEnd isPunctuation' s - in if T.null t then uri else uri :|: unmarked t - | isEmail s = markdown Email s + | isUri s' = res $ uriMarkdown s' + | isDomain s' = res $ markdown Uri s' + | isEmail s' = res $ markdown Email s' | otherwise = unmarked s + where + punct = T.takeWhileEnd isPunctuation' s + s' = T.dropWhileEnd isPunctuation' s + res md' = if T.null punct then md' else md' :|: unmarked punct isPunctuation' = \case '/' -> False ')' -> False @@ -250,6 +254,16 @@ markdownP = mconcat <$> A.many' fragmentP Right cLink -> markdown (simplexUriFormat cLink) s _ -> markdown Uri s isUri s = T.length s >= 10 && any (`T.isPrefixOf` s) ["http://", "https://", "simplex:/"] + -- matches what is likely to be a domain, not all valid domain names + isDomain s = case T.splitOn "." s of + [name, tld] -> isDomain_ name tld + [sub, name, tld] -> T.length sub >= 3 && T.length sub <= 8 && isDomain_ name tld + _ -> False + where + isDomain_ name tld = + (let n = T.length name in n >= 1 && n <= 24) + && (let n = T.length tld in n >= 2 && n <= 8) + && (let p c = isAscii c && isAlpha c in T.all p name && T.all p tld) isEmail s = T.any (== '@') s && Email.isValid (encodeUtf8 s) noFormat = pure . unmarked simplexUriFormat :: AConnectionLink -> Format @@ -307,16 +321,22 @@ markdownText (FormattedText f_ t) = case f_ of White -> Nothing displayNameTextP :: Parser Text -displayNameTextP = quoted '\'' <|> takeNameTill (== ' ') +displayNameTextP = displayNameTextP_ >>= \(t, sfx) -> if T.null sfx then pure t else fail "Name ends with punctuation" +{-# INLINE displayNameTextP #-} + +displayNameTextP_ :: Parser (Text, Text) +displayNameTextP_ = (,"") <$> quoted '\'' <|> splitPunctuation <$> takeNameTill isSpace where takeNameTill p = A.peekChar' >>= \c -> if refChar c then A.takeTill p else fail "invalid first character in display name" + splitPunctuation s = (T.dropWhileEnd isPunctuation s, T.takeWhileEnd isPunctuation s) quoted c = A.char c *> takeNameTill (== c) <* A.char c refChar c = c > ' ' && c /= '#' && c /= '@' && c /= '\'' +-- quotes names that contain spaces or end on punctuation viewName :: Text -> Text -viewName s = if T.any isSpace s then "'" <> s <> "'" else s +viewName s = if T.any isSpace s || maybe False (isPunctuation . snd) (T.unsnoc s) then "'" <> s <> "'" else s $(JQ.deriveJSON (enumJSON $ dropPrefix "XL") ''SimplexLinkType) diff --git a/src/Simplex/Chat/Remote.hs b/src/Simplex/Chat/Remote.hs index 021f048d6b..d41957bbac 100644 --- a/src/Simplex/Chat/Remote.hs +++ b/src/Simplex/Chat/Remote.hs @@ -75,11 +75,11 @@ remoteFilesFolder = "simplex_v1_files" -- when acting as host minRemoteCtrlVersion :: AppVersion -minRemoteCtrlVersion = AppVersion [6, 3, 4, 0] +minRemoteCtrlVersion = AppVersion [6, 3, 4, 1] -- when acting as controller minRemoteHostVersion :: AppVersion -minRemoteHostVersion = AppVersion [6, 3, 4, 0] +minRemoteHostVersion = AppVersion [6, 3, 4, 1] currentAppVersion :: AppVersion currentAppVersion = AppVersion SC.version diff --git a/src/Simplex/Chat/Store/Connections.hs b/src/Simplex/Chat/Store/Connections.hs index 0a4f5392c0..5c177969b9 100644 --- a/src/Simplex/Chat/Store/Connections.hs +++ b/src/Simplex/Chat/Store/Connections.hs @@ -136,7 +136,7 @@ getConnectionEntity db vr user@User {userId, userContactId} agentConnId = do SELECT -- GroupInfo g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, -- GroupInfo {membership} mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index 0c49338a2e..fc23c9ef44 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -277,7 +277,7 @@ getGroupAndMember db User {userId, userContactId} groupMemberId vr = do SELECT -- GroupInfo g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, -- GroupInfo {membership} mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, @@ -318,7 +318,7 @@ getGroupAndMember db User {userId, userContactId} groupMemberId vr = do -- | creates completely new group with a single member - the current user createNewGroup :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupProfile -> Maybe Profile -> ExceptT StoreError IO GroupInfo createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = ExceptT $ do - let GroupProfile {displayName, fullName, description, image, groupPreferences} = groupProfile + let GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission} = groupProfile fullGroupPreferences = mergeGroupPreferences groupPreferences currentTs <- getCurrentTime customUserProfileId <- mapM (createIncognitoProfile_ db userId currentTs) incognitoProfile @@ -326,8 +326,8 @@ createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = Exc groupId <- liftIO $ do DB.execute db - "INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)" - (displayName, fullName, description, image, userId, groupPreferences, currentTs, currentTs) + "INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)" + (displayName, fullName, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs) profileId <- insertedRowId db DB.execute db @@ -387,7 +387,7 @@ createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activ DB.query db "SELECT group_id FROM groups WHERE inv_queue_info = ? AND user_id = ? LIMIT 1" (connRequest, userId) createGroupInvitation_ :: ExceptT StoreError IO (GroupInfo, GroupMemberId) createGroupInvitation_ = do - let GroupProfile {displayName, fullName, description, image, groupPreferences} = groupProfile + let GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission} = groupProfile fullGroupPreferences = mergeGroupPreferences groupPreferences ExceptT $ withLocalDisplayName db userId displayName $ \localDisplayName -> runExceptT $ do @@ -395,8 +395,8 @@ createGroupInvitation db vr user@User {userId} contact@Contact {contactId, activ groupId <- liftIO $ do DB.execute db - "INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)" - (displayName, fullName, description, image, userId, groupPreferences, currentTs, currentTs) + "INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)" + (displayName, fullName, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs) profileId <- insertedRowId db DB.execute db @@ -554,13 +554,13 @@ createGroupViaLink' (,) <$> getGroupInfo db vr user groupId <*> getGroupMemberById db vr user hostMemberId where insertGroup_ currentTs = ExceptT $ do - let GroupProfile {displayName, fullName, description, image, groupPreferences} = groupProfile + let GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission} = groupProfile withLocalDisplayName db userId displayName $ \localDisplayName -> runExceptT $ do liftIO $ do DB.execute db - "INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)" - (displayName, fullName, description, image, userId, groupPreferences, currentTs, currentTs) + "INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)" + (displayName, fullName, description, image, userId, groupPreferences, memberAdmission, currentTs, currentTs) profileId <- insertedRowId db DB.execute db @@ -763,7 +763,7 @@ getUserGroupDetails db vr User {userId, userContactId} _contactId_ search_ = do [sql| SELECT g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, mu.group_member_id, g.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id, pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences, @@ -1544,7 +1544,7 @@ getViaGroupMember db vr User {userId, userContactId} Contact {contactId} = do SELECT -- GroupInfo g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, -- GroupInfo {membership} mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, @@ -1601,7 +1601,7 @@ getViaGroupContact db vr user@User {userId} GroupMember {groupMemberId} = do maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getContact db vr user) contactId_ updateGroupProfile :: DB.Connection -> User -> GroupInfo -> GroupProfile -> ExceptT StoreError IO GroupInfo -updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, description, image, groupPreferences} +updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, description, image, groupPreferences, memberAdmission} | displayName == newName = liftIO $ do currentTs <- getCurrentTime updateGroupProfile_ currentTs @@ -1619,14 +1619,14 @@ updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, db [sql| UPDATE group_profiles - SET display_name = ?, full_name = ?, description = ?, image = ?, preferences = ?, updated_at = ? + SET display_name = ?, full_name = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ? WHERE group_profile_id IN ( SELECT group_profile_id FROM groups WHERE user_id = ? AND group_id = ? ) |] - (newName, fullName, description, image, groupPreferences, currentTs, userId, groupId) + (newName, fullName, description, image, groupPreferences, memberAdmission, currentTs, userId, groupId) updateGroup_ ldn currentTs = do DB.execute db @@ -1664,14 +1664,14 @@ updateGroupProfileFromMember db user g@GroupInfo {groupId} Profile {displayName DB.query db [sql| - SELECT gp.display_name, gp.full_name, gp.description, gp.image, gp.preferences + SELECT gp.display_name, gp.full_name, gp.description, gp.image, gp.preferences, gp.member_admission FROM group_profiles gp JOIN groups g ON gp.group_profile_id = g.group_profile_id WHERE g.group_id = ? |] (Only groupId) - toGroupProfile (displayName, fullName, description, image, groupPreferences) = - GroupProfile {displayName, fullName, description, image, groupPreferences} + toGroupProfile (displayName, fullName, description, image, groupPreferences, memberAdmission) = + GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission} getGroupInfo :: DB.Connection -> VersionRangeChat -> User -> Int64 -> ExceptT StoreError IO GroupInfo getGroupInfo db vr User {userId, userContactId} groupId = ExceptT $ do diff --git a/src/Simplex/Chat/Store/Postgres/Migrations.hs b/src/Simplex/Chat/Store/Postgres/Migrations.hs index dc7202edc8..c392c17db1 100644 --- a/src/Simplex/Chat/Store/Postgres/Migrations.hs +++ b/src/Simplex/Chat/Store/Postgres/Migrations.hs @@ -6,12 +6,14 @@ import Data.List (sortOn) import Data.Text (Text) import Simplex.Chat.Store.Postgres.Migrations.M20241220_initial import Simplex.Chat.Store.Postgres.Migrations.M20250402_short_links +import Simplex.Chat.Store.Postgres.Migrations.M20250512_member_admission import Simplex.Messaging.Agent.Store.Shared (Migration (..)) schemaMigrations :: [(String, Text, Maybe Text)] schemaMigrations = [ ("20241220_initial", m20241220_initial, Nothing), - ("20250402_short_links", m20250402_short_links, Just down_m20250402_short_links) + ("20250402_short_links", m20250402_short_links, Just down_m20250402_short_links), + ("20250512_member_admission", m20250512_member_admission, Just down_m20250512_member_admission) ] -- | The list of migrations in ascending order by date diff --git a/src/Simplex/Chat/Store/Postgres/Migrations/M20250402_short_links.hs b/src/Simplex/Chat/Store/Postgres/Migrations/M20250402_short_links.hs index de4f699377..4b3b7e9640 100644 --- a/src/Simplex/Chat/Store/Postgres/Migrations/M20250402_short_links.hs +++ b/src/Simplex/Chat/Store/Postgres/Migrations/M20250402_short_links.hs @@ -12,6 +12,7 @@ m20250402_short_links = [r| ALTER TABLE user_contact_links ADD COLUMN short_link_contact BYTEA; ALTER TABLE connections ADD COLUMN short_link_inv BYTEA; +ALTER TABLE connections ADD COLUMN via_short_link_contact BYTEA; |] down_m20250402_short_links :: Text @@ -20,4 +21,5 @@ down_m20250402_short_links = [r| ALTER TABLE user_contact_links DROP COLUMN short_link_contact; ALTER TABLE connections DROP COLUMN short_link_inv; +ALTER TABLE connections DROP COLUMN via_short_link_contact; |] diff --git a/src/Simplex/Chat/Store/Postgres/Migrations/M20250512_member_admission.hs b/src/Simplex/Chat/Store/Postgres/Migrations/M20250512_member_admission.hs new file mode 100644 index 0000000000..eb0d73a523 --- /dev/null +++ b/src/Simplex/Chat/Store/Postgres/Migrations/M20250512_member_admission.hs @@ -0,0 +1,21 @@ +{-# LANGUAGE QuasiQuotes #-} + +module Simplex.Chat.Store.Postgres.Migrations.M20250512_member_admission where + +import Data.Text (Text) +import qualified Data.Text as T +import Text.RawString.QQ (r) + +m20250512_member_admission :: Text +m20250512_member_admission = + T.pack + [r| +ALTER TABLE group_profiles ADD COLUMN member_admission TEXT; +|] + +down_m20250512_member_admission :: Text +down_m20250512_member_admission = + T.pack + [r| +ALTER TABLE group_profiles DROP COLUMN member_admission; +|] diff --git a/src/Simplex/Chat/Store/SQLite/Migrations.hs b/src/Simplex/Chat/Store/SQLite/Migrations.hs index 81253c5b87..183d699f01 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations.hs +++ b/src/Simplex/Chat/Store/SQLite/Migrations.hs @@ -129,6 +129,7 @@ import Simplex.Chat.Store.SQLite.Migrations.M20250126_mentions import Simplex.Chat.Store.SQLite.Migrations.M20250129_delete_unused_contacts import Simplex.Chat.Store.SQLite.Migrations.M20250130_indexes import Simplex.Chat.Store.SQLite.Migrations.M20250402_short_links +import Simplex.Chat.Store.SQLite.Migrations.M20250512_member_admission import Simplex.Messaging.Agent.Store.Shared (Migration (..)) schemaMigrations :: [(String, Query, Maybe Query)] @@ -257,7 +258,8 @@ schemaMigrations = ("20250126_mentions", m20250126_mentions, Just down_m20250126_mentions), ("20250129_delete_unused_contacts", m20250129_delete_unused_contacts, Just down_m20250129_delete_unused_contacts), ("20250130_indexes", m20250130_indexes, Just down_m20250130_indexes), - ("20250402_short_links", m20250402_short_links, Just down_m20250402_short_links) + ("20250402_short_links", m20250402_short_links, Just down_m20250402_short_links), + ("20250512_member_admission", m20250512_member_admission, Just down_m20250512_member_admission) ] -- | The list of migrations in ascending order by date diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/M20250512_member_admission.hs b/src/Simplex/Chat/Store/SQLite/Migrations/M20250512_member_admission.hs new file mode 100644 index 0000000000..e1f45beef1 --- /dev/null +++ b/src/Simplex/Chat/Store/SQLite/Migrations/M20250512_member_admission.hs @@ -0,0 +1,18 @@ +{-# LANGUAGE QuasiQuotes #-} + +module Simplex.Chat.Store.SQLite.Migrations.M20250512_member_admission where + +import Database.SQLite.Simple (Query) +import Database.SQLite.Simple.QQ (sql) + +m20250512_member_admission :: Query +m20250512_member_admission = + [sql| +ALTER TABLE group_profiles ADD COLUMN member_admission TEXT; +|] + +down_m20250512_member_admission :: Query +down_m20250512_member_admission = + [sql| +ALTER TABLE group_profiles DROP COLUMN member_admission; +|] diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt index a10d3f3db7..13215dcb75 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt @@ -1119,7 +1119,7 @@ Query: UPDATE rcv_messages SET user_ack = ? WHERE conn_id = ? AND internal_id = Plan: SEARCH rcv_messages USING COVERING INDEX idx_rcv_messages_conn_id_internal_id (conn_id=? AND internal_id=?) -Query: UPDATE rcv_queues SET last_broker_ts = ? WHERE conn_id = ? AND rcv_queue_id = ? AND last_broker_ts < ? +Query: UPDATE rcv_queues SET last_broker_ts = ? WHERE conn_id = ? AND rcv_queue_id = ? AND (last_broker_ts IS NULL OR last_broker_ts < ?) Plan: SEARCH rcv_queues USING INDEX idx_rcv_queue_id (conn_id=? AND rcv_queue_id=?) diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt index e3eff0f6f1..88c6c33b41 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt @@ -35,7 +35,7 @@ Query: SELECT -- GroupInfo g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, -- GroupInfo {membership} mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, @@ -544,7 +544,7 @@ SEARCH m USING INTEGER PRIMARY KEY (rowid=?) SEARCH ct USING INTEGER PRIMARY KEY (rowid=?) Query: - SELECT gp.display_name, gp.full_name, gp.description, gp.image, gp.preferences + SELECT gp.display_name, gp.full_name, gp.description, gp.image, gp.preferences, gp.member_admission FROM group_profiles gp JOIN groups g ON gp.group_profile_id = g.group_profile_id WHERE g.group_id = ? @@ -805,7 +805,7 @@ Query: SELECT -- GroupInfo g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, -- GroupInfo {membership} mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, @@ -850,7 +850,7 @@ SEARCH cc USING COVERING INDEX idx_connections_group_member (user_id=? AND group Query: SELECT g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, mu.group_member_id, g.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, mu.member_status, mu.show_messages, mu.member_restriction, mu.invited_by, mu.invited_by_group_member_id, mu.local_display_name, mu.contact_id, mu.contact_profile_id, pu.contact_profile_id, pu.display_name, pu.full_name, pu.image, pu.contact_link, pu.local_alias, pu.preferences, @@ -1235,7 +1235,7 @@ SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?) Query: UPDATE group_profiles - SET display_name = ?, full_name = ?, description = ?, image = ?, preferences = ?, updated_at = ? + SET display_name = ?, full_name = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ? WHERE group_profile_id IN ( SELECT group_profile_id FROM groups @@ -4458,7 +4458,7 @@ Query: SELECT -- GroupInfo g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, -- GroupMember - membership mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, @@ -4480,7 +4480,7 @@ Query: SELECT -- GroupInfo g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, -- GroupMember - membership mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, @@ -5387,7 +5387,7 @@ Plan: Query: INSERT INTO files (user_id, group_id, file_name, file_size, chunk_size, file_inline, ci_file_status, protocol, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?) Plan: -Query: INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?) +Query: INSERT INTO group_profiles (display_name, full_name, description, image, user_id, preferences, member_admission, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?) Plan: Query: INSERT INTO group_profiles (display_name, full_name, image, user_id, preferences, created_at, updated_at) VALUES (?,?,?,?,?,?,?) diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql b/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql index 33b800f4ef..6fbed97d27 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql @@ -108,7 +108,8 @@ CREATE TABLE group_profiles( image TEXT, user_id INTEGER DEFAULT NULL REFERENCES users ON DELETE CASCADE, preferences TEXT, - description TEXT NULL + description TEXT NULL, + member_admission TEXT ); CREATE TABLE groups( group_id INTEGER PRIMARY KEY, -- local group ID diff --git a/src/Simplex/Chat/Store/Shared.hs b/src/Simplex/Chat/Store/Shared.hs index c681180759..b32fd07bb5 100644 --- a/src/Simplex/Chat/Store/Shared.hs +++ b/src/Simplex/Chat/Store/Shared.hs @@ -579,16 +579,16 @@ safeDeleteLDN db User {userId} localDisplayName = do type BusinessChatInfoRow = (Maybe BusinessChatType, Maybe MemberId, Maybe MemberId) -type GroupInfoRow = (Int64, GroupName, GroupName, Text, Text, Maybe Text, Maybe ImageData, Maybe MsgFilter, Maybe BoolInt, BoolInt, Maybe GroupPreferences) :. (UTCTime, UTCTime, Maybe UTCTime, Maybe UTCTime) :. BusinessChatInfoRow :. (Maybe UIThemeEntityOverrides, Maybe CustomData, Maybe Int64) :. GroupMemberRow +type GroupInfoRow = (Int64, GroupName, GroupName, Text, Text, Maybe Text, Maybe ImageData, Maybe MsgFilter, Maybe BoolInt, BoolInt, Maybe GroupPreferences, Maybe GroupMemberAdmission) :. (UTCTime, UTCTime, Maybe UTCTime, Maybe UTCTime) :. BusinessChatInfoRow :. (Maybe UIThemeEntityOverrides, Maybe CustomData, Maybe Int64) :. GroupMemberRow type GroupMemberRow = (Int64, Int64, MemberId, VersionChat, VersionChat, GroupMemberRole, GroupMemberCategory, GroupMemberStatus, BoolInt, Maybe MemberRestrictionStatus) :. (Maybe Int64, Maybe GroupMemberId, ContactName, Maybe ContactId, ProfileId, ProfileId, ContactName, Text, Maybe ImageData, Maybe ConnLinkContact, LocalAlias, Maybe Preferences) :. (UTCTime, UTCTime) toGroupInfo :: VersionRangeChat -> Int64 -> [ChatTagId] -> GroupInfoRow -> GroupInfo -toGroupInfo vr userContactId chatTags ((groupId, localDisplayName, displayName, fullName, localAlias, description, image, enableNtfs_, sendRcpts, BI favorite, groupPreferences) :. (createdAt, updatedAt, chatTs, userMemberProfileSentAt) :. businessRow :. (uiThemes, customData, chatItemTTL) :. userMemberRow) = +toGroupInfo vr userContactId chatTags ((groupId, localDisplayName, displayName, fullName, localAlias, description, image, enableNtfs_, sendRcpts, BI favorite, groupPreferences, memberAdmission) :. (createdAt, updatedAt, chatTs, userMemberProfileSentAt) :. businessRow :. (uiThemes, customData, chatItemTTL) :. userMemberRow) = let membership = (toGroupMember userContactId userMemberRow) {memberChatVRange = vr} chatSettings = ChatSettings {enableNtfs = fromMaybe MFAll enableNtfs_, sendRcpts = unBI <$> sendRcpts, favorite} fullGroupPreferences = mergeGroupPreferences groupPreferences - groupProfile = GroupProfile {displayName, fullName, description, image, groupPreferences} + groupProfile = GroupProfile {displayName, fullName, description, image, groupPreferences, memberAdmission} businessChat = toBusinessChatInfo businessRow in GroupInfo {groupId, localDisplayName, groupProfile, localAlias, businessChat, fullGroupPreferences, membership, chatSettings, createdAt, updatedAt, chatTs, userMemberProfileSentAt, chatTags, chatItemTTL, uiThemes, customData} @@ -612,7 +612,7 @@ groupInfoQuery = SELECT -- GroupInfo g.group_id, g.local_display_name, gp.display_name, gp.full_name, g.local_alias, gp.description, gp.image, - g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, + g.enable_ntfs, g.send_rcpts, g.favorite, gp.preferences, gp.member_admission, g.created_at, g.updated_at, g.chat_ts, g.user_member_profile_sent_at, g.business_chat, g.business_member_id, g.customer_member_id, g.ui_themes, g.custom_data, g.chat_item_ttl, -- GroupMember - membership mu.group_member_id, mu.group_id, mu.member_id, mu.peer_chat_min_version, mu.peer_chat_max_version, mu.member_role, mu.member_category, diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs index 9d875f5bf4..0063f711c7 100644 --- a/src/Simplex/Chat/Types.hs +++ b/src/Simplex/Chat/Types.hs @@ -57,7 +57,7 @@ import Simplex.Messaging.Crypto.File (CryptoFileArgs (..)) import Simplex.Messaging.Crypto.Ratchet (PQEncryption (..), PQSupport, pattern PQEncOff) import Simplex.Messaging.Encoding.String import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, sumTypeJSON) -import Simplex.Messaging.Util (safeDecodeUtf8, (<$?>)) +import Simplex.Messaging.Util (decodeJSON, encodeJSON, safeDecodeUtf8, (<$?>)) import Simplex.Messaging.Version import Simplex.Messaging.Version.Internal #if defined(dbPostgres) @@ -616,10 +616,24 @@ data GroupProfile = GroupProfile fullName :: Text, description :: Maybe Text, image :: Maybe ImageData, - groupPreferences :: Maybe GroupPreferences + groupPreferences :: Maybe GroupPreferences, + memberAdmission :: Maybe GroupMemberAdmission } deriving (Eq, Show) +data GroupMemberAdmission = GroupMemberAdmission + { -- names :: Maybe MemberCriteria, + -- captcha :: Maybe MemberCriteria, + review :: Maybe MemberCriteria + } + deriving (Eq, Show) + +data MemberCriteria = MCAll + deriving (Eq, Show) + +emptyGroupMemberAdmission :: GroupMemberAdmission +emptyGroupMemberAdmission = GroupMemberAdmission Nothing + newtype ImageData = ImageData Text deriving (Eq, Show) @@ -1816,6 +1830,16 @@ $(JQ.deriveJSON defaultJSON ''LocalProfile) $(JQ.deriveJSON defaultJSON ''UserContactRequest) +$(JQ.deriveJSON (enumJSON $ dropPrefix "MC") {J.tagSingleConstructors = True} ''MemberCriteria) + +$(JQ.deriveJSON defaultJSON ''GroupMemberAdmission) + +instance ToField GroupMemberAdmission where + toField = toField . encodeJSON + +instance FromField GroupMemberAdmission where + fromField = fromTextField_ decodeJSON + $(JQ.deriveJSON defaultJSON ''GroupProfile) $(JQ.deriveJSON (sumTypeJSON $ dropPrefix "IB") ''InvitedBy) diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index c07fcc952d..42d1132961 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -1680,10 +1680,10 @@ countactUserPrefText cup = case cup of viewGroupUpdated :: GroupInfo -> GroupInfo -> Maybe GroupMember -> [StyledString] viewGroupUpdated - GroupInfo {localDisplayName = n, groupProfile = GroupProfile {fullName, description, image, groupPreferences = gps}} - g'@GroupInfo {localDisplayName = n', groupProfile = GroupProfile {fullName = fullName', description = description', image = image', groupPreferences = gps'}} + GroupInfo {localDisplayName = n, groupProfile = GroupProfile {fullName, description, image, groupPreferences = gps, memberAdmission = ma}} + g'@GroupInfo {localDisplayName = n', groupProfile = GroupProfile {fullName = fullName', description = description', image = image', groupPreferences = gps', memberAdmission = ma'}} m = do - let update = groupProfileUpdated <> groupPrefsUpdated + let update = groupProfileUpdated <> groupPrefsUpdated <> memberAdmissionUpdated if null update then [] else memberUpdated <> update @@ -1704,6 +1704,9 @@ viewGroupUpdated | otherwise = Just . plain $ groupPreferenceText (pref gps') where pref = getGroupPreference f . mergeGroupPreferences + memberAdmissionUpdated + | ma == ma' = [] + | otherwise = ["changed member admission rules"] viewGroupProfile :: GroupInfo -> [StyledString] viewGroupProfile g@GroupInfo {groupProfile = GroupProfile {description, image, groupPreferences = gps}} = diff --git a/tests/Bots/DirectoryTests.hs b/tests/Bots/DirectoryTests.hs index 0877a48daa..f8a5aa8b80 100644 --- a/tests/Bots/DirectoryTests.hs +++ b/tests/Bots/DirectoryTests.hs @@ -14,7 +14,6 @@ import Control.Exception (finally) import Control.Monad (forM_, when) import qualified Data.Text as T import Directory.Captcha -import qualified Directory.Events as DE import Directory.Options import Directory.Service import Directory.Store @@ -22,6 +21,7 @@ import GHC.IO.Handle (hClose) import Simplex.Chat.Bot.KnownContacts import Simplex.Chat.Controller (ChatConfig (..), ChatHooks (..), defaultChatHooks) import Simplex.Chat.Core +import qualified Simplex.Chat.Markdown as MD import Simplex.Chat.Options (CoreChatOpts (..)) import Simplex.Chat.Options.DB import Simplex.Chat.Types (Profile (..)) @@ -111,7 +111,7 @@ serviceDbPrefix :: FilePath serviceDbPrefix = "directory_service" viewName :: String -> String -viewName = T.unpack . DE.viewName . T.pack +viewName = T.unpack . MD.viewName . T.pack testDirectoryService :: HasCallStack => TestParams -> IO () testDirectoryService ps = diff --git a/tests/MarkdownTests.hs b/tests/MarkdownTests.hs index fc872f05b1..05d5362cf1 100644 --- a/tests/MarkdownTests.hs +++ b/tests/MarkdownTests.hs @@ -192,10 +192,23 @@ textWithUri = describe "text with Uri" do "https://github.com/simplex-chat/ - SimpleX on GitHub" <==> uri "https://github.com/simplex-chat/" <> " - SimpleX on GitHub" -- "SimpleX on GitHub (https://github.com/simplex-chat/)" <==> "SimpleX on GitHub (" <> uri "https://github.com/simplex-chat/" <> ")" "https://en.m.wikipedia.org/wiki/Servo_(software)" <==> uri "https://en.m.wikipedia.org/wiki/Servo_(software)" + "example.com" <==> uri "example.com" + "example.com." <==> uri "example.com" <> "." + "example.com..." <==> uri "example.com" <> "..." + "www.example.com" <==> uri "www.example.com" + "example.academy" <==> uri "example.academy" + "this is example.com" <==> "this is " <> uri "example.com" + "x.com" <==> uri "x.com" it "ignored as markdown" do "_https://simplex.chat" <==> "_https://simplex.chat" "this is _https://simplex.chat" <==> "this is _https://simplex.chat" "this is https://" <==> "this is https://" + "example.c" <==> "example.c" + "www.www.example.com" <==> "www.www.example.com" + "www.example1.com" <==> "www.example1.com" + "www." <==> "www." + ".com" <==> ".com" + "example.academytoolong" <==> "example.academytoolong" it "SimpleX links" do let inv = "/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D" ("https://simplex.chat" <> inv) <==> simplexLink XLInvitation ("simplex:" <> inv) ["smp.simplex.im"] ("https://simplex.chat" <> inv) @@ -220,12 +233,14 @@ textWithEmail = describe "text with Email" do "test chat.chat+123@simplex.chat" <==> "test " <> email "chat.chat+123@simplex.chat" "chat@simplex.chat test" <==> email "chat@simplex.chat" <> " test" "test1 chat@simplex.chat test2" <==> "test1 " <> email "chat@simplex.chat" <> " test2" - it "ignored as markdown" do + "test chat@simplex.chat." <==> "test " <> email "chat@simplex.chat" <> "." + "test chat@simplex.chat..." <==> "test " <> email "chat@simplex.chat" <> "..." + it "ignored as email markdown" do "chat @simplex.chat" <==> "chat " <> mention "simplex.chat" "@simplex.chat" "this is chat @simplex.chat" <==> "this is chat " <> mention "simplex.chat" "@simplex.chat" - "this is chat@ simplex.chat" <==> "this is chat@ simplex.chat" - "this is chat @ simplex.chat" <==> "this is chat @ simplex.chat" - "*this* is chat @ simplex.chat" <==> bold "this" <> " is chat @ simplex.chat" + "this is chat@ simplex.chat" <==> "this is chat@ " <> uri "simplex.chat" + "this is chat @ simplex.chat" <==> "this is chat @ " <> uri "simplex.chat" + "*this* is chat @ simplex.chat" <==> bold "this" <> " is chat @ " <> uri "simplex.chat" phone :: Text -> Markdown phone = Markdown $ Just Phone @@ -258,8 +273,13 @@ textWithMentions = describe "text with mentions" do "@alice" <==> mention "alice" "@alice" "hello @alice" <==> "hello " <> mention "alice" "@alice" "hello @alice !" <==> "hello " <> mention "alice" "@alice" <> " !" + "hello @alice!" <==> "hello " <> mention "alice" "@alice" <> "!" + "hello @alice..." <==> "hello " <> mention "alice" "@alice" <> "..." + "hello @alice@example.com" <==> "hello " <> mention "alice@example.com" "@alice@example.com" + "hello @'alice @ example.com'" <==> "hello " <> mention "alice @ example.com" "@'alice @ example.com'" "@'alice jones'" <==> mention "alice jones" "@'alice jones'" "hello @'alice jones'!" <==> "hello " <> mention "alice jones" "@'alice jones'" <> "!" + "hello @'a.j.'!" <==> "hello " <> mention "a.j." "@'a.j.'" <> "!" it "ignored as markdown" $ do "hello @'alice jones!" <==> "hello @'alice jones!" "hello @bob @'alice jones!" <==> "hello " <> mention "bob" "@bob" <> " @'alice jones!" diff --git a/tests/ProtocolTests.hs b/tests/ProtocolTests.hs index 50d2c1eef0..1d37a52459 100644 --- a/tests/ProtocolTests.hs +++ b/tests/ProtocolTests.hs @@ -107,7 +107,7 @@ testProfile :: Profile testProfile = Profile {displayName = "alice", fullName = "Alice", image = Just (ImageData "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII="), contactLink = Nothing, preferences = testChatPreferences} testGroupProfile :: GroupProfile -testGroupProfile = GroupProfile {displayName = "team", fullName = "Team", description = Nothing, image = Nothing, groupPreferences = testGroupPreferences} +testGroupProfile = GroupProfile {displayName = "team", fullName = "Team", description = Nothing, image = Nothing, groupPreferences = testGroupPreferences, memberAdmission = Nothing} decodeChatMessageTest :: Spec decodeChatMessageTest = describe "Chat message encoding/decoding" $ do diff --git a/website/langs/ar.json b/website/langs/ar.json index fd759d5491..0c1fb4515a 100644 --- a/website/langs/ar.json +++ b/website/langs/ar.json @@ -29,7 +29,7 @@ "simplex-explained-tab-2-text": "2. كيف يعمل", "simplex-explained-tab-1-p-2": "كيف يمكن أن تعمل مع قوائم انتظار أحادية الاتجاه وبدون معرّفات ملف تعريف المستخدم؟", "simplex-explained-tab-2-p-1": "لكل اتصال، تستخدم قائمتي انتظار منفصلتين للمُراسلة لإرسال واستلام الرسائل عبر خوادم مختلفة.", - "simplex-explained-tab-2-p-2": "تقوم الخوادم بتمرير الرسائل في اتجاه واحد فقط، دون الحصول على الصورة الكاملة لمُحادثات المستخدم أو اتصالاته.", + "simplex-explained-tab-2-p-2": "تمرّر الخوادم الرسائل في اتجاه واحد فقط، دون الحصول على الصورة الكاملة لمُحادثات المستخدم أو اتصالاته.", "simplex-explained-tab-3-p-1": "تحتوي الخوادم على بيانات اعتماد مجهولة منفصلة لكل قائمة انتظار، ولا تعرف المستخدمين الذين ينتمون إليهم.", "copyright-label": "مشروع مفتوح المصدر © SimpleX 2020-2025", "simplex-chat-protocol": "بروتوكول دردشة SimpleX", @@ -51,13 +51,13 @@ "simplex-private-5-title": "طبقات متعددة من
حشوة المحتوى", "simplex-private-7-title": "التحقق
من سلامة الرسالة", "simplex-private-8-title": "خلط الرسائل
لتقليل من الارتباط", - "simplex-private-10-title": "معرفات زوجية مجهولة مؤقتة", + "simplex-private-10-title": "معرّفات زوجية مجهولة مؤقتة", "simplex-private-card-3-point-1": "يتم استخدام TLS 1.2 / 1.3 مع خوارزميات قوية فقط لاتصالات الخادم والعميل.", "simplex-private-card-3-point-2": "تعمل بصمة الخادم وربط القناة على منع هجمات الوسيط (MITM) وإعادة التشغيل.", "simplex-private-card-3-point-3": "استئناف الاتصال معطل لمنع هجمات الجلسة.", "simplex-private-card-4-point-1": "لحماية عنوان IP الخاص بك، يمكنك الوصول إلى الخوادم عبر تور أو بعض شبكات تراكب النقل الأخرى.", "simplex-private-card-5-point-1": "يستخدم SimpleX حشوة المحتوى لكل طبقة تعمية لإحباط هجمات حجم الرسالة.", - "simplex-private-card-6-point-2": "لمنع ذلك، تقوم تطبيقات SimpleX بتمرير مفاتيح لمرة واحدة خارج النطاق، عند مشاركة عنوان كرابط أو رمز QR.", + "simplex-private-card-6-point-2": "لمنع ذلك، تقوم تطبيقات SimpleX بتمرير مفاتيح لمرة واحدة خارج النطاق، عندما تُشارك عنوان كرابط أو رمز QR.", "simplex-private-card-8-point-1": "تعمل خوادم SimpleX كعقد مختلطة بزمن انتقال منخفض — الرسائل الواردة والصادرة لها ترتيب مختلف.", "simplex-private-card-9-point-1": "كل رسالة انتظار تمرر الرسائل في اتجاه واحد، بعناوين إرسال واستلام مختلفة.", "simplex-private-card-9-point-2": "إنه يقلل من نواقل الهجوم، مقارنة بوسطاء الرسائل التقليديين، والبيانات الوصفية المتاحة.", @@ -74,7 +74,7 @@ "simplex-unique-1-overlay-1-title": "الخصوصية الكاملة لهويتك وملفك الشخصي وجهات الاتصال والبيانات الوصفية", "simplex-unique-2-title": "أنت محمي
من رسائل الإزعاج وإساءة الاستخدام", "simplex-unique-3-title": "أنت تتحكم في بياناتك", - "simplex-unique-3-overlay-1-title": "ملكية ومراقبة وأمان بياناتك", + "simplex-unique-3-overlay-1-title": "الملكية والتحكم وأمن بياناتك", "simplex-unique-4-title": "أنت تمتلك شبكة SimpleX", "simplex-unique-4-overlay-1-title": "لامركزية بالكامل — يمتلك المستخدمون شبكة SimpleX", "hero-overlay-card-1-p-4": "هذا التصميم يمنع تسريب أي البيانات الوصفية للمستخدمين على مستوى التطبيق. لزيادة تحسين الخصوصية وحماية عنوان IP الخاص بك، يمكنك الاتصال بخوادم المراسلة عبر Tor.", @@ -85,23 +85,23 @@ "privacy-matters-overlay-card-1-p-2": "يعرف تجار التجزئة عبر الإنترنت أن الأشخاص ذوي الدخل المنخفض هم أكثر عرضة لإجراء عمليات شراء عاجلة، لذلك قد يفرضون أسعارًا أعلى أو يزيلون الخصومات.", "simplex-private-6-title": "تبديل
خارج النطاق", "simplex-private-9-title": "قوائم انتظار
أحادية الاتجاه", - "privacy-matters-overlay-card-1-p-4": "تحمي منصة SimpleX خصوصية اتصالاتك بشكل أفضل من أي بديل آخر، مما يمنع تمامًا الرسم البياني الاجتماعي الخاص بك من أن يصبح متاحًا لأي شركات أو مؤسسات. حتى عندما يستخدم الأشخاص الخوادم التي توفرها SimpleX Chat، فإننا لا نعرف عدد المستخدمين أو اتصالاتهم.", + "privacy-matters-overlay-card-1-p-4": "تحمي شبكة SimpleX خصوصية اتصالاتك بشكل أفضل من أي بديل آخر، مما يمنع تمامًا الرسم البياني الاجتماعي الخاص بك من أن يصبح متاحًا لأي شركات أو مؤسسات. حتى عندما يستخدم الأشخاص الخوادم التي توفرها SimpleX Chat، فإننا لا نعرف عدد المستخدمين أو اتصالاتهم.", "simplex-private-card-1-point-1": "بروتوكول السقاطة المزدوجة —
رسائل OTR مع السرية المستمرة واستعادة الاختراق.", "simplex-private-card-1-point-2": "NaCL cryptobox في كل قائمة انتظار لمنع ارتباط حركة مرور البيانات بين قوائم انتظار الرسائل في حالة اختراق TLS.", "simplex-private-card-2-point-1": "طبقة إضافية من تعمية الخادم للتسليم إلى المُستلم، لمنع الارتباط بين حركة مرور بيانات الخادم المُستلمة والمُرسلة في حالة اختراق TLS.", "simplex-private-card-4-point-2": "لاستخدام SimpleX عبر تور، يُرجى تثبيت تطبيق Orbot وتمكّين وكيل SOCKS5 (أو VPN على iOS ).", "simplex-private-card-5-point-2": "يجعل الرسائل ذات الأحجام المختلفة تبدو متشابهة للخوادم ومراقبي الشبكة.", - "simplex-private-card-6-point-1": "العديد من منصات الاتصال عرضة لهجمات الوسيط (MITM) من قبل الخوادم أو موفري الشبكات.", + "simplex-private-card-6-point-1": "العديد من شبكات التواصل عرضة لهجمات الوسيط (MITM) من قِبل الخوادم أو موفري الشبكات.", "simplex-private-card-7-point-1": "لضمان سلامة الرسائل يتم ترقيمها بالتسلسل وتضمين تجزئة الرسالة السابقة.", "simplex-private-card-7-point-2": "إذا أُضيفت أي رسالة أو أُزيلت أو تغيّرت، فسيتم تنبيه المُستلم.", "simplex-private-card-10-point-2": "يسمح بتسليم الرسائل بدون معرّفات ملف تعريف المستخدم، مما يوفر خصوصية للبيانات الوصفية أفضل من البدائل.", "privacy-matters-2-overlay-1-linkText": "تمنحك الخصوصية القوة", "simplex-unique-2-overlay-1-title": "أفضل حماية من رسائل الإزعاج وإساءة الاستخدام", - "hero-overlay-card-1-p-3": "أنت تحدد الخادم (الخوادم) المراد استخدامه لاستلام الرسائل وجهات الاتصال الخاصة بك — الخوادم التي تستخدمها لإرسال الرسائل إليهم. من المرجح أن تستخدم كل مُحادثة خادمين مختلفين.", + "hero-overlay-card-1-p-3": "أنت تحدد الخادم (الخوادم) المراد استخدامه لاستلام الرسائل وجهات اتصالك — الخوادم التي تستخدمها لإرسال الرسائل إليهم. من المرجح أن تستخدم كل مُحادثة خادمين مختلفين.", "hero-overlay-card-1-p-1": "سأل العديد من المستخدمين: إذا لم يكن لدى SimpleX معرّفات مستخدم، فكيف يمكنها معرفة مكان تسليم الرسائل؟ ", - "hero-overlay-card-1-p-2": "لتوصيل الرسائل، بدلاً من معرفات المستخدم التي تستخدمها جميع المنصات الأخرى، يستخدم SimpleX معرّفات مزدوجة مؤقتة مجهولة الهوية لقوائم انتظار الرسائل، مختلفة لكل اتصال من اتصالاتك — لا توجد معرفات مستخدم دائمة.", + "hero-overlay-card-1-p-2": "لتسليم الرسائل، بدلاً من معرّفات المُستخدم المُستخدمة من قِبل جميع الشبكات الأخرى، يستخدم SimpleX معرّفات زوجية مجهولة مؤقتة لقوائم الرسائل، منفصلة لكل اتصال من اتصالاتك — ولا توجد معرّفات طويلة الأجل.", "simplex-network-overlay-card-1-p-1": "بروتوكولات المُراسلة والتطبيقات P2P بها مشاكل مختلفة تجعلها أقل موثوقية من SimpleX وأكثر تعقيدًا في التحليل و عرضة لعدة أنواع من الهجمات.", - "hero-overlay-card-2-p-1": "عندما يكون لدى المستخدمين هويات ثابتة، حتى لو كان هذا مجرد رقم عشوائي، مثل معرف الجلسة، فهناك خطر يتمثل في أن الموفر أو المهاجم يمكنه مراقبة كيفية اتصال المستخدمين وعدد الرسائل التي يرسلونها.", + "hero-overlay-card-2-p-1": "عندما يكون لدى المستخدمين هويات ثابتة، حتى لو كان هذا مجرد رقم عشوائي، مثل معرّف الجلسة، فهناك خطر يتمثل في أن الموفر أو المهاجم يمكنه مراقبة كيفية اتصال المستخدمين وعدد الرسائل التي يرسلونها.", "hero-overlay-card-1-p-6": "اقرأ المزيد في SimpleX whitepaper .", "hero-overlay-card-2-p-3": "حتى مع معظم التطبيقات الخاصة التي تستخدم خدمات Tor v3، إذا تحدثت إلى جهتي اتصال مختلفتين عبر نفس الملف الشخصي، فيمكنهما إثبات أنهما متصلان بنفس الشخص.", "hero-overlay-card-2-p-4": "يحمي SimpleX من هذه الهجمات من خلال عدم وجود أي معرّفات مستخدم في تصميمه. وإذا كنت تستخدم وضع التخفي، فسيكون لديك اسم عرض مختلف لكل جهة اتصال، مع تجنب أي بيانات مشتركة بينهما.", @@ -112,23 +112,23 @@ "simplex-network-overlay-card-1-li-5": "قد تكون جميع شبكات P2P المعروفة عرضة لهجوم Sybil، لأن كل عقدة قابلة للاكتشاف، وتعمل الشبكة ككل. تتطلب الإجراءات المعروفة لتخفيفها إما مكونًا مركزيًا أو إثبات عمل مكلف . لا تحتوي شبكة SimpleX على إمكانية اكتشاف الخادم، فهي مجزأة وتعمل كشبكات فرعية متعددة ومعزولة، مما يجعل الهجمات على مستوى الشبكة مستحيلة.", "privacy-matters-overlay-card-3-p-1": "يجب على الجميع الاهتمام بخصوصية وأمان اتصالاتهم — يمكن للمُحادثات غير الضارة أن تعرضك للخطر، حتى لو لم يكن لديك ما تخفيه.", "privacy-matters-overlay-card-3-p-4": "لا يكفي استخدام برنامج مُراسلة مُعمَّاة بين الطرفين، يجب علينا جميعًا استخدام برامج مُراسلة التي تحمي خصوصية شبكاتنا الشخصية — مع من نحن مرتبطون.", - "simplex-unique-overlay-card-1-p-3": "يحمي هذا التصميم خصوصية الأشخاص الذين تتواصل معهم، ويخفيها عن خوادم منصة SimpleX ومن أي مراقبين. لإخفاء عنوان IP الخاص بك من الخوادم، يمكنك الاتصال بخوادم SimpleX عبر تور.", - "simplex-unique-overlay-card-2-p-1": "نظرًا لعدم وجود معرف لديك على نظام SimpleX، لا يمكن لأي شخص الاتصال بك ما لم تشارك عنوان مستخدم لمرة واحدة أو مؤقتًا، كرمز QR أو رابط.", + "simplex-unique-overlay-card-1-p-3": "يحمي هذا التصميم خصوصية الأشخاص الذين تتواصل معهم، ويخفيها عن خوادم شبكة SimpleX ومن أي مراقبين. لإخفاء عنوان IP الخاص بك من الخوادم، يمكنك الاتصال بخوادم SimpleX عبر تور.", + "simplex-unique-overlay-card-2-p-1": "نظرًا لعدم وجود معرّف لديك على شبكة SimpleX، لا يمكن لأي شخص الاتصال بك ما لم تشارك عنوان مستخدم لمرة واحدة أو مؤقتًا، كرمز QR أو رابط.", "simplex-unique-overlay-card-2-p-2": "حتى مع عنوان المستخدم الاختياري، بينما يمكن استخدامه لإرسال طلبات جهات اتصال مزعجة، يمكنك تغييره أو حذفه بالكامل دون فقد أي من اتصالاتك.", "simplex-unique-overlay-card-3-p-2": "يتم الاحتفاظ بالرسائل المُعمَّاة بين الطرفين مؤقتًا على خوادم ترحيل SimpleX حتى يتم استلامها، ثُمَّ تُحذف نهائيًا.", - "simplex-unique-overlay-card-3-p-4": "لا توجد معرفّات أو نص مُعَمَّى مشترك بين حركة مرور بيانات الخادم المُرسلة والمُستلمة — ؛ إذا كان أي شخص يراقب ذلك، فلن يتمكّن بسهولة من تحديد من يتواصل مع من، حتى لو اختُرق TLS.", - "simplex-unique-card-1-p-1": "يحمي SimpleX خصوصية ملف التعريف الخاص بك، جهات الاتصال والبيانات الوصفية، ويخفيه عن خوادم منصة SimpleX وأي مراقبين.", + "simplex-unique-overlay-card-3-p-4": "لا توجد معرفّات أو نص مُعَمَّى مشترك بين حركة مرور بيانات الخادم المُرسلة والمُستلمة — إذا كان أي شخص يراقب ذلك، فلن يتمكّن بسهولة من تحديد من يتواصل مع من، حتى لو اختُرق TLS.", + "simplex-unique-card-1-p-1": "يحمي SimpleX خصوصية ملف تعريفك، جهات اتصالك والبيانات الوصفية، ويخفيه عن خوادم شبكة SimpleX وأي مراقبين.", "privacy-matters-overlay-card-2-p-1": "منذ وقت ليس ببعيد، لاحظنا أن الانتخابات الرئيسية يتم التلاعب بها بواسطة شركة استشارية ذات سمعة طيبة التي استخدمت الرسوم البيانية الاجتماعية لتشويه نظرتنا للعالم الحقيقي والتلاعب بأصواتنا.", - "privacy-matters-overlay-card-2-p-2": "لكي تكون موضوعيًا وتتخذ قرارات مستقلة، يجب أن تكون متحكمًا في مساحة المعلومات الخاصة بك. هذا ممكن فقط إذا كنت تستخدم منصة اتصالات خاصة لا يمكنها الوصول إلى الرسم البياني الاجتماعي الخاص بك.", - "privacy-matters-overlay-card-2-p-3": "SimpleX هو النظام الأساسي الأول الذي لا يحتوي على أي معرّفات مستخدم صمّم ليكون خاصًا، وبهذه الطريقة تحمي مخطط اتصالاتك بشكل أفضل من أي بديل معروف.", + "privacy-matters-overlay-card-2-p-2": "لكي تكون موضوعيًا وتتخذ قرارات مستقلة، عليك التحكم في مساحة معلوماتك. لا يمكن تحقيق ذلك إلا باستخدام شبكة اتصال خاصة لا يمكنها الوصول إلى حسابك على مواقع التواصل الاجتماعي.", + "privacy-matters-overlay-card-2-p-3": "SimpleX هي أول شبكة لا تحتوي على أي معرّفات مستخدم من حيث التصميم، وبهذه الطريقة تحمي مخطط اتصالاتك بشكل أفضل من أي بديل معروف.", "privacy-matters-overlay-card-3-p-2": "واحدة من أكثر القصص إثارة للصدمة هي تجربة محمدو ولد صلاحي الموصوفة في مذكراته والموضحة في فيلم موريتاني. تم وضعه في معتقل غوانتانامو بدون محاكمة، وتعرض للتعذيب هناك لمدة 15 عامًا بعد مكالمة هاتفية مع قريبه في أفغانستان، للاشتباه في تورطه في هجمات 11 سبتمبر، على الرغم من أنه عاش في ألمانيا طوال السنوات العشر الماضية.", "privacy-matters-overlay-card-3-p-3": "يتم القبض على الأشخاص العاديين بسبب ما يشاركونه عبر الإنترنت، حتى عبر حساباتهم \"المجهولة\"، وحتى في البلدان الديمقراطية.", - "simplex-unique-overlay-card-1-p-1": "على عكس أنظمة المُراسلة الأخرى، لا يحتوي SimpleX على معرّفات مخصصة للمستخدمين. لا يعتمد على أرقام الهواتف أو العناوين المستندة إلى النطاقات (مثل البريد الإلكتروني أو XMPP)، أسماء المستخدمين، المفاتيح العامة أو حتى الأرقام العشوائية لتحديد مستخدميها — لا نعرف عدد الأشخاص الذين يستخدمون خوادم SimpleX الخاصة بنا.", - "simplex-unique-overlay-card-1-p-2": "لتسليم الرسائل، يستخدم SimpleX العناوين المزدوجة المجهولة لقوائم انتظار الرسائل أحادية الاتجاه، منفصلة عن الرسائل المُستلمة والمُرسلة، عادةً عبر خوادم مختلفة. إن استخدام SimpleX يشبه امتلاك بريد إلكتروني أو هاتف “مؤقت” مختلف لكل جهة اتصال، ولا توجد متاعب في إدارتها.", + "simplex-unique-overlay-card-1-p-1": "على عكس شبكات المُراسلة الأخرى، لا يحتوي SimpleX على معرّفات مخصصة للمستخدمين. لا يعتمد على أرقام الهواتف أو العناوين المستندة إلى النطاقات (مثل البريد الإلكتروني أو XMPP)، أسماء المستخدمين، المفاتيح العامة أو حتى الأرقام العشوائية لتحديد مستخدميها — مُشغلي خادم SimpleX لا يعرفون عدد الأشخاص الذين يستخدمون خوادمهم.", + "simplex-unique-overlay-card-1-p-2": "لتسليم الرسائل، يستخدم SimpleX العناوين المزدوجة المجهولة لقوائم انتظار الرسائل أحادية الاتجاه، منفصلة عن الرسائل المُستلمة والمُرسلة، عادةً عبر خوادم مختلفة.", "simplex-unique-overlay-card-3-p-1": "يخزن SimpleX Chat جميع بيانات المستخدم على أجهزة العميل فقط باستخدام تنسيق قاعدة بيانات محمولة مُعمَّاة يمكّن تصديرها ونقلها إلى أي جهاز مدعوم.", "simplex-unique-overlay-card-3-p-3": "على عكس خوادم الشبكات الاتحادية (البريد الإلكتروني أو XMPP أو Matrix)، لا تقوم خوادم SimpleX بتخزين حسابات المستخدمين، فهي تقوم فقط بترحيل الرسائل، مما يحمي خصوصية كلا الطرفين.", - "simplex-unique-overlay-card-4-p-1": "يمكنك استخدام SimpleX مع الخوادم الخاصة بك والاستمرار في التواصل مع الأشخاص الذين يستخدمون الخوادم المهيأة مسبقًا التي نقدمها.", - "simplex-unique-overlay-card-4-p-3": "إذا كنت تفكر في التطوير لمنصة SimpleX، على سبيل المثال، بوت الدردشة لمستخدمي تطبيق SimpleX، أو دمج مكتبة SimpleX Chat في تطبيقات الأجهزة المحمولة، من فضلك تواصل معي لأي نصيحة والدعم.", + "simplex-unique-overlay-card-4-p-1": "يمكنك استخدام SimpleX مع خوادمك والاستمرار في التواصل مع الأشخاص الذين يستخدمون الخوادم المُهيأة مسبقًا في التطبيقات.", + "simplex-unique-overlay-card-4-p-3": "إذا كنت تفكر في التطوير شبكة SimpleX، على سبيل المثال، بوت الدردشة لمستخدمي تطبيق SimpleX، أو دمج مكتبة SimpleX Chat في تطبيقات الأجهزة المحمولة، من فضلك تواصل معي لأي نصيحة والدعم.", "donate-here-to-help-us": "تبرّع هنا لمساعدتنا", "sign-up-to-receive-our-updates": "اشترك للحصول على آخر مستجداتنا", "enter-your-email-address": "أدخل عنوان بريدك الإلكتروني", @@ -152,16 +152,16 @@ "no-decentralized": "لا - لامركزي", "no-federated": "لا - اتِحاديّ", "comparison-section-list-point-2": "العناوين تعتمد على الـDNS", - "comparison-section-list-point-3": "المفتاح العام أو معرف آخر فريد وعام", + "comparison-section-list-point-3": "المفتاح العام أو معرّف آخر فريد وعام", "comparison-section-list-point-7": "شبكات P2P إما لديها سلطة مركزية أو أن الشبكة كلها يمكن عرضة للخطر", "see-here": "اقرأ هنا", "no-secure": "لا - آمن", "comparison-section-list-point-5": "لا يحمي خصوصية البيانات الوصفية للمستخدمين", - "comparison-section-list-point-6": "على الرغم من أن الـP2P موزعة، إلا أنها ليست اتِحاديَّة - يعملون كشبكة واحدة", + "comparison-section-list-point-6": "على الرغم من أن الـP2P موزعة، إلا أنها ليست اتِحاديَّة — يعملون كشبكة واحدة", "comparison-section-list-point-1": "عادة ما يكون مكوناً من رقم الهاتف، أو اسم المستخدم في بعض الأحيان", "comparison-section-list-point-4": "إذا خوادم المشغّل مُخترقة. تحقق من رمز الأمان في Signal وبعض التطبيقات الأخرى للتخفيف منه", "simplex-unique-card-3-p-1": "يخزن SimpleX جميع بيانات المستخدم على الأجهزة العميلة بتنسيق قاعدة بيانات محمولة مُعمَّاة — يمكّن نقلها إلى جهاز آخر.", - "simplex-unique-card-4-p-1": "شبكة SimpleX لا مركزية بالكامل ومستقلة عن أي عملة مُعمَّاة أو أي منصة أخرى، بخلاف الإنترنت.", + "simplex-unique-card-4-p-1": "شبكة SimpleX لا مركزية بالكامل ومستقلة عن أي عملة مُعمَّاة أو أي شبكة أخرى، بخلاف الإنترنت.", "simplex-unique-card-4-p-2": "يمكنك استخدام SimpleX مع خوادمك الخاصة أو مع الخوادم التي نوفرها — ولا يزال الاتصال ممكن بأي مستخدم.", "join": "انضم إلى", "we-invite-you-to-join-the-conversation": "نحن ندعوك للانضمام إلى المُحادثة", @@ -178,7 +178,7 @@ "use-this-command": "استخدم هذا الأمر:", "see-simplex-chat": "انظر SimpleX Chat", "github-repository": "مستودع Github", - "the-instructions--source-code": "التعليمات حول كيفية تنزيله أو تجميعه من التعليمات البرمجية المصدر.", + "the-instructions--source-code": "للتعليمات حول كيفية تنزيله أو تجميعه من التعليمات البرمجية المصدر.", "if-you-already-installed-simplex-chat-for-the-terminal": "إذا قمت بالفعل بتثبيت SimpleX Chat للوحدة الطرفية", "simplex-chat-for-the-terminal": "SimpleX Chat للوحدة الطرفية", "privacy-matters-section-header": "لماذا الخصوصية مهمة", @@ -189,8 +189,8 @@ "simplex-network-3-header": "شبكة SimpleX", "protocol-1-text": "Signal، منصات كبيرة", "protocol-2-text": "XMPP ،Matrix", - "simplex-unique-card-1-p-2": "بخلاف أي نظام مُراسلة آخر، لا يحتوي SimpleX على معرّفات مخصصة للمستخدمين — ولا حتى أرقام عشوائية.", - "simplex-unique-card-2-p-1": "نظرًا لعدم وجود معرف أو عنوان ثابت على منصة SimpleX، لا يمكن لأي شخص الاتصال بك ما لم تشارك عنوان مستخدم لمرة واحدة أو مؤقتًا، كرمز QR أو رابط.", + "simplex-unique-card-1-p-2": "على عكس أي شبكة مُراسلة آخر، لا يحتوي SimpleX على معرّفات مخصّصة للمستخدمين — ولا حتى أرقام عشوائية.", + "simplex-unique-card-2-p-1": "نظرًا لعدم وجود معرّف أو عنوان ثابت على شبكة SimpleX، لا يمكن لأي شخص الاتصال بك ما لم تشارك عنوان مستخدم لمرة واحدة أو مؤقتًا، كرمز QR أو رابط.", "simplex-unique-card-3-p-2": "يتم الاحتفاظ بالرسائل المُعمَّاة بين الطرفين مؤقتًا على خوادم ترحيل SimpleX حتى يتم استلامها، ثُمَّ تُحذف نهائيًا.", "tap-the-connect-button-in-the-app": "اضغط على زر \"اتصال\" في التطبيق", "scan-the-qr-code-with-the-simplex-chat-app": "امسح رمز QR باستخدام تطبيق SimpleX Chat", @@ -208,7 +208,7 @@ "simplex-network-2-desc": "لا تقوم خوادم الترحيل SimpleX بتخزين ملفات تعريف المستخدمين وجهات الاتصال والرسائل التي تم تسليمها، ولا تتصل ببعضها البعض، ولا يوجد دليل خوادم.", "comparison-point-1-text": "يتطلب هوية عالمية", "protocol-3-text": "بروتوكولات P2P", - "simplex-unique-overlay-card-4-p-2": "تستخدم منصة SimpleX بروتوكول مفتوح وتوفر SDK لإنشاء روبوتات دردشة، مما يسمح بتنفيذ الخدمات التي يمكن للمستخدمين التفاعل معها عبر تطبيقات SimpleX Chat — التي تتطلع حقًا لمعرفة خدمات SimpleX التي يمكنك إنشاؤها.", + "simplex-unique-overlay-card-4-p-2": "تستخدم شبكة SimpleX بروتوكول مفتوح وتوفر SDK لإنشاء روبوتات دردشة، مما يسمح بتنفيذ الخدمات التي يمكن للمستخدمين التفاعل معها عبر تطبيقات SimpleX Chat — التي تتطلع حقًا لمعرفة خدمات SimpleX التي ستبنيها.", "guide-dropdown-1": "بداية سريعة", "guide-dropdown-2": "إرسال الرسائل", "guide-dropdown-3": "مجموعات سرية", @@ -227,7 +227,7 @@ "menu": "قائمة", "on-this-page": "على هذه الصفحة", "back-to-top": "عد إلى الأعلى", - "docs-dropdown-1": "منصة SimpleX", + "docs-dropdown-1": "شبكة SimpleX", "guide": "الدليل", "docs-dropdown-2": "الوصول إلى ملفات اندرويد", "docs-dropdown-3": "الوصول إلى قاعدة بيانات الدردشة", @@ -244,7 +244,7 @@ "f-droid-page-f-droid-org-repo-section-text": "مستودعات SimpleX Chat و F-Droid.org مبنية على مفاتيح مختلفة. للتبديل، يُرجى تصدير قاعدة بيانات الدردشة وإعادة تثبيت التطبيق.", "comparison-section-list-point-4a": "مُرحلات SimpleX لا يمكنها أن تتنازل عن تعمية بين الطرفين. تحقق من رمز الأمان للتخفيف من الهجوم على القناة خارج النطاق", "hero-overlay-3-title": "التقييمات الأمنية", - "hero-overlay-card-3-p-2": "قامت Trail of Bits بمراجعة مكونات التشفير والشبكات الخاصة بمنصة SimpleX في نوفمبر 2022. اقرأ المزيد في الإعلان.", + "hero-overlay-card-3-p-2": "قامت Trail of Bits بمراجعة مكونات التشفير والشبكات الخاصة بشبكة SimpleX في نوفمبر 2022. اقرأ المزيد في الإعلان.", "jobs": "انضم للفريق", "hero-overlay-3-textlink": "التقييمات الأمنية", "hero-overlay-card-3-p-1": "Trail of Bits هي شركة رائدة في مجال الاستشارات الأمنية والتكنولوجية، ومن بين عملائها شركات التكنولوجيا الكبرى والوكالات الحكومية ومشاريع blockchain الكبرى.", diff --git a/website/langs/de.json b/website/langs/de.json index f2ec261ab7..3e5ef9fbc4 100644 --- a/website/langs/de.json +++ b/website/langs/de.json @@ -15,7 +15,7 @@ "simplex-explained-tab-1-p-1": "Sie können Kontakte und Gruppen erstellen und haben Zwei-Wege-Kommunikation wie in jedem anderen Messenger.", "simplex-explained-tab-1-p-2": "Wie funktioniert das mit den unidirektionalen Warteschlangen und ohne Profilkennungen?", "simplex-explained-tab-2-p-1": "Für jede Verbindung nutzen Sie zwei separate Nachrichten-Warteschlangen, um die Nachrichten über verschiedene Server zu senden und zu empfangen.", - "simplex-explained-tab-2-p-2": "Die Server leiten Nachrichten immer nur in eine Richtung weiter, ohne den vollständigen Verlauf der Nutzer-Unterhaltung oder seiner Verbindungen zu kennen.", + "simplex-explained-tab-2-p-2": "Die Server leiten Nachrichten immer nur in eine Richtung weiter, ohne den vollständigen Verlauf der Nutzer-Unterhaltungen oder seiner Verbindungen zu kennen.", "simplex-explained-tab-3-p-1": "Die Server nutzen für jede Warteschlange separate, anonyme Anmeldeinformationen und wissen nicht welchem Nutzer diese gehören.", "simplex-explained-tab-3-p-2": "Durch die Verwendung von Tor-Zugangsservern können Nutzer ihre Metadaten-Privatsphäre weiter verbessern und Korellationen von IP-Adressen verhindern.", "smp-protocol": "SMP-Protokoll", @@ -64,7 +64,7 @@ "simplex-private-card-4-point-2": "Um SimpleX per Tor zu nutzen, installieren Sie unter Android bitte die Orbot-App und aktivieren Sie den SOCKS5-Proxy oder unter iOS per VPN.", "simplex-private-card-5-point-1": "SimpleX nutzt Inhalte-Auffüllung für jede Verschlüsselungs-Schicht, um Angriffe auf die Nachrichtengröße zu vereiteln.", "simplex-private-card-5-point-2": "Erzeugt Nachrichten mit unterschiedlichen Größen, die für Server und Netzwerk-Beobachter identisch aussehen.", - "simplex-private-card-6-point-1": "Viele Kommunikations-Plattformen sind für MITM-Angriffe durch Server oder Netzwerk-Anbieter anfällig.", + "simplex-private-card-6-point-1": "Viele Kommunikations-Netzwerke sind für MITM-Angriffe durch Server oder Netzwerk-Anbieter anfällig.", "simplex-private-card-9-point-1": "Jede Nachrichten-Warteschlange leitet Nachrichten mit unterschiedlichen Sende- und Empfängeradressen jeweils nur in einer Richtung weiter.", "simplex-private-card-9-point-2": "Verglichen mit traditionellen Nachrichten-Brokern, werden mögliche Angriffs-Vektoren und vorhandene Metadaten reduziert.", "simplex-private-card-10-point-1": "SimpleX nutzt für jeden Nutzer-Kontakt oder jedes Gruppenmitglied eigene temporäre, anonyme und paarweise Adressen und Berechtigungsnachweise.", @@ -95,29 +95,29 @@ "hero-overlay-card-1-p-6": "Lesen Sie mehr darüber im SimpleX-Whitepaper.", "hero-overlay-card-2-p-2": "Sie können diese Informationen mit bestehenden öffentlichen sozialen Netzwerken korrelieren und damit wahre Identitäten herausfinden.", "hero-overlay-card-2-p-3": "Wenn Sie sich mit zwei unterschiedlichen Kontakten über dasselbe Profil unterhalten, können sie, selbst bei sehr auf Privatsphäre bedachten Apps, die Tor-v3-Dienste nutzen, feststellen, dass diese Kontakte mit derselben Person verbunden sind.", - "hero-overlay-card-1-p-2": "Um Nachrichten auszuliefern, nutzt SimpleX statt Benutzerkennungen wie auf allen anderen Plattformen temporäre, anonyme und paarweise Kennungen für Nachrichten-Warteschlangen, die für jede Ihrer Verbindungen unterschiedlich sind — Es gibt keinerlei Langzeit-Kennungen.", + "hero-overlay-card-1-p-2": "Um Nachrichten auszuliefern, nutzt SimpleX statt Benutzerkennungen wie alle anderen Netzwerke nur temporäre, anonyme und paarweise Kennungen für Nachrichten-Warteschlangen, die für jede Ihrer Verbindungen unterschiedlich sind — es gibt keinerlei Langzeit-Kennungen.", "hero-overlay-card-1-p-4": "Dieses Design verhindert schon auf der Applikations-Ebene Datenlecks für jegliche Benutzer'Metadaten. Sie können sich über Tor mit Nachrichten-Servern verbinden, um Ihre Privatsphäre weiter zu verbessern und die von Ihnen genutzte IP-Adresse zu schützen.", "hero-overlay-card-2-p-1": "Wenn Nutzer dauerhafte Identitäten besitzen, selbst wenn diese eine Zufallsnummer, wie eine Sitzungs-ID, ist, besteht ein Risiko, das Provider oder Angreifer feststellen können, wie Nutzer miteinander verbunden sind und wie viele Nachrichten sie versenden.", "hero-overlay-card-2-p-4": "SimpleX schützt gegen solche Angriffe, weil es vom Design her keinerlei Benutzerkennungen besitzt. Und Sie haben sogar unterschiedliche Anzeigenamen für jeden Kontakt und vermeiden jegliche geteilte Daten zwischen diesen, wenn Sie den Inkognito-Modus nutzen.", "simplex-network-overlay-card-1-p-1": "Peer-to-Peer-Nachrichten-Protokolle und -Applikationen haben verschiedene Probleme, die diese weniger vertrauenswürdig, die Analyse wesentlich komplexer und anfälliger gegen verschiedene Arten von Angriffen, als bei SimpleX machen.", "simplex-network-overlay-card-1-li-2": "Das SimpleX Design hat, im Gegensatz zu den meisten P2P-Netzwerken, keinerlei globalen Benutzerkennungen, auch keine temporären. Es nutzt ausschließlich temporäre paarweise Kennungen, die bessere Anonymität und Metadaten-Schutz bieten.", - "simplex-network-overlay-card-1-li-4": "P2P-Implementierungen können durch Internetanbieter blockiert werden, wie beispielweise BitTorrent). SimpleX ist transportunabhängig – es kann über Standard-Web-Protokolle, wie beispielsweise WebSockets, arbeiten.", + "simplex-network-overlay-card-1-li-4": "——P2P-Implementierungen können durch Internetanbieter blockiert werden, wie beispielweise BitTorrent). SimpleX ist transportunabhängig — es kann über Standard-Web-Protokolle, wie beispielsweise WebSockets, arbeiten.", "simplex-network-overlay-card-1-li-6": "P2P-Netzwerke können anfällig für DRDoS-Angriffe sein, wenn die Clients den Datenverkehr erneut senden und verstärken können, was zu einem netzwerkweiten Denial-of-Service führt. SimpleX-Clients leiten nur Datenverkehr von bekannten Verbindungen weiter und können von einem Angreifer nicht dazu verwendet werden, den Datenverkehr im gesamten Netzwerk zu verstärken.", "privacy-matters-overlay-card-1-p-1": "Viele große Unternehmen nutzen Informationen, mit wem Sie in Verbindung stehen, um Ihr Einkommen zu schätzen, Ihnen Produkte zu verkaufen, die Sie nicht wirklich benötigen und um die Preise zu bestimmen.", "privacy-matters-overlay-card-1-p-2": "Online-Händler wissen, dass Menschen mit geringerem Einkommen eher dringende Einkäufe tätigen, sodass sie möglicherweise höhere Preise verlangen können oder Rabatte streichen.", "privacy-matters-overlay-card-1-p-3": "Einige Finanz- und Versicherungsunternehmen verwenden soziale Graphen, um Zinssätze und Prämien zu ermitteln. Menschen mit niedrigerem Einkommen zahlen so häufig mehr — dies ist als \"Armutsprämie\" bekannt.", - "privacy-matters-overlay-card-2-p-2": "Um objektiv zu sein und unabhängige Entscheidungen treffen zu können, müssen Sie die Kontrolle über Ihren Informationsraum haben. Dies ist nur möglich, wenn Sie eine private Kommunikationsplattform verwenden, die keinen Zugriff auf Ihren sozialen Graphen hat.", - "privacy-matters-overlay-card-2-p-3": "SimpleX ist die erste Plattform, die per Design keinerlei Benutzerkennungen hat und auf diese Weise Ihren Verbindungsgraphen besser schützt als jede andere bekannte Alternative.", + "privacy-matters-overlay-card-2-p-2": "Um objektiv zu sein und unabhängige Entscheidungen treffen zu können, müssen Sie die Kontrolle über Ihren Informationsraum haben. Dies ist nur möglich, wenn Sie ein privates Kommunikations-Netzwerk verwenden, welches keinen Zugriff auf Ihren sozialen Graphen hat.", + "privacy-matters-overlay-card-2-p-3": "SimpleX ist das erste Netzwerk, welches per Design keinerlei Benutzerkennungen hat und auf diese Weise Ihren Verbindungsgraphen besser schützt als jede andere bekannte Alternative.", "privacy-matters-overlay-card-3-p-1": "Jede Person sollte sich um ihre Privatsphäre und die Sicherheit ihrer Kommunikation kümmern — Harmlose Gespräche könnten Sie in Gefahr bringen, selbst wenn Sie nichts zu verbergen haben.", "privacy-matters-overlay-card-3-p-4": "Es reicht nicht aus, einfach einen Ende-zu-Ende-verschlüsselten Messenger zu verwenden. Wir alle sollten den Messenger verwenden, der die Privatsphäre unserer persönlichen Netzwerke schützt, mit welchen wir verbunden sind.", - "simplex-unique-overlay-card-1-p-3": "Dieses Design schützt die Privatsphäre von Ihnen und der Personen, mit denen Sie kommunizieren, und verbirgt die Verbindungen vor den SimpleX-Plattform-Servern und möglichen Beobachtern. Um Ihre IP-Adresse vor den Servern zu verbergen, können Sie sich per Tor mit den SimpleX-Servern verbinden.", - "simplex-unique-overlay-card-2-p-1": "Da Sie auf der SimpleX-Plattform keine Kennungen haben, kann Sie niemand kontaktieren, es sei denn, Sie geben eine einmalige oder vorübergehende Benutzeradresse in Form eines QR-Codes oder eines Links weiter.", + "simplex-unique-overlay-card-1-p-3": "Dieses Design schützt die Privatsphäre von Ihnen und der Nutzer, mit denen Sie kommunizieren, und verbirgt die Verbindungen vor den SimpleX-Netzwerk-Servern und möglichen Beobachtern. Um Ihre IP-Adresse vor den Servern zu verbergen, können Sie sich per Tor mit den SimpleX-Servern verbinden.", + "simplex-unique-overlay-card-2-p-1": "Da Sie im SimpleX-Netzwerk keine Kennungen haben, kann Sie niemand kontaktieren, es sei denn, Sie geben eine einmalige oder vorübergehende Benutzeradresse in Form eines QR-Codes oder eines Links weiter.", "simplex-unique-overlay-card-3-p-2": "Die Ende-zu-Ende-verschlüsselten Nachrichten werden vorübergehend auf SimpleX-Relay-Servern gespeichert, bis sie vom Endgerät empfangen und danach endgültig gelöscht werden.", "simplex-unique-overlay-card-3-p-3": "Im Gegensatz zu föderierten Netzwerkservern (wie z.B. Mail, XMPP oder Matrix) speichern die SimpleX-Server keine Benutzerkonten, sondern leiten Nachrichten nur weiter, so dass die Privatsphäre der beteiligten Parteien geschützt ist.", - "simplex-unique-overlay-card-4-p-1": "Sie können SimpleX mit Ihren eigenen Servern verwenden und trotzdem mit Personen kommunizieren, welche die von uns bereitgestellten und vorkonfigurierten Server verwenden.", - "simplex-unique-card-1-p-1": "SimpleX schützt die Privatsphäre Ihres Profils, Ihrer Kontakte und Metadaten und verbirgt sie vor den SimpleX-Plattform-Servern und allen Beobachtern.", - "simplex-unique-card-1-p-2": "Im Gegensatz zu allen anderen bestehenden Messaging-Plattformen werden den Nutzern von SimpleX keine Kennungen zugewiesen — nicht einmal Zufallszahlen.", - "simplex-unique-card-2-p-1": "Da Sie keine Kennung oder feste Adresse auf der SimpleX-Plattform haben, kann Sie niemand kontaktieren, es sei denn, Sie geben eine einmalige oder vorübergehende Benutzeradresse in Form eines QR-Codes oder Links weiter.", + "simplex-unique-overlay-card-4-p-1": "Sie können SimpleX mit Ihren eigenen Servern verwenden und trotzdem mit Nutzern kommunizieren, welche die vorkonfigurierten Server der App verwenden.", + "simplex-unique-card-1-p-1": "SimpleX schützt die Privatsphäre Ihres Profils, Ihrer Kontakte und Metadaten und verbirgt sie vor den SimpleX-Netzwerk-Servern und weiteren möglichen Beobachtern.", + "simplex-unique-card-1-p-2": "Im Gegensatz zu allen anderen bestehenden Messaging-Netzwerken werden den Nutzern von SimpleX keine Kennungen zugewiesen — nicht einmal Zufallszahlen.", + "simplex-unique-card-2-p-1": "Da Sie keine Kennung oder feste Adresse im SimpleX-Netzwerk haben, kann Sie niemand kontaktieren, es sei denn, Sie geben eine einmalige oder vorübergehende Benutzeradresse in Form eines QR-Codes oder Links weiter.", "simplex-unique-card-3-p-1": "SimpleX speichert Benutzerdaten nur auf den Endgeräten und das in einem portablen, verschlüsselten Datenbankformat — welches auf ein anderes Gerät übertragen werden kann.", "simplex-unique-card-3-p-2": "Die Ende-zu-Ende-verschlüsselten Nachrichten werden vorübergehend auf SimpleX-Relay-Servern gespeichert, bis sie vom Endgerät empfangen und danach endgültig gelöscht werden.", "join": "Nutzen Sie", @@ -142,7 +142,7 @@ "use-this-command": "Benutzen Sie dieses Kommando:", "see-simplex-chat": "Siehe SimpleX-Chat", "github-repository": "GitHub-Repository", - "the-instructions--source-code": "Die Anleitung, wie Sie es herunterladen und aus dem Quellcode kompilieren.", + "the-instructions--source-code": "Für die Anleitungen, wie Sie es herunterladen oder aus dem Quellcode kompilieren.", "if-you-already-installed": "Wenn Sie es schon installiert haben", "simplex-chat-for-the-terminal": "SimpleX Chat für das Terminal", "privacy-matters-section-header": "Warum es auf Privatsphäre ankommt", @@ -171,13 +171,13 @@ "comparison-section-list-point-2": "DNS-basierte Adressen", "comparison-section-list-point-3": "Öffentlicher Schlüssel oder eine andere weltweit eindeutige ID", "comparison-section-list-point-4": "Wenn die Server des Betreibers kompromittiert werden. In Signal und weiteren Apps kann der Sicherheitscode überprüft werden, um dies zu entschärfen", - "comparison-section-list-point-6": "P2P sind zwar verteilt, aber nicht föderiert - sie arbeiten als ein einziges Netzwerk", + "comparison-section-list-point-6": "P2P sind zwar verteilt, aber nicht föderiert — sie arbeiten als ein einziges Netzwerk", "comparison-section-list-point-7": "P2P-Netzwerke haben entweder eine zentrale Verwaltung oder das gesamte Netzwerk kann kompromittiert werden", "see-here": "Siehe hier", - "simplex-unique-card-4-p-1": "Das SimpleX-Netzwerk ist vollständig dezentralisiert und unabhängig von Kryptowährungen oder anderen Plattformen außer dem Internet.", + "simplex-unique-card-4-p-1": "Das SimpleX-Netzwerk ist vollständig dezentralisiert und unabhängig von Kryptowährungen oder anderen Netzwerken außer dem Internet.", "privacy-matters-overlay-card-2-p-1": "Vor nicht allzu langer Zeit beobachteten wir, wie große Wahlen von einem angesehenen Beratungsunternehmen manipuliert wurden, welches unsere sozialen Graphen nutzte, um unsere Sicht auf die reale Welt zu verzerren und unsere Stimmen zu manipulieren.", "privacy-matters-overlay-card-3-p-2": "Eine der schockierendsten Geschichten ist die Erfahrung von Mohamedou Ould Salahi, welche in seinen Memoiren beschrieben und im Film „The Mauritanian“ gezeigt wird. Er kam nach einem Anruf bei seinen Verwandten in Afghanistan und ohne Gerichtsverfahren in das Guantanamo-Lager und wurde dort einige Jahre lang gefoltert, weil er verdächtigt wurde, an den 9/11-Angriffen beteiligt gewesen zu sein, obwohl er die vorhergehenden 10 Jahre in Deutschland gelebt hatte.", - "simplex-unique-overlay-card-1-p-1": "Im Gegensatz zu anderen Nachrichten-Plattformen weist SimpleX den Benutzern keine Kennungen zu. Es verlässt sich nicht auf Telefonnummern, domänenbasierte Adressen (wie E-Mail oder XMPP), Benutzernamen, öffentliche Schlüssel oder sogar Zufallszahlen, um seine Benutzer zu identifizieren — Wir wissen nicht, wie viele Personen unsere SimpleX-Server verwenden.", + "simplex-unique-overlay-card-1-p-1": "Im Gegensatz zu anderen Nachrichten-Netzwerken weist SimpleX den Benutzern keine Kennungen zu. Es verlässt sich nicht auf Telefonnummern, domänenbasierte Adressen (wie E-Mail oder XMPP), Benutzernamen, öffentliche Schlüssel oder Zufallszahlen, um seine Benutzer zu identifizieren — selbst SimpleX-Server-Betreiber wissen nicht, wie viele Personen deren Server verwenden.", "simplex-unique-overlay-card-1-p-2": "Um Nachrichten auszuliefern nutzt SimpleX paarweise anonyme Adressen aus unidirektionalen Nachrichten-Warteschlangen, die für empfangene und gesendete Nachrichten separiert sind und gewöhnlich über verschiedene Server gesendet werden.", "simplex-network-overlay-card-1-li-5": "Alle bekannten P2P-Netzwerke können anfällig für Sybil-Angriffe sein, da jeder Knoten ermittelbar ist und das Netzwerk als Ganzes funktioniert. Bekannte Maßnahmen zur Verhinderung erfordern entweder eine zentralisierte Komponente oder einen teuren Ausführungsnachweis. Das SimpleX-Netzwerk bietet keine Ermittlung der Server, ist fragmentiert und arbeitet mit mehreren isolierten Subnetzwerken, wodurch netzwerkweite Angriffe unmöglich werden.", "simplex-network-overlay-card-1-li-3": "P2P löst nicht das Problem des MITM-Angriffs und die meisten bestehenden Implementierungen nutzen für den initialen Schlüsselaustausch keine Out-of-Band-Nachrichten. Im Gegensatz hierzu nutzt SimpleX für den initialen Schlüsselaustausch Out-of-Band-Nachrichten oder zum Teil schon bestehende sichere und vertrauenswürdige Verbindungen.", @@ -196,14 +196,14 @@ "comparison-section-list-point-5": "Die Privatsphäre-Metadaten des Nutzers werden nicht geschützt", "simplex-network-overlay-card-1-li-1": "P2P-Netzwerke vertrauen auf Varianten von DHT, um Nachrichten zu routen. DHT-Designs müssen zwischen Zustellungsgarantie und Latenz ausgleichen. Verglichen mit P2P bietet SimpleX sowohl eine bessere Zustellungsgarantie als auch eine niedrigere Latenz, weil eine Nachricht redundant und parallel über mehrere Server gesendet werden kann, wobei die durch den Empfänger ausgewählten Server genutzt werden. In P2P-Netzwerken werden Nachrichten sequentiell über O(log N)-Knoten gesendet, wobei die Knoten durch einen Algorithmus ausgewählt werden.", "simplex-unique-overlay-card-3-p-4": "Zwischen dem gesendeten und empfangenen Serververkehr gibt es keine gemeinsamen Kennungen oder Chiffriertexte — sodass ein Beobachter nicht ohne weiteres feststellen kann, wer mit wem kommuniziert, selbst wenn TLS kompromittiert wurde.", - "simplex-unique-overlay-card-4-p-3": "Wenn Sie darüber nachdenken, für die SimpleX-Plattform entwickeln zu wollen, z.B. einen Chatbot für SimpleX-App-Nutzer oder die Integration der SimpleX-Chat-Bibliothek in Ihre mobilen Apps, kontaktieren Sie uns bitte für eine weitere Beratung und Unterstützung.", - "privacy-matters-overlay-card-1-p-4": "Die SimpleX-Plattform schützt die Privatsphäre Ihrer Verbindungen besser als jede Alternative und verhindert vollständig, dass Ihr sozialer Graph für Unternehmen oder Organisationen verfügbar wird. Selbst wenn die Anwender SimpleX-Chat-Server verwenden, kennen wir die Anzahl der Benutzer oder ihre Verbindungen nicht.", + "simplex-unique-overlay-card-4-p-3": "Falls Sie Interesse daran haben, aktiv bei der Entwicklung des SimpleX-Netzwerks mitzuhelfen, z.B. einen Chatbot für SimpleX-App-Nutzer zu entwickeln oder die Integration der SimpleX-Chat-Bibliothek in mobile Apps voranzutreiben, kontaktieren Sie uns bitte für eine weitere Beratung und Unterstützung.", + "privacy-matters-overlay-card-1-p-4": "Das SimpleX-Netzwerk schützt die Privatsphäre Ihrer Verbindungen besser als jede Alternative und verhindert vollständig, dass Ihr sozialer Graph für Unternehmen oder Organisationen verfügbar wird. Selbst wenn Anwender die in der SimpleX-Chat-App vorkonfigurierten Server verwenden, kennen die Server-Betreiber die Anzahl der Benutzer oder deren Verbindungen nicht.", "contact-hero-header": "Sie haben eine Adresse zur Verbindung mit SimpleX Chat erhalten", "invitation-hero-header": "Sie haben einen Einmal-Link zur Verbindung mit SimpleX Chat erhalten", "privacy-matters-overlay-card-3-p-3": "Normale Menschen werden für das, was sie online teilen, sogar unter Nutzung ihrer „anonymen“ Konten, selbst in demokratischen Ländern verhaftet.", "simplex-unique-overlay-card-3-p-1": "SimpleX Chat speichert alle Benutzerdaten ausschließlich auf den Endgeräten in einem portablen und verschlüsselten Datenbankformat, welches exportiert und auf jedes unterstützte Gerät übertragen werden kann.", "simplex-unique-overlay-card-2-p-2": "Auch wenn die optionale Benutzeradresse zum Versenden von Spam-Kontaktanfragen verwendet werden kann, können Sie sie ändern oder ganz löschen, ohne dass Ihre Verbindungen verloren gehen.", - "simplex-unique-overlay-card-4-p-2": "Die SimpleX-Plattform verwendet ein offenes Protokoll und bietet ein SDK zur Erstellung von Chatbots an, welches die Erstellung von Diensten ermöglicht, mit denen Nutzer über SimpleX-Chat interagieren können — Wir sind gespannt, welche SimpleX-Dienste Sie erstellen können.", + "simplex-unique-overlay-card-4-p-2": "Das SimpleX-Netzwerk verwendet ein offenes Protokoll und bietet ein SDK zur Erstellung von Chatbots an. Dies ermöglicht die Erstellung von Diensten, mit denen Nutzer über SimpleX-Chat-Apps interagieren können — wir sind gespannt, welche SimpleX-Dienste Sie entwickeln werden.", "simplex-unique-card-4-p-2": "Sie können SimpleX mit Ihren eigenen Servern oder mit den von uns zur Verfügung gestellten Servern verwenden — und sich trotzdem mit jedem Benutzer verbinden.", "why-simplex-is-unique": "Warum ist SimpleX einmalig", "contact-hero-p-1": "Die öffentlichen Schlüssel und die Adresse der Nachrichtenwarteschlange in diesem Link werden NICHT über das Netzwerk gesendet, wenn Sie diese Seite aufrufen — sie sind in dem Hash-Fragment der Link-URL enthalten.", @@ -218,7 +218,7 @@ "guide-dropdown-8": "App-Einstellungen", "guide-dropdown-9": "Verbindungen herstellen", "guide": "Leitfaden", - "docs-dropdown-1": "SimpleX-Plattform", + "docs-dropdown-1": "SimpleX-Netzwerk", "docs-dropdown-2": "Zugriff auf Android-Dateien", "docs-dropdown-3": "Zugriff auf die Chat-Datenbank", "docs-dropdown-4": "Den SMP-Server hosten", diff --git a/website/langs/hu.json b/website/langs/hu.json index f502291e52..9dfd3d9f65 100644 --- a/website/langs/hu.json +++ b/website/langs/hu.json @@ -14,7 +14,7 @@ "simplex-explained-tab-1-p-1": "Létrehozhat kapcsolatokat és csoportokat, valamint kétirányú beszélgetéseket folytathat, ugyanúgy mint bármely más üzenetváltó-alkalmazásban.", "simplex-explained-tab-1-p-2": "Hogyan működhet egyirányú üzenet-sorballítással és felhasználói profilazonosítók nélkül?", "simplex-explained-tab-2-p-1": "Minden kapcsolathoz két különböző üzenetküldési sorbaállítást használ a különböző kiszolgálókon keresztül történő üzenetküldéshez és -fogadáshoz.", - "simplex-explained-tab-2-p-2": "A kiszolgálók csak egyirányú üzeneteket továbbítanak, anélkül, hogy teljes képet kapnának a felhasználók beszélgetéseiről vagy kapcsolatairól.", + "simplex-explained-tab-2-p-2": "A kiszolgálók csak egyetlen irányba továbbítják az üzeneteket, anélkül, hogy teljes képet kapnának a felhasználók beszélgetéseiről vagy kapcsolatairól.", "simplex-explained-tab-3-p-1": "A kiszolgálók minden egyes üzenetsorbaállításhoz külön névtelen hitelesítő-adatokkal rendelkeznek, és nem tudják, hogy melyik felhasználóhoz tartoznak.", "simplex-explained-tab-3-p-2": "A felhasználók tovább fokozhatják a metaadatok adatvédelmét, ha a Tor segítségével férnek hozzá a kiszolgálókhoz, így megakadályozva az IP-cím szerinti korrelációt.", "smp-protocol": "SMP-protokoll", @@ -24,7 +24,7 @@ "simplex-chat-protocol": "A SimpleX Chat-protokoll", "terminal-cli": "Terminál CLI", "terms-and-privacy-policy": "Adatvédelmi irányelvek", - "hero-header": "Újradefiniált adatvédelem", + "hero-header": "Újraértelmezett adatvédelem", "hero-subheader": "Az első üzenetváltó-alkalmazás
felhasználói azonosítók nélkül", "hero-p-1": "Más alkalmazások felhasználói azonosítókkal rendelkeznek: Signal, Matrix, Session, Briar, Jami, Cwtch, stb.
A SimpleX azonban nem, még véletlenszerű számokkal sem.
Ez radikálisan javítja az adatvédelmet.", "hero-overlay-1-textlink": "Miért ártanak a felhasználói azonosítók az adatvédelemnek?", @@ -60,7 +60,7 @@ "simplex-private-card-3-point-2": "A kiszolgáló ujjlenyomata és a csatornakötés megakadályozza a MITM- és a visszajátszási támadásokat.", "simplex-private-card-3-point-3": "Az újrakapcsolódás le van tiltva a munkamenet elleni támadások megelőzése érdekében.", "simplex-private-card-4-point-1": "Az IP-címe védelme érdekében a kiszolgálókat a Tor-on vagy más átvitel-átfedő-hálózaton keresztül is elérheti.", - "simplex-private-card-6-point-1": "Számos kommunikációs platform sebezhető a kiszolgálók vagy a hálózat-szolgáltatók MITM-támadásaival szemben.", + "simplex-private-card-6-point-1": "Számos kommunikációs hálózat sebezhető a kiszolgálók vagy a hálózat-szolgáltatók MITM-támadásaival szemben.", "simplex-private-card-6-point-2": "Ennek megakadályozása érdekében a SimpleX-alkalmazások egyszeri kulcsokat adnak át sávon kívül, amikor egy címet hivatkozásként vagy QR-kódként oszt meg.", "simplex-private-card-7-point-1": "Az integritás garantálása érdekében az üzenetek sorszámozással vannak ellátva, és tartalmazzák az előző üzenet hasítóértékét.", "simplex-private-card-7-point-2": "Ha bármilyen üzenetet hozzáadnak, eltávolítanak vagy módosítanak, a címzett értesítést kap róla.", @@ -86,7 +86,7 @@ "simplex-unique-4-title": "Öné a SimpleX-hálózat", "simplex-unique-4-overlay-1-title": "Teljesen decentralizált — a SimpleX-hálózat a felhasználóké", "hero-overlay-card-1-p-1": "Sok felhasználó kérdezte: ha a SimpleXnek nincsenek felhasználói azonosítói, honnan tudja, hogy hová kell eljuttatni az üzeneteket?", - "hero-overlay-card-1-p-2": "Az üzenetek kézbesítéséhez az összes többi platform által használt felhasználói azonosítók helyett a SimpleX az üzenetek sorbaállításához ideiglenes, névtelen, páros azonosítókat használ, külön-külön minden egyes kapcsolathoz — nincsenek hosszú távú azonosítók.", + "hero-overlay-card-1-p-2": "Az üzenetek kézbesítéséhez az összes többi hálózat által használt felhasználói azonosítók helyett a SimpleX az üzenetek sorbaállításához ideiglenes, névtelen, páros azonosítókat használ, külön-külön minden egyes kapcsolathoz — nincsenek hosszú távú azonosítók.", "hero-overlay-card-1-p-4": "Ez a kialakítás megakadályozza a felhasználók metaadatainak kiszivárgását az alkalmazás szintjén. Az adatvédelem további javítása és az IP-cím védelme érdekében az üzenetküldő kiszolgálókhoz Tor hálózaton keresztül is kapcsolódhat.", "hero-overlay-card-1-p-5": "Csak a kliensek tárolják a felhasználói profilokat, kapcsolatokat és csoportokat; az üzenetek küldése 2 rétegű végpontok közötti titkosítással történik.", "hero-overlay-card-1-p-6": "További leírást a SimpleX ismertetőben olvashat.", @@ -104,32 +104,32 @@ "privacy-matters-overlay-card-1-p-1": "Sok nagyvállalat arra használja fel az önnel kapcsolatban álló személyek adatait, hogy megbecsülje az ön jövedelmét, hogy olyan termékeket adjon el önnek, amelyekre valójában nincs is szüksége, és hogy meghatározza az árakat.", "privacy-matters-overlay-card-1-p-2": "Az online kiskereskedők tudják, hogy az alacsonyabb jövedelműek nagyobb valószínűséggel vásárolnak azonnal, ezért magasabb árakat számíthatnak fel, vagy eltörölhetik a kedvezményeket.", "privacy-matters-overlay-card-1-p-3": "Egyes pénzügyi és biztosítótársaságok szociális grafikonokat használnak a kamatlábak és a díjak meghatározásához. Ez gyakran arra készteti az alacsonyabb jövedelmű embereket, hogy többet fizessenek — ez az úgynevezett „szegénységi prémium”.", - "privacy-matters-overlay-card-1-p-4": "A SimpleX-platform minden alternatívánál jobban védi a kapcsolatainak adatait, teljes mértékben megakadályozva, hogy a ismeretségi-hálója bármilyen vállalat vagy szervezet számára elérhetővé váljon. Még ha az emberek a SimpleX Chat által biztosított kiszolgálókat is használják, sem a felhasználók számát, sem a kapcsolataikat nem ismerjük.", + "privacy-matters-overlay-card-1-p-4": "A SimpleX-hálózat minden alternatívánál jobban védi a kapcsolatainak adatait, teljes mértékben megakadályozva, hogy az ismeretségi-hálója bármilyen vállalat vagy szervezet számára elérhetővé váljon. Még ha az emberek a SimpleX Chat által előre beállított kiszolgálókat is használják, sem az alkalmazások, sem a kiszolgálók üzemeltetői nem ismerik, sem felhasználók számát, sem a kapcsolataikat.", "privacy-matters-overlay-card-2-p-1": "Nem is olyan régen megfigyelhettük, hogy a nagy választásokat manipulálta egy neves tanácsadó cég, amely az ismeretségi-háló segítségével eltorzította a valós világról alkotott képünket, és manipulálta a szavazatainkat.", - "privacy-matters-overlay-card-2-p-2": "Ahhoz, hogy objektív legyen és független döntéseket tudjon hozni, az információs terét is kézben kell tartania. Ez csak akkor lehetséges, ha privát kommunikációs platformot használ, amely nem fér hozzá az ismeretségi-hálójához.", - "privacy-matters-overlay-card-2-p-3": "A SimpleX az első olyan platform, amely eleve nem rendelkezik felhasználói azonosítókkal, így jobban védi az ismeretségi-hálóját, mint bármely ismert alternatíva.", + "privacy-matters-overlay-card-2-p-2": "Ahhoz, hogy objektív legyen és független döntéseket tudjon hozni, az információs terét is kézben kell tartania. Ez csak akkor lehetséges, ha privát kommunikációs hálózatot használ, amely nem fér hozzá az ismeretségi-hálójához.", + "privacy-matters-overlay-card-2-p-3": "A SimpleX az első olyan hálózat, amely eleve nem rendelkezik felhasználói azonosítókkal, így jobban védi az ismeretségi-hálóját, mint bármely ismert alternatíva.", "privacy-matters-overlay-card-3-p-1": "Mindenkinek törődnie kell a magánélet és a kommunikáció biztonságával — az ártalmatlan beszélgetések veszélybe sodorhatják, még akkor is, ha nincs semmi rejtegetnivalója.", "privacy-matters-overlay-card-3-p-2": "Az egyik legmegdöbbentőbb a Mohamedou Ould Salahi memoárjában leírt és az „A mauritániai” c. filmben bemutatott történet. Őt bírósági tárgyalás nélkül a guantánamói táborba zárták, és ott kínozták 15 éven át, miután egy afganisztáni rokonát telefonon felhívta, akit azzal gyanúsítottak a hatóságok, hogy köze van a 9/11-es merényletekhez, holott Salahi az előző 10 évben Németországban élt.", "privacy-matters-overlay-card-3-p-3": "Átlagos embereket letartóztatnak azért, amit online megosztanak, még „névtelen” fiókjaikon keresztül is, még demokratikus országokban is.", "privacy-matters-overlay-card-3-p-4": "Nem elég csak egy végpontok között titkosított üzenetváltó-alkalmazást használnunk, mindannyiunknak olyan üzenetváltó-alkalmazásokat kell használnunk, amelyek védik a személyes partnereink magánéletét — akikkel kapcsolatban állunk.", - "simplex-unique-overlay-card-1-p-1": "Más üzenetküldő platformoktól eltérően a SimpleX nem rendel azonosítókat a felhasználókhoz. Nem támaszkodik telefonszámokra, tartomány-alapú címekre (mint az e-mail, XMPP vagy a Matrix), felhasználónevekre, nyilvános kulcsokra vagy akár véletlenszerű számokra a felhasználók azonosításához — nem tudjuk, hogy hányan használják a SimpleX-kiszolgálóinkat.", + "simplex-unique-overlay-card-1-p-1": "Más üzenetküldő hálózatoktól eltérően a SimpleX nem rendel azonosítókat a felhasználókhoz. Nem támaszkodik telefonszámokra, tartomány-alapú címekre (mint az e-mail, XMPP vagy a Matrix), felhasználónevekre, nyilvános kulcsokra vagy akár véletlenszerű számokra a felhasználók azonosításához — a SimpleX-kiszolgálók üzemeltetői nem tudják, hogy hányan használják a kiszolgálóikat.", "simplex-unique-overlay-card-1-p-2": "Az üzenetek kézbesítéséhez a SimpleX az egyirányú üzenet várakoztatást használ páronkénti névtelen címekkel, külön a fogadott és külön az elküldött üzenetek számára, általában különböző kiszolgálókon keresztül.", - "simplex-unique-overlay-card-1-p-3": "Ez a kialakítás megvédi annak titkosságát, hogy kivel kommunikál, elrejtve azt a SimpleX-platform kiszolgálói és a megfigyelők elől. IP-címének a kiszolgálók elől való elrejtéséhez azt teheti meg, hogy Toron keresztül kapcsolódik a SimpleX-kiszolgálókhoz.", - "simplex-unique-overlay-card-2-p-1": "Mivel ön nem rendelkezik azonosítóval a SimpleX-platformon, senki sem tud kapcsolatba lépni önnel, hacsak nem oszt meg egy egyszeri vagy ideiglenes felhasználói címet, például QR-kódot vagy hivatkozást.", + "simplex-unique-overlay-card-1-p-3": "Ez a kialakítás megvédi annak titkosságát, hogy kivel kommunikál, elrejtve azt a SimpleX-hálózat kiszolgálói és a megfigyelők elől. IP-címének a kiszolgálók elől való elrejtéséhez azt teheti meg, hogy Toron keresztül kapcsolódik a SimpleX-kiszolgálókhoz.", + "simplex-unique-overlay-card-2-p-1": "Mivel ön nem rendelkezik azonosítóval a SimpleX-hálózaton, senki sem tud kapcsolatba lépni önnel, hacsak nem oszt meg egy egyszeri vagy ideiglenes felhasználói címet, például QR-kódot vagy hivatkozást.", "simplex-unique-overlay-card-2-p-2": "Még a felhasználói cím használata esetén is, aminek használata nem kötelező – ugyanakkor ez a kéretlen kapcsolatkérelmek küldésére is használható – módosíthatja vagy teljesen törölheti anélkül, hogy elveszítené a meglévő kapcsolatait.", "simplex-unique-overlay-card-3-p-1": "A SimpleX Chat az összes felhasználói adatot kizárólag a klienseken tárolja egy hordozható titkosított adatbázis-formátumban, amely exportálható és átvihető bármely más támogatott eszközre.", "simplex-unique-overlay-card-3-p-2": "A végpontok között titkosított üzenetek átmenetileg a SimpleX továbbítókiszolgálóin tartózkodnak, amíg be nem érkeznek a címzetthez, majd automatikusan véglegesen törlődnek onnan.", "simplex-unique-overlay-card-3-p-3": "A föderált hálózatok kiszolgálóitól (e-mail, XMPP vagy Matrix) eltérően a SimpleX-kiszolgálók nem tárolják a felhasználói fiókokat, csak továbbítják az üzeneteket, így védve mindkét fél magánéletét.", "simplex-unique-overlay-card-3-p-4": "A küldött és a fogadott kiszolgálóforgalom között nincsenek közös azonosítók vagy titkosított szövegek — ha bárki megfigyeli, nem tudja könnyen megállapítani, hogy ki kivel kommunikál, még akkor sem, ha a TLS-t kompromittálják.", - "simplex-unique-overlay-card-4-p-1": "Használhatja a SimpleXet a saját kiszolgálóival, és továbbra is kommunikálhat azokkal, akik az általunk biztosított, előre konfigurált kiszolgálókat használják.", - "simplex-unique-overlay-card-4-p-2": "A SimpleX-platform nyitott protokollt használ és SDK-t biztosít a chatbotok létrehozásához, lehetővé téve olyan szolgáltatások megvalósítását, amelyekkel a felhasználók a SimpleX Chat alkalmazásokon keresztül léphetnek kapcsolatba — mi már nagyon várjuk, hogy milyen SimpleX szolgáltatásokat készítenek a lelkes közreműködők.", - "simplex-unique-overlay-card-4-p-3": "Ha a SimpleX-platformra való fejlesztést fontolgatja, például a SimpleX-alkalmazások felhasználóinak szánt chatbotot, vagy a SimpleX Chat könyvtárbotjának integrálását más mobilalkalmazásba, lépjen velünk kapcsolatba, ha bármilyen tanácsot vagy támogatást szeretne kapni.", - "simplex-unique-card-1-p-1": "A SimpleX védi az ön profiljához tartozó kapcsolatokat és metaadatokat, elrejtve azokat a SimpleX-platform kiszolgálói és a megfigyelők elől.", - "simplex-unique-card-1-p-2": "Minden más létező üzenetküldő platformtól eltérően a SimpleX nem rendelkezik a felhasználókhoz rendelt azonosítókkal — még véletlenszerű számokkal sem.", - "simplex-unique-card-2-p-1": "Mivel a SimpleX-platformon nincs azonosítója vagy állandó címe, senki sem tud kapcsolatba lépni önnel, hacsak nem oszt meg egy egyszeri vagy ideiglenes felhasználói címet, például QR-kódot vagy hivatkozást.", + "simplex-unique-overlay-card-4-p-1": "Használhatja a SimpleXet a saját kiszolgálóival, és továbbra is kommunikálhat azokkal, akik az előre beállított kiszolgálókat használják az alkalmazásban.", + "simplex-unique-overlay-card-4-p-2": "A SimpleX-hálózat nyitott protokollt használ és SDK-t biztosít a chatbotok létrehozásához, lehetővé téve olyan szolgáltatások megvalósítását, amelyekkel a felhasználók a SimpleX Chat alkalmazásokon keresztül léphetnek kapcsolatba — mi már nagyon várjuk, hogy milyen SimpleX szolgáltatásokat készítenek a lelkes közreműködők.", + "simplex-unique-overlay-card-4-p-3": "Ha a SimpleX-hálózatra való fejlesztést fontolgatja, például a SimpleX-alkalmazások felhasználóinak szánt chatbotot, vagy a SimpleX Chat könyvtárbotjának integrálását más mobilalkalmazásba, lépjen velünk kapcsolatba, ha bármilyen tanácsot vagy támogatást szeretne kapni.", + "simplex-unique-card-1-p-1": "A SimpleX megvédi a profilhoz tartozó kapcsolatokat és metaadatokat, elrejtve azokat a SimpleX-hálózat kiszolgálói és a megfigyelők elől.", + "simplex-unique-card-1-p-2": "Minden más létező üzenetküldő hálózattól eltérően a SimpleX nem rendelkezik a felhasználókhoz rendelt azonosítókkal — még véletlenszerű számokkal sem.", + "simplex-unique-card-2-p-1": "Mivel a SimpleX-hálózaton nincs azonosítója vagy állandó címe, senki sem tud kapcsolatba lépni önnel, hacsak nem oszt meg egy egyszeri vagy ideiglenes felhasználói címet, például QR-kódot vagy hivatkozást.", "simplex-unique-card-3-p-1": "A SimpleX Chat az összes felhasználói adatot kizárólag a klienseken tárolja egy hordozható titkosított adatbázis-formátumban —, amely exportálható és átvihető bármely más támogatott eszközre.", "simplex-unique-card-3-p-2": "A végpontok között titkosított üzenetek átmenetileg a SimpleX továbbítókiszolgálóin tartózkodnak, amíg be nem érkeznek a címzetthez, majd automatikusan véglegesen törlődnek onnan.", - "simplex-unique-card-4-p-1": "A SimpleX-hálózat teljesen decentralizált és független bármely kriptopénztől vagy bármely más platformtól, kivéve az internetet.", + "simplex-unique-card-4-p-1": "A SimpleX-hálózat teljesen decentralizált és független bármely kriptopénztől vagy bármely más hálózattól, kivéve az internetet.", "simplex-unique-card-4-p-2": "Használhatja a SimpleXet a saját kiszolgálóival vagy az általunk biztosított kiszolgálókkal, és továbbra is kapcsolódhat bármely felhasználóhoz.", "join": "Csatlakozzon a közösségeinkhez", "we-invite-you-to-join-the-conversation": "Meghívjuk Önt, hogy csatlakozzon a beszélgetésekhez", @@ -138,8 +138,8 @@ "donate-here-to-help-us": "Adományozzon és segítsen nekünk", "sign-up-to-receive-our-updates": "Regisztráljon a hírleveleinkre, hogy ne maradjon le semmiről", "enter-your-email-address": "Adja meg az e-mail-címét", - "get-simplex": "A SimpleX számítógép-alkalmazásának letöltése", - "why-simplex-is-unique": "A SimpleX mitől egyedülálló", + "get-simplex": "A SimpleX számítógépes alkalmazásának letöltése", + "why-simplex-is-unique": "Mitől egyedülálló a SimpleX", "learn-more": "Tudjon meg többet", "more-info": "További információ", "hide-info": "Információ elrejtése", @@ -165,7 +165,7 @@ "copy-the-command-below-text": "másolja be az alábbi parancsot, és használja a csevegésben:", "privacy-matters-section-header": "Miért számít az adatvédelem", "privacy-matters-section-subheader": "A metaadatok védelmének megőrzése — kivel beszélget — megvédi a következőktől:", - "privacy-matters-section-label": "Győződjön meg arról, hogy az üzenetváltó-alkalmazás amit használ nem fér hozzá az adataidhoz!", + "privacy-matters-section-label": "Győződjön meg arról, hogy az üzenetváltó-alkalmazás amit használ nem fér hozzá az adataihoz!", "simplex-private-section-header": "Mitől lesz a SimpleX privát", "simplex-network-section-header": "SimpleX-hálózat", "simplex-network-section-desc": "A Simplex Chat a P2P- és a föderált hálózatok előnyeinek kombinálásával biztosítja a legjobb adatvédelmet.", @@ -194,7 +194,7 @@ "comparison-section-list-point-4a": "A SimpleX továbbítókiszolgálói nem veszélyeztethetik az e2e titkosítást. Hitelesítse a biztonsági kódot a sávon kívüli csatorna elleni támadások veszélyeinek csökkentésére", "comparison-section-list-point-4": "Ha az üzemeltetett kiszolgálók veszélybe kerülnek. Hitelesítse a biztonsági kódot a Signal vagy más biztonságos üzenetküldő alkalmazás segítségével a támadások veszélyeinek csökkentésére", "comparison-section-list-point-5": "Nem védi a felhasználók metaadatait", - "comparison-section-list-point-6": "Bár a P2P elosztott, de nem föderált – egyetlen hálózatként működnek", + "comparison-section-list-point-6": "Bár a P2P elosztott, de nem föderált — egyetlen hálózatként működnek", "comparison-section-list-point-7": "A P2P-hálózatoknak vagy van egy központi hitelesítője, vagy az egész hálózat kompromittálódhat", "see-here": "tekintse meg itt", "guide-dropdown-1": "Gyors indítás", @@ -206,7 +206,7 @@ "guide-dropdown-7": "Adatvédelem és biztonság", "guide-dropdown-8": "Alkalmazás beállításai", "guide": "Útmutató", - "docs-dropdown-1": "SimpleX-platform", + "docs-dropdown-1": "SimpleX-hálózat", "docs-dropdown-2": "Android fájlok elérése", "docs-dropdown-3": "Hozzáférés a csevegési adatbázishoz", "docs-dropdown-8": "SimpleX jegyzékszolgáltatás", @@ -222,7 +222,7 @@ "please-use-link-in-mobile-app": "Használja a mobilalkalmazásban található hivatkozást", "contact-hero-header": "Kapott egy meghívót a SimpleX Chaten való beszélgetéshez", "invitation-hero-header": "Kapott egy egyszer használható meghívót a SimpleX Chaten való beszélgetéshez", - "simplex-network-overlay-card-1-li-4": "A P2P-megvalósításokat egyes internetszolgáltatók blokkolhatják (mint például a BitTorrent). A SimpleX átvitel-független - a szabványos webes protokollokon, pl. WebSocketsen keresztül is működik.", + "simplex-network-overlay-card-1-li-4": "A P2P-megvalósításokat egyes internetszolgáltatók blokkolhatják (mint például a BitTorrent). A SimpleX átvitel-független — a szabványos webes protokollokon, például WebSocketsen keresztül is működik.", "simplex-private-card-4-point-2": "A SimpleX Tor-on keresztüli használatához telepítse az Orbot alkalmazást és engedélyezze a SOCKS5 proxyt (vagy a VPN-t az iOS-ban).", "simplex-private-card-5-point-1": "A SimpleX minden titkosítási réteghez tartalomkitöltést használ, hogy meghiúsítsa az üzenetméret ellen irányuló támadásokat.", "simplex-private-card-5-point-2": "A kiszolgálók és a hálózatot megfigyelők számára a különböző méretű üzenetek egyformának tűnnek.", diff --git a/website/langs/it.json b/website/langs/it.json index 032706ebab..18a47bfe9f 100644 --- a/website/langs/it.json +++ b/website/langs/it.json @@ -60,23 +60,23 @@ "hero-overlay-card-2-p-2": "Potrebbero quindi correlare queste informazioni con i social network pubblici esistenti e determinare alcune identità reali.", "hero-overlay-card-2-p-4": "SimpleX protegge da questi attacchi non avendo alcun ID utente per design. Inoltre, se usi la modalità di modalità in incognito, il tuo nome mostrato sarà diverso per ogni contatto, evitando dati condivisi tra di loro.", "simplex-network-overlay-card-1-li-2": "Il design di SimpleX, a differenza della maggior parte delle reti P2P, non ha identificatori utente globali di alcun tipo, nemmeno temporanei, e usa solo identificatori temporanei a coppie, garantendo una maggiore protezione dell'anonimato e dei metadati.", - "simplex-network-overlay-card-1-li-4": "Le implementazioni P2P possono essere bloccate da alcuni fornitori di internet (come BitTorrent). SimpleX è indipendente dal trasporto - può funzionare su protocolli web standard, es. WebSocket.", + "simplex-network-overlay-card-1-li-4": "Le implementazioni P2P possono essere bloccate da alcuni fornitori di internet (come BitTorrent). SimpleX è indipendente dal trasporto — può funzionare su protocolli web standard, es. WebSocket.", "hero-overlay-card-2-p-1": "Quando gli utenti hanno identità permanenti, anche se si tratta solo di un numero casuale, come un Session ID, c'è il rischio che il fornitore o un malintenzionato possano osservare come gli utenti sono connessi e quanti messaggi inviano.", "simplex-network-overlay-card-1-li-6": "Le reti P2P possono essere vulnerabili all'attacco DRDoS, quando i client possono ritrasmettere e amplificare il traffico, con conseguente \"denial of service\" a livello di rete. I client SimpleX si limitano a inoltrare il traffico da una connessione nota e non possono essere usati da un aggressore per amplificare il traffico nell'intera rete.", - "privacy-matters-overlay-card-1-p-4": "La piattaforma SimpleX protegge la privacy delle tue connessioni meglio di qualsiasi alternativa, impedendo completamente che il tuo grafico sociale sia disponibile a qualsiasi azienda o organizzazione. Anche quando le persone usano i server forniti da SimpleX Chat, non conosciamo il numero di utenti o le loro connessioni.", - "privacy-matters-overlay-card-2-p-3": "SimpleX è la prima piattaforma che non ha alcun identificatore utente per design, proteggendo così il tuo grafico delle connessioni meglio di qualsiasi alternativa conosciuta.", + "privacy-matters-overlay-card-1-p-4": "La rete di SimpleX protegge la privacy delle tue connessioni meglio di qualsiasi alternativa, impedendo completamente che il tuo grafico sociale sia disponibile a qualsiasi azienda o organizzazione. Anche quando le persone usano i server preconfigurati in SimpleX Chat, gli operatori dei server non conoscono il numero di utenti o le loro connessioni.", + "privacy-matters-overlay-card-2-p-3": "SimpleX è la prima rete che non ha alcun identificatore utente per design, proteggendo così il tuo grafico delle connessioni meglio di qualsiasi alternativa conosciuta.", "privacy-matters-overlay-card-3-p-1": "Tutti dovrebbero preoccuparsi della privacy e della sicurezza delle proprie comunicazioni — conversazioni innocue possono metterti in pericolo, anche se non hai nulla da nascondere.", "privacy-matters-overlay-card-3-p-3": "Le persone comuni vengono arrestate per ciò che condividono online, anche tramite i loro account \"anonimi\", anche nei Paesi democratici.", - "simplex-unique-overlay-card-1-p-3": "Questo design protegge la privacy di chi stai comunicando, nascondendola ai server della piattaforma SimpleX e a qualsiasi osservatore. Per nascondere il tuo indirizzo IP ai server, puoi connetterti ai server SimpleX tramite Tor.", - "simplex-unique-overlay-card-2-p-1": "Poiché non hai alcun identificatore sulla piattaforma SimpleX, nessuno può contattarti a meno che tu non condivida un indirizzo utente una tantum o temporaneo, come un codice QR o un link.", + "simplex-unique-overlay-card-1-p-3": "Questo design protegge la privacy di chi stai comunicando, nascondendola ai server della rete SimpleX e a qualsiasi osservatore. Per nascondere il tuo indirizzo IP ai server, puoi connetterti ai server SimpleX tramite Tor.", + "simplex-unique-overlay-card-2-p-1": "Poiché non hai alcun identificatore sulla rete SimpleX, nessuno può contattarti a meno che tu non condivida un indirizzo utente una tantum o temporaneo, come un codice QR o un link.", "simplex-unique-overlay-card-2-p-2": "Anche l'indirizzo utente opzionale, che può essere usato per inviare richieste di contatto spam, è possibile modificarlo o eliminarlo completamente senza perdere alcuna connessione.", "simplex-unique-overlay-card-3-p-1": "SimpleX Chat conserva tutti i dati utente solo sui dispositivi client usando un formato trasferibile di database crittografato che può essere esportato e trasferito su qualsiasi dispositivo supportato.", "simplex-unique-overlay-card-3-p-2": "I messaggi crittografati end-to-end vengono conservati temporaneamente sui server di inoltro SimpleX fino alla ricezione, quindi vengono eliminati definitivamente.", - "simplex-unique-overlay-card-4-p-1": "Puoi usare SimpleX con i tuoi server personali e continuare a comunicare con le persone che usano i server preconfigurati forniti da noi.", - "simplex-unique-overlay-card-4-p-3": "Se stai pensando di sviluppare per la piattaforma SimpleX, ad esempio, il chat bot per gli utenti dell'app SimpleX o l'integrazione della libreria SimpleX Chat nelle tue app mobili, contattaci per qualsiasi consiglio e supporto.", - "simplex-unique-card-1-p-1": "SimpleX protegge la privacy del tuo profilo, contatti e metadati, nascondendoli ai server della piattaforma SimpleX e ad eventuali osservatori.", - "simplex-unique-card-1-p-2": "A differenza di qualsiasi altra piattaforma di messaggistica esistente, SimpleX non ha identificatori assegnati agli utenti — nemmeno numeri casuali.", - "simplex-unique-card-2-p-1": "Poiché non hai un identificatore o un indirizzo fisso sulla piattaforma SimpleX, nessuno può contattarti a meno che tu non condivida un indirizzo utente una tantum o temporaneo, come codice un QR o un link.", + "simplex-unique-overlay-card-4-p-1": "Puoi usare SimpleX con i tuoi server personali e continuare a comunicare con le persone che usano i server preconfigurati nelle app.", + "simplex-unique-overlay-card-4-p-3": "Se stai pensando di sviluppare per la rete SimpleX, ad esempio, il chat bot per gli utenti dell'app SimpleX o l'integrazione della libreria SimpleX Chat nelle tue app mobili, contattaci per qualsiasi consiglio e supporto.", + "simplex-unique-card-1-p-1": "SimpleX protegge la privacy del tuo profilo, contatti e metadati, nascondendoli ai server della rete SimpleX e ad eventuali osservatori.", + "simplex-unique-card-1-p-2": "A differenza di qualsiasi altra rete di messaggistica esistente, SimpleX non ha identificatori assegnati agli utenti — nemmeno numeri casuali.", + "simplex-unique-card-2-p-1": "Poiché non hai un identificatore o un indirizzo fisso sulla rete SimpleX, nessuno può contattarti a meno che tu non condivida un indirizzo utente una tantum o temporaneo, come codice un QR o un link.", "simplex-unique-card-3-p-1": "SimpleX conserva tutti i dati utente sui dispositivi client in un formato trasferibile di database crittografato — può essere trasferito su un altro dispositivo.", "join": "Unisciti a", "we-invite-you-to-join-the-conversation": "Ti invitiamo a unirti alla conversazione", @@ -102,7 +102,7 @@ "use-this-command": "Usa questo comando:", "see-simplex-chat": "Vedi SimpleX Chat", "github-repository": "Repository GitHub", - "the-instructions--source-code": "le istruzioni su come scaricarlo o compilarlo dal codice sorgente.", + "the-instructions--source-code": "per le istruzioni su come scaricarlo o compilarlo dal codice sorgente.", "if-you-already-installed-simplex-chat-for-the-terminal": "Se hai già installato SimpleX Chat per il terminale", "if-you-already-installed": "Se hai già installato", "privacy-matters-section-subheader": "Preservare la privacy dei tuoi metadati — con chi parli — ti protegge da:", @@ -130,13 +130,13 @@ "no-federated": "No - federato", "comparison-section-list-point-1": "Solitamente si basa su un numero di telefono, in alcuni casi su nomi utente", "comparison-section-list-point-2": "Indirizzi basati su DNS", - "comparison-section-list-point-6": "Sebbene i P2P siano distribuiti, non sono federati - operano come un'unica rete", + "comparison-section-list-point-6": "Sebbene i P2P siano distribuiti, non sono federati — operano come un'unica rete", "comparison-section-list-point-7": "Le reti P2P hanno un'autorità centrale o l'intera rete può essere compromessa", "see-here": "vedi qui", "simplex-network-3-header": "Nella rete di SimpleX", "simplex-private-card-7-point-2": "Se un messaggio viene aggiunto, rimosso o modificato, il destinatario verrà avvisato.", - "hero-overlay-card-1-p-2": "Per consegnare i messaggi, invece degli ID utente utilizzati da tutte le altre piattaforme, SimpleX usa identificatori temporanei anonimi a coppie delle code di messaggi, separati per ciascuna delle tue connessioni — non ci sono identificatori a lungo termine.", - "simplex-private-card-6-point-1": "Molte piattaforme di comunicazione sono vulnerabili agli attacchi MITM da parte di server o fornitori di rete.", + "hero-overlay-card-1-p-2": "Per consegnare i messaggi, invece degli ID utente utilizzati da tutte le altre reti, SimpleX usa identificatori temporanei anonimi a coppie delle code di messaggi, separati per ciascuna delle tue connessioni — non ci sono identificatori a lungo termine.", + "simplex-private-card-6-point-1": "Molte reti di comunicazione sono vulnerabili agli attacchi MITM da parte di server o fornitori di rete.", "simplex-private-card-7-point-1": "Per garantire l'integrità, i messaggi sono numerati in sequenza e includono l'hash del messaggio precedente.", "simplex-private-card-9-point-2": "Riduce i vettori di attacco, rispetto ai broker di messaggi tradizionali, e i metadati disponibili.", "simplex-private-card-10-point-2": "Ciò consente di recapitare messaggi senza identificatori del profilo utente, garantendo una migliore privacy dei metadati rispetto alle alternative.", @@ -161,7 +161,7 @@ "feature-3-title": "Gruppi decentralizzati crittografati E2E — solo gli utenti sanno che esistono", "blog": "Blog", "simplex-explained-tab-2-p-1": "Per ogni connessione usi due code di messaggi distinte per inviare e ricevere i messaggi attraverso server diversi.", - "simplex-explained-tab-2-p-2": "I server passano i messaggi solo in una direzione, senza avere il quadro completo della conversazione dell'utente o delle connessioni.", + "simplex-explained-tab-2-p-2": "I server passano i messaggi solo in una direzione, senza avere il quadro completo delle conversazioni dell'utente o delle connessioni.", "simplex-explained-tab-3-p-2": "Gli utenti possono aumentare ulteriormente la privacy dei metadati usando Tor per accedere ai server, evitando correlazioni per indirizzo IP.", "smp-protocol": "Protocollo SMP", "feature-1-title": "Messaggi crittografati E2E con markdown e modifica", @@ -181,21 +181,21 @@ "privacy-matters-overlay-card-1-p-2": "I rivenditori online sanno che le persone con redditi più bassi sono più propense a fare acquisti urgenti, quindi possono applicare prezzi più alti o rimuovere sconti.", "privacy-matters-overlay-card-1-p-3": "Alcune società finanziarie e assicurative usano grafici sociali per determinare i tassi di interesse e i premi. Spesso ciò fa pagare di più le persone con redditi più bassi — è noto come \"premio di povertà\" .", "privacy-matters-overlay-card-2-p-1": "Non molto tempo fa abbiamo assistito alla manipolazione delle principali elezioni da una rispettabile società di consulenza che ha usato i nostri grafici sociali per distorcere la nostra visione del mondo reale e manipolare i nostri voti.", - "privacy-matters-overlay-card-2-p-2": "Per essere obiettivi e prendere decisioni indipendenti devi avere il controllo del tuo spazio informativo. È possibile solo se utilizzi una piattaforma di comunicazione privata che non ha accesso al tuo grafico sociale.", + "privacy-matters-overlay-card-2-p-2": "Per essere obiettivi e prendere decisioni indipendenti devi avere il controllo del tuo spazio informativo. È possibile solo se utilizzi una rete di comunicazione privata che non ha accesso al tuo grafico sociale.", "privacy-matters-overlay-card-3-p-2": "Una delle storie più scioccanti è l'esperienza di Mohamedou Ould Salahi descritta nel suo libro di memorie e mostrata nel film The Mauritanian. È stato rinchiuso nel campo di Guantánamo, senza processo, e lì è stato torturato per 15 anni dopo una telefonata a un suo parente in Afghanistan, sospettato di essere coinvolto negli attacchi dell'11/9, nonostante avesse vissuto in Germania per i precedenti 10 anni.", "join-us-on-GitHub": "Unisciti a noi su GitHub", "simplex-chat-for-the-terminal": "SimpleX Chat per il terminale", "privacy-matters-overlay-card-3-p-4": "Non è sufficiente usare un messenger crittografato end-to-end, tutti dovremmo usare i messenger che proteggono la privacy delle nostre reti personali — con chi siamo connessi.", "simplex-unique-overlay-card-1-p-2": "Per recapitare i messaggi, SimpleX usa indirizzi anonimi a coppie di code di messaggi unidirezionali, separate per i messaggi ricevuti e inviati, di solito tramite server diversi.", - "simplex-unique-overlay-card-1-p-1": "A differenza di altre piattaforme di messaggistica, SimpleX non ha alcun identificatore assegnato agli utenti. Non si basa su numeri di telefono, indirizzi basati su domini (come email o XMPP), nomi utente, chiavi pubbliche o persino numeri casuali per identificare i suoi utenti — non sappiamo quante persone usano i nostri server SimpleX.", + "simplex-unique-overlay-card-1-p-1": "A differenza di altre reti di messaggistica, SimpleX non ha alcun identificatore assegnato agli utenti. Non si basa su numeri di telefono, indirizzi basati su domini (come email o XMPP), nomi utente, chiavi pubbliche o persino numeri casuali per identificare i suoi utenti — gli operatori dei server non sanno quante persone usano i loro server.", "simplex-unique-overlay-card-3-p-3": "A differenza dei server di reti federate (email, XMPP o Matrix), i server SimpleX non conservano gli account utente, ma trasmettono solo i messaggi, proteggendo la privacy di entrambe le parti.", "simplex-unique-card-3-p-2": "I messaggi crittografati end-to-end vengono conservati temporaneamente sui server di inoltro SimpleX fino alla ricezione, quindi vengono eliminati definitivamente.", "simplex-unique-card-4-p-2": "Puoi usare SimpleX con i tuoi server personali o con i server forniti da noi — e connetterti comunque a qualsiasi utente.", "join-the-REDDIT-community": "Unisciti alla comunità di REDDIT", "sign-up-to-receive-our-updates": "Iscriviti per ricevere i nostri aggiornamenti", "simplex-unique-overlay-card-3-p-4": "Non ci sono identificatori o testi cifrati in comune tra il traffico del server inviato e quello ricevuto — se qualcuno lo osserva, non può determinare facilmente chi comunica con chi, anche se il TLS è compromesso.", - "simplex-unique-overlay-card-4-p-2": "La piattaforma SimpleX usa un protocollo aperto e fornisce un SDK per creare chat bot, consentendo l'implementazione di servizi con cui gli utenti possono interagire tramite le app SimpleX Chat — siamo impazienti di vedere quali servizi SimpleX puoi creare.", - "simplex-unique-card-4-p-1": "La rete SimpleX è completamente decentralizzata e indipendente da qualsiasi criptovaluta o altra piattaforma, ad eccezione di internet.", + "simplex-unique-overlay-card-4-p-2": "La rete di SimpleX usa un protocollo aperto e fornisce un SDK per creare chat bot, consentendo l'implementazione di servizi con cui gli utenti possono interagire tramite le app SimpleX Chat — siamo impazienti di vedere quali servizi SimpleX creerai.", + "simplex-unique-card-4-p-1": "La rete SimpleX è completamente decentralizzata e indipendente da qualsiasi criptovaluta o altra rete, ad eccezione di internet.", "donate-here-to-help-us": "Dona qui per aiutarci", "to-make-a-connection": "Per stabilire una connessione:", "scan-the-qr-code-with-the-simplex-chat-app-description": "Le chiavi pubbliche e l'indirizzo della coda di messaggi in questo link NON vengono inviati in rete quando vedi questa pagina —
sono contenuti nel frammento hash dell'URL del link.", @@ -218,7 +218,7 @@ "guide-dropdown-7": "Privacy e sicurezza", "guide-dropdown-9": "Creare connessioni", "guide": "Guida", - "docs-dropdown-1": "Piattaforma SimpleX", + "docs-dropdown-1": "Rete di SimpleX", "docs-dropdown-2": "Accesso ai file Android", "docs-dropdown-3": "Accesso al database di chat", "docs-dropdown-4": "Ospita un server SMP", diff --git a/website/langs/uk.json b/website/langs/uk.json index 71b3254e63..1c1780edb3 100644 --- a/website/langs/uk.json +++ b/website/langs/uk.json @@ -14,19 +14,19 @@ "simplex-network-overlay-card-1-li-6": "P2P-мережі можуть бути вразливими до атаки DRDoS, коли клієнти можуть ребродкастити та збільшувати трафік, що призводить до відмови в обслуговуванні на рівні всієї мережі. Клієнти SimpleX лише пересилають трафік від відомого підключення і не можуть бути використані зловмисником для збільшення трафіку в усій мережі.", "privacy-matters-overlay-card-1-p-2": "Інтернет-роздрібники знають, що люди з низьким доходом частіше роблять термінові покупки, тому вони можуть встановлювати вищі ціни або скасовувати знижки.", "privacy-matters-overlay-card-1-p-3": "Деякі фінансові та страхові компанії використовують соціальні графи для визначення ставок та страхових премій. Це часто змушує людей з низькими доходами платити більше — це відомо як 'поширений преміум'.", - "privacy-matters-overlay-card-1-p-4": "Платформа SimpleX захищає конфіденційність ваших з'єднань краще, ніж будь-яка альтернатива, повністю запобігаючи доступу вашого соціального графа будь-яким компаніям чи організаціям. Навіть коли люди використовують сервери, надані SimpleX Chat, ми не знаємо кількість користувачів чи їх зв'язки.", + "privacy-matters-overlay-card-1-p-4": "Мережа SimpleX краще захищає конфіденційність ваших з'єднань, ніж будь-яка інша альтернатива, повністю запобігаючи тому, щоб ваш соціальний граф став доступним для будь-яких компаній чи організацій. Навіть коли люди використовують сервери, попередньо налаштовані в додатках SimpleX Chat, оператори серверів не знають кількості користувачів або їхніх з'єднань.", "privacy-matters-overlay-card-2-p-1": "Не так давно ми спостерігали, як великі вибори маніпулювалися поважною консалтинговою компанією, яка використовувала наші соціальні графи для спотворення нашого уявлення про реальний світ та маніпулювання нашими голосами.", - "privacy-matters-overlay-card-2-p-2": "Щоб бути об'єктивним та приймати незалежні рішення, вам потрібно контролювати ваш інформаційний простір. Це можливо лише за умови використання приватної платформи для спілкування, яка не має доступу до вашого соціального графа.", - "privacy-matters-overlay-card-2-p-3": "SimpleX - це перша платформа, яка не має жодних ідентифікаторів користувачів за своїм дизайном, таким чином, захищаючи ваш графік з'єднань краще, ніж будь-яка відома альтернатива.", + "privacy-matters-overlay-card-2-p-2": "Щоб бути об'єктивним та приймати незалежні рішення, вам потрібно контролювати ваш інформаційний простір. Це можливо лише за умови використання приватної мережі для спілкування, яка не має доступу до вашого соціального графа.", + "privacy-matters-overlay-card-2-p-3": "SimpleX - це перша мережа, яка не має жодних ідентифікаторів користувачів за своїм дизайном, таким чином, захищаючи ваш графік з'єднань краще, ніж будь-яка відома альтернатива.", "privacy-matters-overlay-card-3-p-1": "Кожен повинен турбуватися про конфіденційність та безпеку свого спілкування — безпечні розмови можуть поставити вас під загрозу, навіть якщо у вас немає чого приховувати.", "privacy-matters-overlay-card-3-p-2": "Однією з найшокуючих історій є досвід Мохамеду Ульд Слахі, описаний в його мемуарах і показаний у фільмі \"Мавританець\". Його посадили в табір Гуантанамо без суду і мукили там 15 років після телефонного дзвінка йому родичеві в Афганістані, під підозрою в причетності до атак 11 вересня, навіть не дивлячись на те, що він проживав у Німеччині протягом попередніх 10 років.", "privacy-matters-overlay-card-3-p-4": "Недостатньо використовувати зашифрований від кінця до кінця месенджер; ми всі повинні використовувати месенджери, які захищають конфіденційність наших особистих мереж — з ким ми з'єднані.", - "simplex-unique-overlay-card-1-p-1": "На відміну від інших платформ обміну повідомленнями, у SimpleX не присвоюються ідентифікатори користувачів. Він не покладається на номери телефонів, адреси на основі домену (наприклад, електронна пошта або XMPP), імена користувачів, публічні ключі або навіть випадкові номери для ідентифікації своїх користувачів — ми не знаємо, скільки людей використовує наші сервери SimpleX.", + "simplex-unique-overlay-card-1-p-1": "На відміну від інших мереж для обміну повідомленнями, у SimpleX немає ідентифікаторів, призначених користувачам. Він не покладається на номери телефонів, адреси на основі доменів (як електронна пошта або XMPP), імена користувачів, публічні ключі або навіть випадкові числа для ідентифікації своїх користувачів — оператори серверів SimpleX не знають, скільки людей використовують їхні сервери.", "simplex-unique-overlay-card-3-p-3": "На відміну від федеративних мереж серверів (електронна пошта, XMPP або Matrix), сервери SimpleX не зберігають облікові записи користувачів, вони лише ретранслюють повідомлення, захищаючи приватність обох сторін.", "simplex-unique-card-3-p-2": "Зашифровані повідомлення від кінця до кінця тимчасово зберігаються на ретрансляційних серверах SimpleX до їх отримання, після чого вони назавжди видаляються.", - "simplex-unique-card-4-p-1": "Мережа SimpleX є повністю децентралізованою та незалежною від будь-якої криптовалюти чи іншої платформи, крім Інтернету.", + "simplex-unique-card-4-p-1": "Мережа SimpleX повністю децентралізована та незалежна від будь-якої криптовалюти або будь-якої іншої мережі, окрім Інтернету.", "simplex-network-overlay-card-1-li-3": "P2P не вирішує проблему атаки MITM, і більшість існуючих реалізацій не використовують поза каналом повідомлень для початкового обміну ключами. SimpleX використовує поза каналом повідомлень або, у деяких випадках, передбачені і безпечні з'єднання для початкового обміну ключами.", - "simplex-network-overlay-card-1-li-4": "Реалізації P2P можуть бути блоковані деякими інтернет-провайдерами (наприклад, BitTorrent). SimpleX є транспортно-агностичним - він може працювати через стандартні веб-протоколи, наприклад, WebSockets.", + "simplex-network-overlay-card-1-li-4": "Реалізації P2P можуть бути заблоковані деякими інтернет-провайдерами (наприклад, BitTorrent). SimpleX є незалежним від транспорту — він може працювати через стандартні веб-протоколи, наприклад, WebSockets.", "simplex-unique-card-4-p-2": "Ви можете використовувати SimpleX з власними серверами або з серверами, які ми надаємо — і все одно підключатися до будь-якого користувача.", "contact-hero-p-1": "Публічні ключі та адреса черги повідомлень в цьому посиланні НЕ відправляються по мережі під час перегляду цієї сторінки — вони містяться в хеш-фрагменті URL-посилання.", "scan-qr-code-from-mobile-app": "Сканувати QR-код з мобільного додатка", @@ -46,7 +46,7 @@ "guide-dropdown-8": "Налаштування додатка", "guide-dropdown-9": "Створення підключень", "guide": "Посібник", - "docs-dropdown-1": "Платформа SimpleX", + "docs-dropdown-1": "SimpleX мережа", "docs-dropdown-2": "Доступ до файлів Android", "docs-dropdown-3": "Доступ до бази даних чату", "docs-dropdown-4": "Хостинг сервера SMP", @@ -71,7 +71,7 @@ "simplex-explained-tab-1-p-1": "Ви можете створювати контакти та групи і вести двосторонні розмови, як у будь-якому іншому месенджері.", "simplex-explained-tab-1-p-2": "Як це може працювати з однобічними чергами та без ідентифікаторів профілю користувача?", "simplex-explained-tab-2-p-1": "Для кожного з'єднання ви використовуєте дві окремі черги обміну повідомленнями для відправки та отримання повідомлень через різні сервери.", - "simplex-explained-tab-2-p-2": "Сервери передають повідомлення тільки в одному напрямку, не маючи повної картини розмови або підключень користувача.", + "simplex-explained-tab-2-p-2": "Сервери передають повідомлення тільки в одному напрямку, не маючи повної картини розмов або підключень користувача.", "simplex-explained-tab-3-p-1": "Сервери мають окремі анонімні облікові дані для кожної черги і не знають, які користувачі до них відносяться.", "simplex-explained-tab-3-p-2": "Користувачі можуть додатково підвищити конфіденційність метаданих, використовуючи Tor для доступу до серверів, що запобігає кореляції за IP-адресою.", "chat-bot-example": "Приклад чат-бота", @@ -116,7 +116,7 @@ "simplex-private-card-4-point-2": "Для використання SimpleX через Tor, будь ласка, встановіть додаток Orbot та активуйте SOCKS5-проксі (або VPN на iOS).", "simplex-private-card-5-point-1": "SimpleX використовує наповнення вмісту для кожного шару шифрування для ускладнення атак за розміром повідомлень.", "simplex-private-card-5-point-2": "Це забезпечує, що повідомлення різних розмірів виглядають однаково для серверів та спостерігачів мережі.", - "simplex-private-card-6-point-1": "Багато комунікаційних платформ вразливі до MITM-атак серверів чи постачальників мережі.", + "simplex-private-card-6-point-1": "Багато комунікаційних мереж вразливі до MITM-атак серверів чи постачальників мережі.", "simplex-private-card-6-point-2": "Щоб запобігти цьому, програми SimpleX передають одноразові ключі позаканально, коли ви ділитесь адресою як посиланням або QR-кодом.", "simplex-private-card-7-point-2": "Якщо будь-яке повідомлення додається, вилучається чи змінюється, отримувач буде проінформований.", "simplex-private-card-8-point-1": "Сервери SimpleX виступають як вузли низької затримки для змішування — вхідні та вихідні повідомлення мають різний порядок.", @@ -140,7 +140,7 @@ "simplex-unique-4-title": "Ви власник мережі SimpleX", "simplex-unique-4-overlay-1-title": "Повністю децентралізована — користувачі володіють мережею SimpleX", "hero-overlay-card-1-p-1": "Багато користувачів запитували: якщо у SimpleX немає ідентифікаторів користувачів, як він може знати, куди відправити повідомлення?", - "hero-overlay-card-1-p-2": "Для доставки повідомлень, замість ідентифікаторів користувачів, які використовують усі інші платформи, SimpleX використовує тимчасові анонімні парні ідентифікатори черг повідомлень, окремі для кожного вашого підключення — тут немає довгострокових ідентифікаторів.", + "hero-overlay-card-1-p-2": "Для доставки повідомлень, замість ідентифікаторів користувачів, які використовують усі інші мережі, SimpleX використовує тимчасові анонімні парні ідентифікатори черг повідомлень, окремі для кожного вашого підключення — тут немає довгострокових ідентифікаторів.", "hero-overlay-card-1-p-3": "Ви визначаєте, який(кі) сервер(и) використовувати для отримання повідомлень, ваші контакти — сервери, які ви використовуєте для відправки повідомлень їм. Кожна розмова, ймовірно, використовує два різних сервери.", "hero-overlay-card-1-p-4": "Цей дизайн запобігає витоку метаданих будь-яких користувачів на рівні додатка. Для подальшого покращення конфіденційності та захисту вашої IP-адреси ви можете підключитися до серверів обміну повідомленнями через Tor.", "hero-overlay-card-1-p-6": "Докладніше читайте у білетному запису SimpleX.", @@ -153,18 +153,18 @@ "privacy-matters-overlay-card-1-p-1": "Багато великих компаній використовують інформацію про те, з ким ви з'єднані, щоб оцінити ваш дохід, продавати вам продукти, які вам дійсно не потрібні, і визначати ціни.", "privacy-matters-overlay-card-3-p-3": "Звичайних людей арештовують за те, що вони публікують онлайн, навіть через свої 'анонімні' облікові записи, навіть у демократичних країнах.", "simplex-unique-overlay-card-1-p-2": "Для доставки повідомлень SimpleX використовує парні анонімні адреси однобічних черг повідомлень, окремо для отриманих та відправлених повідомлень, зазвичай через різні сервери.", - "simplex-unique-overlay-card-1-p-3": "Цей дизайн захищає конфіденційність осіб, з якими ви спілкуєтеся, приховуючи це від серверів платформи SimpleX та будь-яких спостерігачів. Щоб сховати свою IP-адресу від серверів, ви можете підключитися до серверів SimpleX через Tor.", - "simplex-unique-overlay-card-2-p-1": "Оскільки у вас немає ідентифікатора на платформі SimpleX, ніхто не може з вами зв'язатися, якщо ви не поділитеся одноразовою або тимчасовою адресою користувача, у вигляді QR-коду або посилання.", + "simplex-unique-overlay-card-1-p-3": "Цей дизайн захищає конфіденційність того, з ким ви спілкуєтесь, приховуючи це від серверів мережі SimpleX та від будь-яких спостерігачів. Щоб приховати вашу IP-адресу від серверів, ви можете підключатися до серверів SimpleX через Tor.", + "simplex-unique-overlay-card-2-p-1": "Оскільки у вас немає ідентифікатора в мережі SimpleX, ніхто не може зв'язатися з вами, якщо ви не поділитеся одноразовою або тимчасовою адресою користувача, як QR-кодом або посиланням.", "simplex-unique-overlay-card-2-p-2": "Навіть з необов'язковою адресою користувача, яка може бути використана для відправки спамових запитань на зв'язок, ви можете змінити або повністю видалити її, не втрачаючи жодного з ваших з'єднань.", "simplex-unique-overlay-card-3-p-1": "SimpleX Chat зберігає всі дані користувачів лише на пристроях клієнтів за допомогою переносного зашифрованого формату бази даних, який можна експортувати і передавати на будь-який підтримуваний пристрій.", "simplex-unique-overlay-card-3-p-2": "Зашифровані повідомлення від кінця до кінця тимчасово зберігаються на ретрансляційних серверах SimpleX до їх отримання, після чого вони назавжди видаляються.", "simplex-unique-overlay-card-3-p-4": "Між надісланим і отриманим серверним трафіком немає спільних ідентифікаторів чи шифрованого тексту — якщо хтось його спостерігає, він не може легко визначити, хто спілкується з ким, навіть якщо TLS скомпрометовано.", - "simplex-unique-overlay-card-4-p-1": "Ви можете використовувати SimpleX з власними серверами і все одно спілкуватися з людьми, які використовують надані нам сервери заздалегідь налаштовані.", - "simplex-unique-overlay-card-4-p-2": "Платформа SimpleX використовує відкритий протокол та надає SDK для створення чат-ботів, що дозволяє впроваджувати сервіси, з якими користувачі можуть взаємодіяти через додатки SimpleX Chat — ми дійсно чекаємо, які сервіси SimpleX ви зможете побудувати.", - "simplex-unique-overlay-card-4-p-3": "Якщо ви розглядаєте можливість розробки для платформи SimpleX, наприклад, чат-бота для користувачів додатку SimpleX або інтеграції бібліотеки SimpleX Chat у свої мобільні додатки, будь ласка, зв'яжіться з нами для отримання порад та підтримки.", - "simplex-unique-card-1-p-1": "SimpleX захищає конфіденційність вашого профілю, контактів та метаданих, приховуючи їх від серверів платформи SimpleX та будь-яких спостерігачів.", - "simplex-unique-card-1-p-2": "На відміну від будь-якої іншої існуючої платформи обміну повідомленнями, SimpleX не має ідентифікаторів, призначених користувачам — навіть випадкових чисел.", - "simplex-unique-card-2-p-1": "Оскільки у вас немає ідентифікатора або фіксованої адреси на платформі SimpleX, ніхто не може з вами зв'язатися, якщо ви не поділитесь одноразовою або тимчасовою адресою користувача, як QR-код або посиланням.", + "simplex-unique-overlay-card-4-p-1": "Ви можете використовувати SimpleX зі своїми власними серверами і при цьому спілкуватися з людьми, які використовують сервери, попередньо налаштовані в додатках.", + "simplex-unique-overlay-card-4-p-2": "Мережа SimpleX використовує відкритий протокол і надає SDK для створення чат-ботів, що дозволяє реалізувати сервіси, з якими користувачі можуть взаємодіяти через додатки SimpleX Chat — ми справді чекаємо, щоб побачити, які сервіси SimpleX ви створите.", + "simplex-unique-overlay-card-4-p-3": "Якщо ви плануєте розробляти для мережі SimpleX, наприклад, чат-бота для користувачів додатка SimpleX або інтеграцію бібліотеки SimpleX Chat у ваші мобільні додатки, будь ласка, зв'яжіться з нами для отримання порад та підтримки.", + "simplex-unique-card-1-p-1": "SimpleX захищає конфіденційність вашого профілю, контактів та метаданих, приховуючи їх від серверів мережі SimpleX та будь-яких спостерігачів.", + "simplex-unique-card-1-p-2": "На відміну від будь-якої іншої існуючої мережі для обміну повідомленнями, у SimpleX немає ідентифікаторів, призначених користувачам — не навіть випадкових чисел.", + "simplex-unique-card-2-p-1": "Оскільки у вас немає ідентифікатора або фіксованої адреси в мережі SimpleX, ніхто не може зв'язатися з вами, якщо ви не поділитеся одноразовою або тимчасовою адресою користувача, як QR-кодом або посиланням.", "simplex-unique-card-3-p-1": "SimpleX зберігає всі дані користувачів на пристроях клієнтів у переносному зашифрованому форматі бази даних — його можна передавати на інший пристрій.", "join": "Приєднатися", "we-invite-you-to-join-the-conversation": "Ми запрошуємо вас приєднатися до розмови", @@ -191,7 +191,7 @@ "installing-simplex-chat-to-terminal": "Встановлення SimpleX Chat для терміналу", "use-this-command": "Використовуйте цю команду:", "see-simplex-chat": "Дивіться SimpleX Chat", - "the-instructions--source-code": "інструкції з того, як його завантажити чи скомпілювати з вихідного коду.", + "the-instructions--source-code": "для інструкції з того, як його завантажити чи скомпілювати з вихідного коду.", "if-you-already-installed-simplex-chat-for-the-terminal": "Якщо ви вже встановили SimpleX Chat для терміналу", "if-you-already-installed": "Якщо ви вже встановили", "simplex-chat-for-the-terminal": "SimpleX Chat для терміналу", @@ -227,7 +227,7 @@ "no-decentralized": "Ні - децентралізовано", "comparison-section-list-point-4": "Якщо сервери оператора порушені. Перевірте безпековий код в Signal та деяких інших додатках для зменшення ризику", "comparison-section-list-point-5": "Не захищає конфіденційність метаданих користувачів", - "comparison-section-list-point-6": "Хоча P2P є розподіленими, вони не є федеративними - вони працюють як єдина мережа", + "comparison-section-list-point-6": "Хоча P2P є розподіленими, вони не є федеративними — вони працюють як одна мережа", "guide-dropdown-1": "Швидкий старт", "guide-dropdown-2": "Відправлення повідомлень", "guide-dropdown-3": "Таємні групи", diff --git a/website/langs/zh_Hans.json b/website/langs/zh_Hans.json index c6712e7bbf..c0b843ca9e 100644 --- a/website/langs/zh_Hans.json +++ b/website/langs/zh_Hans.json @@ -24,7 +24,7 @@ "simplex-network-overlay-card-1-li-2": "与大多数 P2P 网络不同,SimpleX 在设计上没有任何类型的全局用户标识符,甚至临时的也没有。SimpleX 仅使用临时的成对标识符,提供更好的匿名性和元数据保护。", "privacy-matters-overlay-card-1-p-1": "许多大型公司会使用您的人际关系来估算您的收入,决定商品的价格,并向您兜售您并不真正需要的产品。", "simplex-unique-overlay-card-3-p-4": "发送和接收的服务器流量之间没有共同的标识符或密文—— 如果有人在观察它,他们也无法轻易确定谁与谁通信,即使 TLS 受到威胁。", - "simplex-unique-card-4-p-1": "SimpleX 网络是完全去中心化的,并且独立于任何加密货币或除互联网以外的任何其他平台。", + "simplex-unique-card-4-p-1": "SimpleX 网络是完全去中心化的,并且独立于任何加密货币或除互联网以外的任何其他网络。", "join": "加入", "get-simplex": "获取 SimpleX desktop app", "hide-info": "隐藏信息", @@ -49,8 +49,8 @@ "simplex-explained": "SimpleX 简述", "simplex-explained-tab-3-text": "3. 服务器能看到什么", "hero-header": "重新定义隐私", - "simplex-explained-tab-1-p-2": "它是如何在单向消息队列与没有用户识别符的情况下工作的?", - "simplex-explained-tab-2-p-2": "服务器只会单向传输消息,而无法掌握用户的会话或连接的全貌。", + "simplex-explained-tab-1-p-2": "它是如何利用单向消息队列并不利用用户识别符工作的?", + "simplex-explained-tab-2-p-2": "服务器只会单向传输消息,而无法掌握用户的对话或连接的全貌。", "simplex-explained-tab-3-p-1": "服务器对每个队列都有单独的匿名凭证,并且不知道这些凭证属于哪些用户。", "donate": "捐赠", "simplex-explained-tab-2-p-1": "对于每个连接,您都会使用两个单独的消息队列,通过不同的服务器发送和接收消息。", @@ -104,7 +104,7 @@ "simplex-private-card-10-point-1": "SimpleX 为每个用户的联系人或群组成员均使用临时匿名成对地址和凭据。", "privacy-matters-3-title": "因无辜结社而被起诉", "privacy-matters-2-overlay-1-title": "隐私给您力量", - "hero-overlay-card-1-p-2": "为了传递消息,SimpleX 使用消息队列的临时匿名成对标识符(而非其他平台使用的用户 ID)来区分您的每个连接——没有长期标识符这种东西。", + "hero-overlay-card-1-p-2": "SimpleX 使用消息队列的临时匿名成对标识符(而非其他网络使用的用户 ID)来传递消息,而每个连接的标识符均不尽相同 — 没有长期标识符这种东西。", "hero-overlay-card-1-p-3": "您定义用于接收消息的服务器、您的联系人—— 您用来向他们发送消息的服务器。 每个会话都很可能会使用两个不同的服务器。", "hero-overlay-card-1-p-4": "此设计可防止在应用程序级别泄漏任何用户元数据。 为了进一步改善隐私并保护您的 IP 地址,您可以通过 Tor 连接到消息服务器。", "hero-overlay-card-1-p-5": "只有客户端设备存储用户配置文件、联系人和群组; 消息均使用两层端到端加密发送。", @@ -115,29 +115,29 @@ "hero-overlay-card-2-p-3": "即使是使用 Tor v3 服务的最私密的应用程序,如果您通过同一个人资料与两个不同的联系人交谈,他们也可以证明他们与同一个人有联系。", "hero-overlay-card-2-p-4": "为防止这些攻击,SimpleX 在其设计中不包含任何用户 ID 。 而且,如果您使用隐身模式,您将为每个联系人显示不同的名称,避免他们之间共享任何数据。", "simplex-network-overlay-card-1-li-1": "P2P 网络依赖于 分布式散列表(DHT) 的某些变体来路由消息。 DHT 在设计上必须平衡可达性和延迟。 SimpleX 比 P2P 具有更好的可达性和更低的延迟,因为消息可以通过通讯双方选择的多个服务器并行地冗余传递。若是在 P2P 网络中,消息则需要使用算法选择,并依次通过 O(log N) 个节点。", - "simplex-network-overlay-card-1-li-4": "P2P 实现(如 BitTorrent)可能会被某些互联网提供商阻止。 SimpleX 与传输协议无关——它可以在标准网络协议上工作,例如 WebSockets。", + "simplex-network-overlay-card-1-li-4": "P2P 实现(如 BitTorrent)可能会被某些互联网提供商阻止。 SimpleX 与传输协议无关 — 它可以在标准网络协议上工作,例如 WebSockets。", "simplex-network-overlay-card-1-li-3": "P2P 并未解决中间人攻击(MITM Attack) 问题。大多数现有的 P2P 实现没有使用带外通讯来进行初始密钥的交换,而 SimpleX 使用带外通讯,或者在某些情况下,使用预先存在的安全和可信连接来进行初始密钥交换。", "simplex-network-overlay-card-1-li-5": "所有已知的 P2P 网络都可能受到 Sybil 攻击,因为每个节点都是可发现的,并且网络作为一个整体运行。 已知的缓解措施不是需要一个中心化的组件就是需要昂贵的工作量证明。而 SimpleX 网络没有服务器可发现性,它是碎片化的并且作为多个隔离的子网运行,这样全网络范围的攻击便无从实现。", "simplex-network-overlay-card-1-li-6": "P2P 网络可能受到 DRDoS 攻击 。客户端有能力重新广播和放大流量,从而导致整个网络范围内的服务中断。 SimpleX 客户端仅中继来自已知连接的流量,因此不能被攻击者用来放大整个网络的流量。", "privacy-matters-overlay-card-1-p-2": "在线零售商知道收入较低的人更有可能在紧急情况下购买商品,因此他们可能会收取更高的价格或取消折扣。", "privacy-matters-overlay-card-1-p-3": "一些金融和保险公司使用社交图谱来确定利率和保费。 它通常会让收入较低的人支付更多—— 它被称为“贫困溢价”。", - "privacy-matters-overlay-card-1-p-4": "SimpleX 平台比任何替代方案都能更好地保护您人际关系层面的隐私,防止您的社交图谱被任何公司或组织使用。 即使人们使用 SimpleX Chat 提供的服务器,我们也不知道用户数量或他们的连接数。", + "privacy-matters-overlay-card-1-p-4": "SimpleX 网络比任何替代方案都能更好地保护您人际关系层面的隐私,防止您的社交图谱被任何公司或组织使用。 即使人们使用 SimpleX Chat 应用预配置的服务器,服务器运营方也不知道用户数量或他们的连接数。", "privacy-matters-overlay-card-2-p-1": "不久前,我们观察到几次大选被一家知名咨询公司操纵,该公司使用我们的社交图谱扭曲我们对现实世界的看法并操纵我们的选票。", - "privacy-matters-overlay-card-2-p-2": "为了客观并做出独立的决定,您需要控制您的信息空间。 而这只有当您使用没有能力访问您的社交图谱的,注重隐私的通信平台时,这才有可能。", - "privacy-matters-overlay-card-2-p-3": "SimpleX 是第一个没有设计任何用户标识符的平台,这样能比任何已知的替代方案都更好地保护您的连接图谱。", + "privacy-matters-overlay-card-2-p-2": "为了客观并做出独立的决定,您需要控制您的信息空间。 而这只有当您使用没有能力访问您的社交图谱的,注重隐私的通信网络时,这才有可能。", + "privacy-matters-overlay-card-2-p-3": "SimpleX 是第一个没有设计任何用户标识符的网络,这样能比任何已知的替代方案都更好地保护您的连接图谱。", "privacy-matters-overlay-card-3-p-2": "最令人震惊的故事之一是 Mohamedou Ould Salahi 在他的回忆录中描述并在毛里塔尼亚电影中展示的经历。 他在未经审判的情况下被关进关塔那摩集中营,并在打电话给他在阿富汗的亲戚后在那里遭受了 15 年的折磨,他被怀疑参与了 9/11 袭击,尽管他在过去 10 年住在德国。", "privacy-matters-overlay-card-3-p-1": "每个人都应该关心他们通信的隐私和安全——无害的谈话会让您处于危险之中,即使您没有什么可隐瞒的。", "privacy-matters-overlay-card-3-p-3": "普通人会因为他们在网上分享的内容而被捕,即使是通过他们的“匿名”帐户,即使是在民主国家。", "privacy-matters-overlay-card-3-p-4": "使用端到端加密的即时通讯软件还不够,我们都应该使用保护我们个人网络隐私——即我们与谁有联系的即时通讯软件。", - "simplex-unique-overlay-card-1-p-1": "与其他消息传递平台不同,SimpleX 没有分配给用户的标识符。 它不依赖电话号码、基于域的地址(如电子邮件或 XMPP)、用户名、公钥甚至随机数来识别其用户—— 我们不知道有多少人使用我们的 SimpleX 服务器。", - "simplex-unique-overlay-card-1-p-2": "为了传递消息,SimpleX 使用单向消息队列的成对匿名地址,通常通过不同的服务器将接收和发送的消息分开。 使用 SimpleX 就像为每个联系人使用不同的即时电子邮件或电话,并且无需管理它们。", - "simplex-unique-overlay-card-1-p-3": "这种设计保护了您正在与之通信的人的隐私,将其隐藏在 SimpleX 平台服务器和任何观察者之外。 要对服务器隐藏您的 IP 地址,您可以通过 Tor 连接到 SimpleX 服务器。", - "simplex-unique-overlay-card-4-p-1": "您可以将 SimpleX 与您自己的服务器一起使用,并且仍然可以与使用我们提供的预配置服务器的人进行通信。", + "simplex-unique-overlay-card-1-p-1": "与其他消息网络不同,SimpleX 没有分配给用户的标识符。 它不依赖电话号码、基于域的地址(如电子邮件或 XMPP)、用户名、公钥甚至随机数来识别其用户—— SimpleX 服务器运营方不知道有多少人使用其服务器。", + "simplex-unique-overlay-card-1-p-2": "为了传递消息,SimpleX 使用单向消息队列的成对匿名地址,通常通过不同的服务器将接收和发送的消息分开。", + "simplex-unique-overlay-card-1-p-3": "这种设计保护了您正在与之通信的人的隐私,将其隐藏在 SimpleX 网络的服务器和任何观察者之外。 要对服务器隐藏您的 IP 地址,您可以通过 Tor 连接到 SimpleX 服务器。", + "simplex-unique-overlay-card-4-p-1": "您可以将 SimpleX 与您自己的服务器一起使用,并且仍然可以与使用应用中预配置服务器的人们进行通信。", "simplex-unique-card-3-p-2": "端到端加密的消息在被收到前会暂时保存在 SimpleX 中继服务器上,传送完成后它们会被永久删除。", - "simplex-unique-card-1-p-1": "SimpleX 保护您的个人资料、联系人和元数据的隐私,将其隐藏在 SimpleX 平台服务器和任何观察者之外。", - "simplex-unique-overlay-card-4-p-3": "如果您正在考虑为在SimpleX 平台上开发,例如,为 SimpleX 应用程序用户开发聊天机器人,或将 SimpleX 聊天库集成到您的移动应用程序中,请 联系我们 以获取建议和支持。", + "simplex-unique-card-1-p-1": "SimpleX 保护您的个人资料、联系人和元数据的隐私,不让 SimpleX 网络服务器和任何观察者看到它们。", + "simplex-unique-overlay-card-4-p-3": "如果您正在考虑为在SimpleX 网络上开发,例如,为 SimpleX 应用程序用户开发聊天机器人,或将 SimpleX 聊天库集成到您的移动应用程序中,请 联系我们 以获取建议和支持。", "simplex-unique-card-4-p-2": "您可以搭配自己的服务器来使用 SimpleX 或使用我们提供的服务器 — 并仍然连接到任何用户。", - "simplex-unique-card-2-p-1": "因为您在 SimpleX 平台上没有标识符或固定地址,所以除非您以二维码或链接的形式分享一次性或临时用户地址,没有人可以联系您。", + "simplex-unique-card-2-p-1": "因为您在 SimpleX 网络上没有标识符或固定地址,所以除非您以二维码或链接的形式分享一次性或临时用户地址,没有人可以联系您。", "simplex-unique-card-3-p-1": "SimpleX 以便携式加密数据库格式将所有用户数据存储在客户端设备上—— 它可以转移到另一个设备。", "sign-up-to-receive-our-updates": "注册以接收我们的更新", "we-invite-you-to-join-the-conversation": "我们邀请您加入对话", @@ -164,7 +164,7 @@ "github-repository": "GitHub 仓库", "copy-the-command-below-text": "复制下面的命令并在聊天中使用它:", "privacy-matters-section-header": "为什么隐私很重要", - "the-instructions--source-code": "如何从源代码下载或编译它的说明。", + "the-instructions--source-code": "如何下载或从源代码下载进行编译的说明。", "if-you-already-installed-simplex-chat-for-the-terminal": "如果您已经为终端安装了 SimpleX Chat", "if-you-already-installed": "如果您已经安装", "simplex-chat-for-the-terminal": "用于终端的 SimpleX Chat", @@ -197,16 +197,16 @@ "comparison-section-list-point-4": "如果运营商的服务器受到威胁。 验证 Signal 和其他一些应用程序中的安全代码以缓解该问题", "comparison-section-list-point-1": "通常基于电话号码,在某些情况下基于用户名", "comparison-section-list-point-2": "基于 DNS 的地址", - "comparison-section-list-point-6": "P2P 是分布式的,而非联邦式的 - 它们作为单个网络运行", + "comparison-section-list-point-6": "P2P 是分布式的,但并非联邦式的 — 它们作为单个网络运行", "see-here": "参见此处", "comparison-section-list-point-7": "P2P 网络要么拥有中央权威,要么整个网络可能被攻陷", "simplex-private-card-5-point-1": "SimpleX 为每个加密层进行内容填充来对抗长度扩展攻击。", - "simplex-unique-overlay-card-4-p-2": "SimpleX 平台使用开放协议并提供用于创建聊天机器人的 SDK, 允许用户实现通过 SimpleX Chat 应用程序与之交互的服务—— 我们真的很期待看到您可以依托SimpleX构建哪些服务。", + "simplex-unique-overlay-card-4-p-2": "SimpleX 网络使用开放协议并提供用于创建聊天机器人的 SDK, 允许用户实现通过 SimpleX Chat 应用程序与之交互的服务—— 我们真的很期待看到您会依托SimpleX构建哪些服务。", "simplex-unique-overlay-card-2-p-2": "即使使用可选的用户地址,当它被用于发送垃圾邮件联系请求,您可以更改或完全删除它而不会丢失任何连接。", "simplex-unique-overlay-card-3-p-1": "SimpleX Chat 使用便携式加密数据库格式仅将所有用户数据存储在客户端设备上,该格式可以导出并传输到任何支持的设备。", "donate-here-to-help-us": "在这里捐款来帮助我们", - "simplex-unique-card-1-p-2": "与任何其他现有的消息传递平台不同,SimpleX 没有分配给用户的标识符—— 甚至随机数也没有。", - "simplex-unique-overlay-card-2-p-1": "因为您在 SimpleX 平台上没有标识符,所以除非您以二维码或链接的形式分享一次性或临时用户地址,没有人可以联系您。", + "simplex-unique-card-1-p-2": "与任何其他现有的消息传递网络不同,SimpleX 没有分配给用户的标识符—— 甚至随机数也没有。", + "simplex-unique-overlay-card-2-p-1": "因为您在 SimpleX 网络上没有标识符,所以除非您以二维码或链接的形式分享一次性或临时用户地址,没有人可以联系您。", "simplex-unique-overlay-card-3-p-2": "端到端加密的消息在被收到前会暂时保存在 SimpleX 中继服务器上,传送完成后它们会被永久删除。", "simplex-unique-overlay-card-3-p-3": "与联合网络服务器(电子邮件、XMPP 或 Matrix)不同,SimpleX 服务器不存储用户帐户,它们仅中继消息,保护双方的隐私。", "guide-dropdown-2": "发送消息", @@ -223,7 +223,7 @@ "click-to-see": "点击查看", "menu": "菜单", "guide-dropdown-1": "快速指南", - "docs-dropdown-1": "SimpleX 平台", + "docs-dropdown-1": "SimpleX 网络", "docs-dropdown-5": "托管 XFTP 服务器", "newer-version-of-eng-msg": "本页面有较新的英语版本。", "guide-dropdown-4": "聊天档案", diff --git a/website/langs/zh_Hant.json b/website/langs/zh_Hant.json index d95c6259c7..324360cb19 100644 --- a/website/langs/zh_Hant.json +++ b/website/langs/zh_Hant.json @@ -1,13 +1,13 @@ { - "home": "家", + "home": "开始", "developers": "開發人員", "reference": "參考", - "blog": "博客", + "blog": "部落格", "features": "特徵", "why-simplex": "為什麼選擇SimpleX", "simplex-privacy": "SimpleX 隱私", "simplex-network": "SimpleX 網路", - "simplex-explained": "Simplex 解釋", + "simplex-explained": "SimpleX 解釋", "simplex-explained-tab-1-text": "1. 用戶體驗", "simplex-explained-tab-2-text": "2. 它是如何工作的", "simplex-explained-tab-3-text": "3. 伺服器可以看到什麼", @@ -16,15 +16,191 @@ "hero-subheader": "第一個沒有 User ID 的 Messenger", "simplex-explained-tab-3-p-2": "用戶可以通過使用 Tor 訪問伺服器來進一步提高元數據隱私,防止按 IP 位址進行序列化。", "smp-protocol": "SMP 協定", - "simplex-explained-tab-2-p-2": "伺服器僅以一種方式傳遞消息,而無法全面瞭解使用者的對話或連接。", + "simplex-explained-tab-2-p-2": "伺服器僅單向傳遞消息,無法全面瞭解使用者的對話記錄或連接。", "simplex-explained-tab-2-p-1": "對於每個連接,您可以使用兩個單獨的消息佇列通過不同的伺服器發送和接收消息。", "chat-protocol": "聊天協定", - "copyright-label": "© 2020-2024 單工 |開源專案", - "donate": "捐", + "copyright-label": "© 2020-2025 SimpleX |開源專案", + "donate": "捐助", "simplex-explained-tab-1-p-1": "您可以創建聯繫人和群組,並進行雙向對話,就像在任何其他 Messenger 中一樣。", "simplex-explained-tab-1-p-2": "它如何在沒有使用者配置檔標識符的情況下使用單向佇列?", "simplex-explained-tab-3-p-1": "伺服器對每個佇列都有單獨的匿名憑證,並且不知道它們屬於哪些使用者。", "chat-bot-example": "聊天機器人示例", "simplex-chat-protocol": "SimpleX Chat 協定", - "terms-and-privacy-policy": "隱私策略" + "terms-and-privacy-policy": "隱私策略", + "hero-overlay-card-3-p-3": "Trail of Bits 在 2024 年 7 月檢閱了 SimpleX 網路通訊協定的加密設計。閱讀更多。", + "hero-overlay-3-textlink": "安全評估", + "hero-overlay-card-3-p-2": "Trail of Bits 在 2022 年 11 月檢閱了 SimpleX 網路加密和網路元件。閱讀更多。", + "hero-overlay-1-textlink": "用戶ID為何有害私隱?", + "hero-overlay-2-textlink": "SimpleX如何工作?", + "simplex-private-card-5-point-2": "它讓不同長度的訊息在伺服器和網路觀察者看來相同。", + "simplex-private-card-10-point-1": "對用戶與群組成員,SimpleX使用臨時、匿名的地址對與憑證對。", + "privacy-matters-1-title": "廣告投放與價格歧視", + "privacy-matters-1-overlay-1-linkText": "私隱為您省錢", + "privacy-matters-2-title": "操縱選舉", + "privacy-matters-2-overlay-1-title": "私隱給您權力", + "privacy-matters-2-overlay-1-linkText": "私隱給您權力", + "privacy-matters-3-overlay-1-title": "私隱保護您的自由", + "privacy-matters-3-overlay-1-linkText": "私隱保護您的自由", + "simplex-unique-4-title": "您擁有SimpleX網路", + "simplex-unique-4-overlay-1-title": "完全去中心化—用戶擁有 SimpleX 網路", + "hero-overlay-card-1-p-4": "此設計可防止在應用程式層級洩漏任何使用者' 元資料。為了進一步改善隱私並保護您的 IP 位址,您可以透過 Tor 連接到訊息伺服器。", + "hero-overlay-card-1-p-5": "只有用戶端會儲存使用者設定檔、聯絡人和群組;訊息傳送採用雙層端對端加密。", + "hero-overlay-card-2-p-2": "然後他們可以將這些資訊與現有的公開社交網路進行關聯,並確定一些真實身份。", + "simplex-unique-card-1-p-1": "SimpleX 保護您的個人資料、聯絡人和元資料的隱私,使其對 SimpleX 網路伺服器和任何觀察者隱藏。", + "scan-qr-code-from-mobile-app": "用手機應用程式掃描二維碼", + "scan-the-qr-code-with-the-simplex-chat-app": "使用SimpleX Chat應用程式掃描二維碼", + "protocol-3-text": "點對點協議", + "hero-p-1": "其他聊天應用,如Signal、Matrix、Session、Briar、Jami、Cwtch等,使用用戶ID;SimpleX不這樣做。它甚至不使用隨機數。這種做法極大地保護用戶私隱。", + "hero-2-header-desc": "此視訊教您以一次性QR碼、親身或以視訊連結的方式與聯繫人連線。您也可以通過分享邀請連結與人連線。", + "feature-2-title": "端到端加密的圖像、視訊、檔案", + "simplex-private-card-9-point-2": "與傳統的訊息代理相比,它可減小攻擊媒介及可見的詮釋資料量。", + "simplex-private-10-title": "臨時匿名標識符對", + "simplex-private-card-1-point-1": "雙棘輪協定—帶有前向保密、入侵恢復特質的不留記錄即時通訊協定。", + "privacy-matters-3-title": "因無辜關聯而被起訴", + "signing-key-fingerprint": "簽名密鑰指紋(SHA-256)", + "hero-overlay-card-1-p-3": "您決定用哪個/哪些伺服器接收訊息。您的聯絡人用此伺服器向您傳送訊息。往往每個對話都使用兩台不同的伺服器。", + "docs-dropdown-2": "訪問Android檔案", + "simplex-unique-card-2-p-1": "由於您在 SimpleX 網路上沒有任何標識符或固定地址,因此除非您分享一次性或臨時地址 (如 二維碼或連結),任何人都無法與您聯絡。", + "see-here": "見此", + "privacy-matters-overlay-card-3-p-4": "僅使用端對端加密的通訊工具是不夠的,我們都應使用能保護個人網路隱私的通訊工具。", + "hero-overlay-card-1-p-1": "很多用戶問: 如果 SimpleX 沒有用戶標識符,它何以知道向何處傳送訊息?", + "simplex-unique-overlay-card-4-p-2": "SimpleX網路使用開源協議並提供開發包以編寫聊天機器人,允許使用者透過SimpleX Chat應用程式與服務互動—我們非常期待看到您的SimpleX服務之作!", + "hero-overlay-card-1-p-2": "為傳送訊息,SimpleX 使用消息佇列中的臨時匿名標識符對,每連線各異,而不像其他網路一樣使用用戶ID— SimpleX 沒有長期標識符。", + "privacy-matters-overlay-card-3-p-2": "最令人震驚的故事之一是 Mohamedou Ould Salahi 的經歷,描述於他的回憶錄中,並在《The Mauritanian movie》中呈現。他在未經審訊的情況下被送進關塔納摩集中營,並在那裏遭受了長達 15 年的酷刑,原因是他被懷疑參與了 9/11 襲擊事件,而此前 10 年他一直住在德國。", + "simplex-private-2-title": "伺服器附加加密層", + "hero-overlay-card-2-p-1": "如使用者擁有持久性身份,即使只是一個隨機數,例如 Session ID,也會有服務提供者或攻擊者可以觀察使用者如何連線以及傳送了多少條訊息的風險。", + "simplex-unique-overlay-card-4-p-3": "如您正考慮針對 SimpleX 網路進行開發,例如針對 SimpleX 使用者的聊天機器人,或將 SimpleX 聊天函式庫整合至您的手機應用程式,請與我們聯絡以獲取支持與建議。", + "simplex-network-overlay-card-1-li-1": "點對點網路依賴 DHT 的某些變體來路由訊息。DHT 設計必須平衡傳送保證和延遲。與點對點相比,SimpleX 具有更好的傳送保證和更低的延遲,因為訊息可以使用收件者選擇的伺服器,經由多個伺服器並行冗餘地傳送。在點對點網路中,訊息依次經由O(log N)個由演算法選擇的節點。", + "simplex-private-card-3-point-3": "連線恢復被停用,以防止會話攻擊。", + "simplex-private-card-2-point-1": "傳送至收件者的伺服器加密附加層,以防止 TLS 遭到攻擊時,接收和傳送的伺服器流量之間的關聯。", + "simplex-private-card-5-point-1": "SimpleX 為每個加密層使用內容填充,以挫敗通過監控訊息長度的攻擊。", + "comparison-section-list-point-4a": "SimpleX中繼不可能威脅端到端加密。由其他方式驗證安全碼以杜絕攻擊之可能", + "docs-dropdown-6": "WebRTC伺服器", + "feature-3-title": "端到端加密的、去中心化的群組—存在只有用戶自己知道", + "feature-7-title": "可攜、加密存儲—將設定檔移至另一設備", + "back-to-top": "回到頂部", + "click-to-see": "點擊查看", + "menu": "功能表", + "on-this-page": "此頁中", + "docs-dropdown-14": "在商業中使用SimpleX", + "glossary": "詞彙表", + "simplex-chat-repo": "SimpleX Chat儲存庫", + "newer-version-of-eng-msg": "本頁面有更新的英文版本。", + "f-droid-page-simplex-chat-repo-section-text": "掃描二維碼或使用此URL以添加SimpleX儲存庫至您的F-Droid客戶端:", + "jobs": "加入團隊", + "please-use-link-in-mobile-app": "請使用手機應用程式中的連結", + "stable-versions-built-by-f-droid-org": "由F-Droid.org編譯的穩定版", + "please-enable-javascript": "啟用JavaScript以查看二維碼。", + "docs-dropdown-8": "SimpleX通訊錄服務", + "hero-2-header": "創建私密連線", + "hero-overlay-1-title": "SimpleX如何工作?", + "hero-overlay-2-title": "用戶ID為何有害私隱?", + "hero-overlay-3-title": "安全評估", + "feature-1-title": "支持Markdown與編輯的、端到端加密的訊息", + "feature-4-title": "端到端加密的語音訊息", + "feature-5-title": "自刪除訊息", + "feature-6-title": "端到端加密的語音、視訊通話", + "simplex-network-overlay-1-title": "與點對點訊息傳輸協定的比較", + "simplex-private-1-title": "雙層端到端加密", + "simplex-private-3-title": "經安全鑑權的TLS 傳送", + "simplex-private-4-title": "可選的經由Tor訪問", + "simplex-private-5-title": "多層內容填充", + "feature-8-title": "隱身模式—SimpleX獨有", + "simplex-private-6-title": "頻帶外密鑰交換", + "simplex-private-7-title": "訊息完整性驗證", + "simplex-private-8-title": "訊息混雜以降低關聯性", + "simplex-private-card-1-point-2": "如TLS安全受威脅,每個隊列中的NaCL cryptobox可防止關聯訊息隊列間的通訊。", + "simplex-private-9-title": "單向訊息隊列", + "simplex-private-card-10-point-2": "SimpleX使不用用戶設定檔傳輸訊息成為可能,與其他軟體相比提供更強的詮釋資料私隱性。", + "privacy-matters-1-overlay-1-title": "私隱為您省錢", + "simplex-unique-1-title": "您擁有完整的私隱權", + "simplex-unique-1-overlay-1-title": "您的身份、個人資料、聯絡人與詮釋資料完全隱密", + "simplex-unique-2-title": "SimpleX保護您免受垃圾訊息、濫用之害", + "simplex-private-card-4-point-1": "為保護您的 IP 位址,您可透過 Tor 或其他傳輸覆蓋網路訪問伺服器。", + "simplex-unique-2-overlay-1-title": "防止垃圾郵件和濫用的最佳保護", + "simplex-unique-3-title": "您掌控您的數據", + "simplex-unique-3-overlay-1-title": "您的數據的擁有權、控制與安全", + "hero-overlay-card-2-p-4": "SimpleX 通過在設計中不使用任何使用者 ID以防止這些攻擊。而且,如果您使用匿名聊天模式,每個聯絡人都會有不同的顯示名稱,避免他們之間有任何共用資料。", + "hero-overlay-card-2-p-3": "即使是使用 Tor v3 服務的最隱私的應用程式,如果您透過相同的設定檔與兩個不同的人交談,他們也可以證明他們連線的是同一個人。", + "hero-overlay-card-1-p-6": "請參閱 SimpleX 白皮書以閱讀更多資訊。", + "hero-overlay-card-3-p-1": "Trail of Bits 是一家領先的安全和技術顧問公司,客戶包括大型科技公司、政府機構和主要的區塊鏈專案。", + "simplex-network-overlay-card-1-p-1": "點對點通訊協定和應用程式有多種問題,使得它們不如 SimpleX 可靠、分析起來更複雜,而且易受幾種類型的攻擊。", + "simplex-network-overlay-card-1-li-2": "SimpleX 的設計與大多數點對點網路不同,沒有任何類型的全局使用者標識符,即使是臨時標識符。SimpleX 只使用臨時的標識符對,提供更好的匿名性和元資料保護。", + "privacy-matters-overlay-card-1-p-1": "許多大公司利用與您有聯繫的人的資訊來估計您的收入,向您銷售您並不真正需要的產品,以及定價。", + "privacy-matters-overlay-card-1-p-2": "線上零售商知道收入較低的人更有可能進行緊急購物,因此他們可能收取較高的價格或取消折扣。", + "enter-your-email-address": "輸入您的電郵地址", + "get-simplex": "下載SimpleX 桌面版應用程式", + "join-us-on-GitHub": "在GitHub上加入我們", + "donate-here-to-help-us": "於此捐助以幫助我們", + "sign-up-to-receive-our-updates": "登記以收取更新", + "join": "加入", + "simplex-unique-card-3-p-1": "SimpleX 以 可攜式加密數據庫格式 儲存用戶端裝置上的所有使用者資料;這些資料可傳輸至其他設備。", + "simplex-unique-card-3-p-2": "端對端加密的訊息暫時保留在 SimpleX 中繼伺服器上,收到訊息後會被永久刪除。", + "simplex-unique-card-4-p-2": "您可以使用您自己的伺服器運行SimpleX,或使用我們提供的伺服器並仍連線到任何使用者。", + "simplex-unique-overlay-card-3-p-4": "傳送與接收的伺服器流量之間沒有共同的標識符或密文—如果有人觀察,即使 TLS 遭到破壞,也無法輕易確定誰與誰通訊。", + "join-the-REDDIT-community": "加入Reddit社群", + "privacy-matters-overlay-card-3-p-1": "人人都應關心自己通訊的隱私和安全;無害的對話可能會讓您陷入危險,即使您沒有什麼要隱瞞的。", + "privacy-matters-overlay-card-3-p-3": "普通人會因為他們在網路上分享的內容而被捕,即使是透過他們的「匿名」帳號,即使是在民主國家。", + "privacy-matters-overlay-card-2-p-1": "不久前我們觀察到大選被一家聲譽良好的顧問公司操縱,該公司利用我們的社交圖來扭曲我們對真實世界的看法,並操縱我們的選票。", + "comparison-section-list-point-2": "基於DNS的位址", + "comparison-section-list-point-1": "通常基於電話號碼,有時用戶名", + "simplex-private-card-6-point-1": "許多通訊網路容易受到伺服器或網路供應商的中間人攻擊。", + "privacy-matters-overlay-card-1-p-4": "SimpleX 網路比任何其他方式都能更好地保護您的連線隱私,完全防止您的社交圖表被任何公司或組織獲得。即使使用 SimpleX Chat 應用程式中預設的伺服器,伺服器操作員也不會知道使用者的數量或他們的連線。", + "privacy-matters-overlay-card-2-p-2": "要做到客觀和獨立決策,您需要控制自己的資訊空間。只有當使用無法存取您的社交圖表的私人通訊網路時,您才可能做到這一點。", + "simplex-unique-overlay-card-1-p-1": "與其他通訊網路不同,SimpleX 不為使用者指定標識符。它不依賴電話號碼、網域地址 (如電子郵件或 XMPP)、用戶名、公鑰或甚至隨機數來識別使用者;SimpleX 伺服器操作員不知道有多少人使用他們的伺服器。", + "privacy-matters-overlay-card-2-p-3": "SimpleX 是第一個在設計上不使用任何使用者標識符的網路,因此比任何已知的其他方案都能更好地保護您的社交圖。", + "simplex-unique-overlay-card-4-p-1": "您可以使用您自己的伺服器運行SimpleX,並仍與使用應用程式中預設伺服器的人進行通訊。", + "simplex-unique-card-1-p-2": "與任何其他現有的訊息網路不同,SimpleX 不指定使用者的標識符—甚至沒有隨機數。", + "why-simplex-is-unique": "SimpleX為何與眾不同", + "learn-more": "查看更多", + "more-info": "更多訊息", + "hide-info": "隱藏訊息", + "contact-hero-header": "您收到了SimpleX聯絡地址", + "simplex-unique-card-4-p-1": "SimpleX 網路是完全去中心化的,獨立於任何加密貨幣或任何其他網路(除Internet)。", + "invitation-hero-header": "您收到了SimpleX一次性連結", + "contact-hero-subheader": "使用手提電話或平板電腦中的SimpleX應用程式掃描二維碼。", + "connect-in-app": "在應用中連結", + "contact-hero-p-2": "尚未下載SimpleX?", + "contact-hero-p-1": "當您檢視此頁面時,此連結中的公鑰和訊息佇列位址不透過網路傳送;它們包含在連結 URL 的雜湊片段中。", + "contact-hero-p-3": "使用以下連結下載應用程式。", + "to-make-a-connection": "建立連結:", + "install-simplex-app": "安裝 SimpleX 應用程式", + "use-this-command": "使用此命令:", + "scan-the-qr-code-with-the-simplex-chat-app-description": "當您檢視此頁面時,此連結中的公鑰和訊息佇列位址不會透過網路傳送 —它們包含在連結 URL 的雜湊片段中。", + "installing-simplex-chat-to-terminal": "安裝SimpleX至終端", + "open-simplex-app": "開啟SimpleX應用程式", + "if-you-already-installed": "如已安裝", + "simplex-chat-for-the-terminal": "用於終端的 SimpleX Chat", + "if-you-already-installed-simplex-chat-for-the-terminal": "如您已經安裝了用於終端的 SimpleX Chat", + "tap-to-close": "輕觸以關閉", + "simplex-network-1-desc": "所有訊息都經由伺服器傳送,既能提供更好的元資料隱私和可靠的異步訊息傳送,又能避免許多", + "simplex-network-section-desc": "SinpleX Chat 結合點對點和互聯網路的優點,提供最佳的隱私性。", + "copy-the-command-below-text": "複製下面的命令並用於聊天:", + "privacy-matters-section-header": "隱私為何 重要", + "privacy-matters-section-label": "確保您的通訊應用程式無法竊取您的資料!", + "simplex-network-3-header": "SimpleX網路", + "simplex-network-1-overlay-linktext": "點對點網路的弊病", + "simplex-network-2-desc": "SimpleX 中繼伺服器不儲存使用者個人資料、聯絡人和傳送的訊息,也不連線彼此,也沒有伺服器目錄。", + "simplex-network-2-header": "與互聯網路不同", + "comparison-section-header": "與其他協議之比較", + "protocol-2-text": "XMPP、Matrix", + "comparison-point-1-text": "需要全局身份", + "simplex-network-3-desc": "伺服器提供單向佇列以連接使用者,但伺服器無法看到網路連線圖 —只有使用者能看到。", + "protocol-1-text": "Signal,大平台", + "comparison-point-2-text": "中間人攻擊之可能", + "comparison-point-3-text": "對DNS的依賴", + "comparison-point-4-text": "單一或集中式網路", + "comparison-section-list-point-3": "公鑰或其他某種全局獨一的標識符", + "comparison-section-list-point-5": "不保護使用者的元數據隱私", + "comparison-section-list-point-7": "點對點網路必須有中央權威,否則整個網路都可能受到攻擊", + "comparison-section-list-point-4": "如果運營商的伺服器受到攻擊,用其他應用程式(如 Signal)驗證 SimpleX 安全碼,以減輕風險", + "guide-dropdown-8": "應用程式設定", + "guide-dropdown-6": "音視訊通話", + "docs-dropdown-1": "SimpleX 網路", + "guide": "指南", + "docs-dropdown-9": "下載", + "docs-dropdown-11": "常見問題", + "docs-dropdown-12": "安全性", + "docs-dropdown-7": "翻譯SimpleX", + "f-droid-page-f-droid-org-repo-section-text": "SimpleX Chat 和F-Droid.org 儲存庫使用不同的金鑰為安裝包簽名。若要切換,請匯出聊天資料庫並重新安裝應用程式。" } diff --git a/website/web.sh b/website/web.sh index 4feba4be50..897c87743e 100755 --- a/website/web.sh +++ b/website/web.sh @@ -5,6 +5,7 @@ set -e cp -R docs website/src rm -rf website/src/docs/rfcs rm website/src/docs/lang/*/README.md +rm -rf website/src/docs/dependencies cp -R blog website/src cp -R images website/src rm website/src/blog/README.md