mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Compare commits
172 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d438cec674 | |||
| e4c5dbdb08 | |||
| 5d1a393131 | |||
| 8e3a713a49 | |||
| 7cec79e79b | |||
| e9db7e8e58 | |||
| f53882049f | |||
| 8f4c9a673a | |||
| 02f980e968 | |||
| 412f75219a | |||
| c8c81a840b | |||
| 925cb39397 | |||
| f6ceb89c4b | |||
| a35d392f76 | |||
| 1306c84938 | |||
| 6484e36b82 | |||
| 918be31f2c | |||
| 648884044f | |||
| 505c6cb062 | |||
| 065c8f8861 | |||
| 6c509027f7 | |||
| 4eafdc3723 | |||
| 77f5c678d5 | |||
| 5e71d00ace | |||
| c2169f7813 | |||
| 7ff4b05c90 | |||
| d7f8bff957 | |||
| bda0917787 | |||
| 0eae7f56f3 | |||
| 24e3806b25 | |||
| f606e5742c | |||
| c6af2c285a | |||
| 35b7f2cb1c | |||
| 76a33a3743 | |||
| b6fd5e61b6 | |||
| fe639eed48 | |||
| 638fd3756a | |||
| de81434b36 | |||
| 433b3652fb | |||
| 86fe2212c3 | |||
| 182225a5b1 | |||
| e10c63dc64 | |||
| 29941729d2 | |||
| ee53377070 | |||
| 0deb6a4eb1 | |||
| b84ef0ce35 | |||
| 34dee32def | |||
| 94851f177b | |||
| e560b49d14 | |||
| d8b52ee0d3 | |||
| a9c0f356b4 | |||
| 8a3710482b | |||
| b3a4ea8e57 | |||
| 4be6c69633 | |||
| 005d99ad50 | |||
| 36f86beafd | |||
| 1fa79a2654 | |||
| 72611084d3 | |||
| a5db36469d | |||
| f8e6a78a3b | |||
| 5b0c8e0f76 | |||
| 2968cd0460 | |||
| 8ffb4e500e | |||
| 6133993cfe | |||
| 0d7a32877f | |||
| 18efc28d16 | |||
| 069395c2a0 | |||
| a725d2efac | |||
| 5f9710e4bb | |||
| ea6c5bfb0b | |||
| 14c279d1e0 | |||
| d2de81100d | |||
| 9b28ae6d9e | |||
| ea862a8f34 | |||
| 2bd1a82b7d | |||
| 97a37634ef | |||
| 28fbc1cd84 | |||
| b8ee2af5b7 | |||
| c234809894 | |||
| e1a997877a | |||
| 69218952c3 | |||
| dc2591b0bf | |||
| 2272b77b53 | |||
| d90e2f4436 | |||
| 9b6ca23dcb | |||
| 1410b4bd85 | |||
| 42a35e8c72 | |||
| 86fe28f1ed | |||
| 735359c279 | |||
| 3d20465662 | |||
| b64ae90850 | |||
| 366b58ead5 | |||
| 32bcaad126 | |||
| d65137882b | |||
| 095d613f01 | |||
| f22beefbd4 | |||
| c9bf36291b | |||
| 42ebe8bc60 | |||
| 96fb61ccfc | |||
| 1d698c114f | |||
| 154ce5843d | |||
| a5817d9feb | |||
| 72082af139 | |||
| eb36704f59 | |||
| 84fbff6148 | |||
| dd75d30c08 | |||
| 52803ae976 | |||
| ec73a31cb5 | |||
| 6ad5048b58 | |||
| ca0ce4dfdd | |||
| d27502ec47 | |||
| 655ad4d813 | |||
| e0566599a4 | |||
| 2546ad5351 | |||
| 0706e6e464 | |||
| c2adf40b5a | |||
| b220ea23e2 | |||
| a16e3eebd1 | |||
| 6d54c21774 | |||
| d2e6313ce3 | |||
| c2707d3c2b | |||
| 43381b5cf0 | |||
| 3f1d86623a | |||
| 5fde879fea | |||
| 157c4722ca | |||
| 5bc8bbe16c | |||
| d835f9df3d | |||
| 8f04e13750 | |||
| 39167ab3dd | |||
| e925d87548 | |||
| c2e2408394 | |||
| bb16922634 | |||
| a3310cd62e | |||
| 94a6f300ed | |||
| 1f8eb1d638 | |||
| 5a016378a8 | |||
| bac4e61997 | |||
| f3eeb9dcc2 | |||
| 240ca30f91 | |||
| 835944ab24 | |||
| d53ef24bf1 | |||
| e75be71d9a | |||
| 7fa2f2f72e | |||
| 5fd8e6e4fe | |||
| d3b255b7cb | |||
| 96fba950ff | |||
| 4a404f14d9 | |||
| 4f893d9502 | |||
| 01447716fa | |||
| c9df591e52 | |||
| a56bc6760b | |||
| 80690326cb | |||
| 3f6c74f975 | |||
| 8b8846c7b7 | |||
| 6c78bbc178 | |||
| eaf720a0f2 | |||
| 0e7d81681f | |||
| 56fcaf514e | |||
| 49bd866c4b | |||
| 8660bf420a | |||
| 60a73a539e | |||
| 93d56a25bc | |||
| 7fb3c4abdb | |||
| 191d833947 | |||
| 19ca4f7447 | |||
| b86b5578de | |||
| 435ea9a453 | |||
| 1f93d91af5 | |||
| 405348732b | |||
| 109b6e0cff | |||
| b403201310 | |||
| 9ff11f886e |
@@ -270,7 +270,7 @@ jobs:
|
||||
|
||||
- name: Unix test
|
||||
if: matrix.os != 'windows-latest'
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 40
|
||||
shell: bash
|
||||
run: cabal test --test-show-details=direct
|
||||
|
||||
|
||||
@@ -5,14 +5,20 @@ on:
|
||||
pull_request_target:
|
||||
types: [opened, closed, synchronize]
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
contents: write
|
||||
pull-requests: write
|
||||
statuses: write
|
||||
|
||||
jobs:
|
||||
CLAssistant:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "CLA Assistant"
|
||||
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request'
|
||||
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
|
||||
# Beta Release
|
||||
uses: cla-assistant/github-action@v2.1.3-beta
|
||||
uses: cla-assistant/github-action@v2.3.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# the below token should have repo scope and must be manually added by you in the repository's secret
|
||||
@@ -33,4 +39,4 @@ jobs:
|
||||
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
|
||||
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
|
||||
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
|
||||
#use-dco-flag: true - If you are using DCO instead of CLA
|
||||
#use-dco-flag: true - If you are using DCO instead of CLA
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[](https://www.reddit.com/r/SimpleXChat)
|
||||
<a rel="me" href="https://mastodon.social/@simplex"></a>
|
||||
|
||||
| 30/03/2023 | EN, [FR](/docs/lang/fr/README.md), [CZ](/docs/lang/cs/README.md) |
|
||||
| 30/03/2023 | EN, [FR](/docs/lang/fr/README.md), [CZ](/docs/lang/cs/README.md), [PL](/docs/lang/pl/README.md) |
|
||||
|
||||
<img src="images/simplex-chat-logo.svg" alt="SimpleX logo" width="100%">
|
||||
|
||||
@@ -234,6 +234,10 @@ You can use SimpleX with your own servers and still communicate with people usin
|
||||
|
||||
Recent and important updates:
|
||||
|
||||
[Mar 23, 2024. SimpleX network: real privacy and stable profits, non-profits for protocols, v5.6 released with quantum resistant e2e encryption and simple profile migration.](./blog/20240323-simplex-network-privacy-non-profit-v5-6-quantum-resistant-e2e-encryption-simple-migration.md)
|
||||
|
||||
[Mar 14, 2024. SimpleX Chat v5.6 beta: adding quantum resistance to Signal double ratchet algorithm.](./blog/20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.md)
|
||||
|
||||
[Jan 24, 2024. SimpleX Chat: free infrastructure from Linode, v5.5 released with private notes, group history and a simpler UX to connect.](./blog/20240124-simplex-chat-infrastructure-costs-v5-5-simplex-ux-private-notes-group-history.md)
|
||||
|
||||
[Nov 25, 2023. SimpleX Chat v5.4 released: link mobile and desktop apps via quantum resistant protocol, and much better groups](./blog/20231125-simplex-chat-v5-4-link-mobile-desktop-quantum-resistant-better-groups.md).
|
||||
@@ -375,8 +379,9 @@ Please also join [#simplex-devs](https://simplex.chat/contact#/?v=1-2&smp=smp%3A
|
||||
- ✅ Using mobile profiles from the desktop app.
|
||||
- ✅ Private notes.
|
||||
- ✅ Improve sending videos (including encryption of locally stored videos).
|
||||
- ✅ Post-quantum resistant key exchange in double ratchet protocol.
|
||||
- 🏗 Improve stability and reduce battery usage.
|
||||
- 🏗 Improve experience for the new users.
|
||||
- 🏗 Post-quantum resistant key exchange in double ratchet protocol.
|
||||
- 🏗 Large groups, communities and public channels.
|
||||
- 🏗 Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic).
|
||||
- Privacy & security slider - a simple way to set all settings at once.
|
||||
|
||||
@@ -95,6 +95,7 @@ final class ChatModel: ObservableObject {
|
||||
@Published var remoteCtrlSession: RemoteCtrlSession?
|
||||
// currently showing invitation
|
||||
@Published var showingInvitation: ShowingInvitation?
|
||||
@Published var migrationState: MigrationToState? = MigrationToDeviceState.makeMigrationState()
|
||||
// audio recording and playback
|
||||
@Published var stopPreviousRecPlay: URL? = nil // coordinates currently playing source
|
||||
@Published var draft: ComposeState?
|
||||
@@ -102,6 +103,7 @@ final class ChatModel: ObservableObject {
|
||||
// tracks keyboard height via subscription in AppDelegate
|
||||
@Published var keyboardHeight: CGFloat = 0
|
||||
@Published var pasteboardHasStrings: Bool = UIPasteboard.general.hasStrings
|
||||
@Published var networkInfo = UserNetworkInfo(networkType: .other, online: true)
|
||||
|
||||
var messageDelivery: Dictionary<Int64, () -> Void> = [:]
|
||||
|
||||
@@ -777,6 +779,24 @@ final class Chat: ObservableObject, Identifiable {
|
||||
|
||||
var viewId: String { get { "\(chatInfo.id) \(created.timeIntervalSince1970)" } }
|
||||
|
||||
func groupFeatureEnabled(_ feature: GroupFeature) -> Bool {
|
||||
if case let .group(groupInfo) = self.chatInfo {
|
||||
let p = groupInfo.fullGroupPreferences
|
||||
return switch feature {
|
||||
case .timedMessages: p.timedMessages.on
|
||||
case .directMessages: p.directMessages.on(for: groupInfo.membership)
|
||||
case .fullDelete: p.fullDelete.on
|
||||
case .reactions: p.reactions.on
|
||||
case .voice: p.voice.on(for: groupInfo.membership)
|
||||
case .files: p.files.on(for: groupInfo.membership)
|
||||
case .simplexLinks: p.simplexLinks.on(for: groupInfo.membership)
|
||||
case .history: p.history.on
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public static var sampleData: Chat = Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: [])
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// NetworkObserver.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 05.04.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Network
|
||||
import SimpleXChat
|
||||
|
||||
class NetworkObserver {
|
||||
static let shared = NetworkObserver()
|
||||
private let queue: DispatchQueue = DispatchQueue(label: "chat.simplex.app.NetworkObserver")
|
||||
private var prevInfo: UserNetworkInfo? = nil
|
||||
private var monitor: NWPathMonitor?
|
||||
private let monitorLock: DispatchQueue = DispatchQueue(label: "chat.simplex.app.monitorLock")
|
||||
|
||||
func restartMonitor() {
|
||||
monitorLock.sync {
|
||||
monitor?.cancel()
|
||||
let mon = NWPathMonitor()
|
||||
mon.pathUpdateHandler = { [weak self] path in
|
||||
self?.networkPathChanged(path: path)
|
||||
}
|
||||
mon.start(queue: queue)
|
||||
monitor = mon
|
||||
}
|
||||
}
|
||||
|
||||
private func networkPathChanged(path: NWPath) {
|
||||
let info = UserNetworkInfo(
|
||||
networkType: networkTypeFromPath(path),
|
||||
online: path.status == .satisfied
|
||||
)
|
||||
if (prevInfo != info) {
|
||||
prevInfo = info
|
||||
setNetworkInfo(info)
|
||||
}
|
||||
}
|
||||
|
||||
private func networkTypeFromPath(_ path: NWPath) -> UserNetworkType {
|
||||
if path.usesInterfaceType(.wiredEthernet) {
|
||||
.ethernet
|
||||
} else if path.usesInterfaceType(.wifi) {
|
||||
.wifi
|
||||
} else if path.usesInterfaceType(.cellular) {
|
||||
.cellular
|
||||
} else if path.usesInterfaceType(.other) {
|
||||
.other
|
||||
} else {
|
||||
.none
|
||||
}
|
||||
}
|
||||
|
||||
private static var networkObserver: NetworkObserver? = nil
|
||||
|
||||
private func setNetworkInfo(_ info: UserNetworkInfo) {
|
||||
logger.debug("setNetworkInfo Network changed: \(String(describing: info))")
|
||||
DispatchQueue.main.sync {
|
||||
ChatModel.shared.networkInfo = info
|
||||
}
|
||||
if !hasChatCtrl() { return }
|
||||
self.monitorLock.sync {
|
||||
do {
|
||||
try apiSetNetworkInfo(info)
|
||||
} catch let err {
|
||||
logger.error("setNetworkInfo error: \(responseError(err))")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ public let CURRENT_CHAT_VERSION: Int = 2
|
||||
// version range that supports establishing direct connection with a group member (xGrpDirectInvVRange in core)
|
||||
public let CREATE_MEMBER_CONTACT_VRANGE = VersionRange(minVersion: 2, maxVersion: CURRENT_CHAT_VERSION)
|
||||
|
||||
private let networkStatusesLock = DispatchQueue(label: "chat.simplex.app.network-statuses.lock")
|
||||
|
||||
enum TerminalItem: Identifiable {
|
||||
case cmd(Date, ChatCommand)
|
||||
case resp(Date, ChatResponse)
|
||||
@@ -90,12 +92,12 @@ private func withBGTask<T>(bgDelay: Double? = nil, f: @escaping () -> T) -> T {
|
||||
return r
|
||||
}
|
||||
|
||||
func chatSendCmdSync(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil) -> ChatResponse {
|
||||
func chatSendCmdSync(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil, _ ctrl: chat_ctrl? = nil) -> ChatResponse {
|
||||
logger.debug("chatSendCmd \(cmd.cmdType)")
|
||||
let start = Date.now
|
||||
let resp = bgTask
|
||||
? withBGTask(bgDelay: bgDelay) { sendSimpleXCmd(cmd) }
|
||||
: sendSimpleXCmd(cmd)
|
||||
? withBGTask(bgDelay: bgDelay) { sendSimpleXCmd(cmd, ctrl) }
|
||||
: sendSimpleXCmd(cmd, ctrl)
|
||||
logger.debug("chatSendCmd \(cmd.cmdType): \(resp.responseType)")
|
||||
if case let .response(_, json) = resp {
|
||||
logger.debug("chatSendCmd \(cmd.cmdType) response: \(json)")
|
||||
@@ -106,24 +108,24 @@ func chatSendCmdSync(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? =
|
||||
return resp
|
||||
}
|
||||
|
||||
func chatSendCmd(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil) async -> ChatResponse {
|
||||
func chatSendCmd(_ cmd: ChatCommand, bgTask: Bool = true, bgDelay: Double? = nil, _ ctrl: chat_ctrl? = nil) async -> ChatResponse {
|
||||
await withCheckedContinuation { cont in
|
||||
cont.resume(returning: chatSendCmdSync(cmd, bgTask: bgTask, bgDelay: bgDelay))
|
||||
cont.resume(returning: chatSendCmdSync(cmd, bgTask: bgTask, bgDelay: bgDelay, ctrl))
|
||||
}
|
||||
}
|
||||
|
||||
func chatRecvMsg() async -> ChatResponse? {
|
||||
func chatRecvMsg(_ ctrl: chat_ctrl? = nil) async -> ChatResponse? {
|
||||
await withCheckedContinuation { cont in
|
||||
_ = withBGTask(bgDelay: msgDelay) { () -> ChatResponse? in
|
||||
let resp = recvSimpleXMsg()
|
||||
let resp = recvSimpleXMsg(ctrl)
|
||||
cont.resume(returning: resp)
|
||||
return resp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func apiGetActiveUser() throws -> User? {
|
||||
let r = chatSendCmdSync(.showActiveUser)
|
||||
func apiGetActiveUser(ctrl: chat_ctrl? = nil) throws -> User? {
|
||||
let r = chatSendCmdSync(.showActiveUser, ctrl)
|
||||
switch r {
|
||||
case let .activeUser(user): return user
|
||||
case .chatCmdError(_, .error(.noActiveUser)): return nil
|
||||
@@ -131,8 +133,8 @@ func apiGetActiveUser() throws -> User? {
|
||||
}
|
||||
}
|
||||
|
||||
func apiCreateActiveUser(_ p: Profile?, sameServers: Bool = false, pastTimestamp: Bool = false) throws -> User {
|
||||
let r = chatSendCmdSync(.createActiveUser(profile: p, sameServers: sameServers, pastTimestamp: pastTimestamp))
|
||||
func apiCreateActiveUser(_ p: Profile?, sameServers: Bool = false, pastTimestamp: Bool = false, ctrl: chat_ctrl? = nil) throws -> User {
|
||||
let r = chatSendCmdSync(.createActiveUser(profile: p, sameServers: sameServers, pastTimestamp: pastTimestamp), ctrl)
|
||||
if case let .activeUser(user) = r { return user }
|
||||
throw r
|
||||
}
|
||||
@@ -210,8 +212,8 @@ func apiDeleteUser(_ userId: Int64, _ delSMPQueues: Bool, viewPwd: String?) asyn
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiStartChat() throws -> Bool {
|
||||
let r = chatSendCmdSync(.startChat(mainApp: true))
|
||||
func apiStartChat(ctrl: chat_ctrl? = nil) throws -> Bool {
|
||||
let r = chatSendCmdSync(.startChat(mainApp: true), ctrl)
|
||||
switch r {
|
||||
case .chatStarted: return true
|
||||
case .chatRunning: return false
|
||||
@@ -240,14 +242,14 @@ func apiSuspendChat(timeoutMicroseconds: Int) {
|
||||
logger.error("apiSuspendChat error: \(String(describing: r))")
|
||||
}
|
||||
|
||||
func apiSetTempFolder(tempFolder: String) throws {
|
||||
let r = chatSendCmdSync(.setTempFolder(tempFolder: tempFolder))
|
||||
func apiSetTempFolder(tempFolder: String, ctrl: chat_ctrl? = nil) throws {
|
||||
let r = chatSendCmdSync(.setTempFolder(tempFolder: tempFolder), ctrl)
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetFilesFolder(filesFolder: String) throws {
|
||||
let r = chatSendCmdSync(.setFilesFolder(filesFolder: filesFolder))
|
||||
func apiSetFilesFolder(filesFolder: String, ctrl: chat_ctrl? = nil) throws {
|
||||
let r = chatSendCmdSync(.setFilesFolder(filesFolder: filesFolder), ctrl)
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
@@ -258,15 +260,27 @@ func apiSetEncryptLocalFiles(_ enable: Bool) throws {
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetPQEnabled(_ enable: Bool) throws {
|
||||
let r = chatSendCmdSync(.apiSetPQEnabled(enable: enable))
|
||||
func apiSaveAppSettings(settings: AppSettings) throws {
|
||||
let r = chatSendCmdSync(.apiSaveSettings(settings: settings))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiAllowContactPQ(_ contactId: Int64) async throws -> Contact {
|
||||
let r = await chatSendCmd(.apiAllowContactPQ(contactId: contactId))
|
||||
if case let .contactPQAllowed(_, contact) = r { return contact }
|
||||
func apiGetAppSettings(settings: AppSettings) throws -> AppSettings {
|
||||
let r = chatSendCmdSync(.apiGetSettings(settings: settings))
|
||||
if case let .appSettings(settings) = r { return settings }
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetPQEncryption(_ enable: Bool) throws {
|
||||
let r = chatSendCmdSync(.apiSetPQEncryption(enable: enable))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetContactPQ(_ contactId: Int64, _ enable: Bool) async throws -> Contact {
|
||||
let r = await chatSendCmd(.apiSetContactPQ(contactId: contactId, enable: enable))
|
||||
if case let .contactPQAllowed(_, contact, _) = r { return contact }
|
||||
throw r
|
||||
}
|
||||
|
||||
@@ -288,6 +302,10 @@ func apiStorageEncryption(currentKey: String = "", newKey: String = "") async th
|
||||
try await sendCommandOkResp(.apiStorageEncryption(config: DBEncryptionConfig(currentKey: currentKey, newKey: newKey)))
|
||||
}
|
||||
|
||||
func testStorageEncryption(key: String, _ ctrl: chat_ctrl? = nil) async throws {
|
||||
try await sendCommandOkResp(.testStorageEncryption(key: key), ctrl)
|
||||
}
|
||||
|
||||
func apiGetChats() throws -> [ChatData] {
|
||||
let userId = try currentUserId("apiGetChats")
|
||||
return try apiChatsResponse(chatSendCmdSync(.apiGetChats(userId: userId)))
|
||||
@@ -335,11 +353,20 @@ func apiGetChatItemInfo(type: ChatType, id: Int64, itemId: Int64) async throws -
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64) async -> ChatItem? {
|
||||
let cmd: ChatCommand = .apiForwardChatItem(toChatType: toChatType, toChatId: toChatId, fromChatType: fromChatType, fromChatId: fromChatId, itemId: itemId)
|
||||
return await processSendMessageCmd(toChatType: toChatType, cmd: cmd)
|
||||
}
|
||||
|
||||
func apiSendMessage(type: ChatType, id: Int64, file: CryptoFile?, quotedItemId: Int64?, msg: MsgContent, live: Bool = false, ttl: Int? = nil) async -> ChatItem? {
|
||||
let chatModel = ChatModel.shared
|
||||
let cmd: ChatCommand = .apiSendMessage(type: type, id: id, file: file, quotedItemId: quotedItemId, msg: msg, live: live, ttl: ttl)
|
||||
return await processSendMessageCmd(toChatType: type, cmd: cmd)
|
||||
}
|
||||
|
||||
private func processSendMessageCmd(toChatType: ChatType, cmd: ChatCommand) async -> ChatItem? {
|
||||
let chatModel = ChatModel.shared
|
||||
let r: ChatResponse
|
||||
if type == .direct {
|
||||
if toChatType == .direct {
|
||||
var cItem: ChatItem? = nil
|
||||
let endTask = beginBGTask({
|
||||
if let cItem = cItem {
|
||||
@@ -379,7 +406,7 @@ func apiCreateChatItem(noteFolderId: Int64, file: CryptoFile?, msg: MsgContent)
|
||||
}
|
||||
|
||||
private func sendMessageErrorAlert(_ r: ChatResponse) {
|
||||
logger.error("apiSendMessage error: \(String(describing: r))")
|
||||
logger.error("send message error: \(String(describing: r))")
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title: "Error sending message",
|
||||
message: "Error: \(String(describing: r))"
|
||||
@@ -510,8 +537,14 @@ func getNetworkConfig() async throws -> NetCfg? {
|
||||
throw r
|
||||
}
|
||||
|
||||
func setNetworkConfig(_ cfg: NetCfg) throws {
|
||||
let r = chatSendCmdSync(.apiSetNetworkConfig(networkConfig: cfg))
|
||||
func setNetworkConfig(_ cfg: NetCfg, ctrl: chat_ctrl? = nil) throws {
|
||||
let r = chatSendCmdSync(.apiSetNetworkConfig(networkConfig: cfg), ctrl)
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetNetworkInfo(_ networkInfo: UserNetworkInfo) throws {
|
||||
let r = chatSendCmdSync(.apiSetNetworkInfo(networkInfo: networkInfo))
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
@@ -876,6 +909,36 @@ func apiChatUnread(type: ChatType, id: Int64, unreadChat: Bool) async throws {
|
||||
try await sendCommandOkResp(.apiChatUnread(type: type, id: id, unreadChat: unreadChat))
|
||||
}
|
||||
|
||||
func uploadStandaloneFile(user: any UserLike, file: CryptoFile, ctrl: chat_ctrl? = nil) async -> (FileTransferMeta?, String?) {
|
||||
let r = await chatSendCmd(.apiUploadStandaloneFile(userId: user.userId, file: file), ctrl)
|
||||
if case let .sndStandaloneFileCreated(_, fileTransferMeta) = r {
|
||||
return (fileTransferMeta, nil)
|
||||
} else {
|
||||
logger.error("uploadStandaloneFile error: \(String(describing: r))")
|
||||
return (nil, String(describing: r))
|
||||
}
|
||||
}
|
||||
|
||||
func downloadStandaloneFile(user: any UserLike, url: String, file: CryptoFile, ctrl: chat_ctrl? = nil) async -> (RcvFileTransfer?, String?) {
|
||||
let r = await chatSendCmd(.apiDownloadStandaloneFile(userId: user.userId, url: url, file: file), ctrl)
|
||||
if case let .rcvStandaloneFileCreated(_, rcvFileTransfer) = r {
|
||||
return (rcvFileTransfer, nil)
|
||||
} else {
|
||||
logger.error("downloadStandaloneFile error: \(String(describing: r))")
|
||||
return (nil, String(describing: r))
|
||||
}
|
||||
}
|
||||
|
||||
func standaloneFileInfo(url: String, ctrl: chat_ctrl? = nil) async -> MigrationFileLinkData? {
|
||||
let r = await chatSendCmd(.apiStandaloneFileInfo(url: url), ctrl)
|
||||
if case let .standaloneFileInfo(fileMeta) = r {
|
||||
return fileMeta
|
||||
} else {
|
||||
logger.error("standaloneFileInfo error: \(String(describing: r))")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func receiveFile(user: any UserLike, fileId: Int64, auto: Bool = false) async {
|
||||
if let chatItem = await apiReceiveFile(fileId: fileId, encrypted: privacyEncryptLocalFilesGroupDefault.get(), auto: auto) {
|
||||
await chatItemSimpleUpdate(user, chatItem)
|
||||
@@ -921,8 +984,8 @@ func cancelFile(user: User, fileId: Int64) async {
|
||||
}
|
||||
}
|
||||
|
||||
func apiCancelFile(fileId: Int64) async -> AChatItem? {
|
||||
let r = await chatSendCmd(.cancelFile(fileId: fileId))
|
||||
func apiCancelFile(fileId: Int64, ctrl: chat_ctrl? = nil) async -> AChatItem? {
|
||||
let r = await chatSendCmd(.cancelFile(fileId: fileId), ctrl)
|
||||
switch r {
|
||||
case let .sndFileCancelled(_, chatItem, _, _) : return chatItem
|
||||
case let .rcvFileCancelled(_, chatItem, _) : return chatItem
|
||||
@@ -1094,8 +1157,8 @@ func apiMarkChatItemRead(_ cInfo: ChatInfo, _ cItem: ChatItem) async {
|
||||
}
|
||||
}
|
||||
|
||||
private func sendCommandOkResp(_ cmd: ChatCommand) async throws {
|
||||
let r = await chatSendCmd(cmd)
|
||||
private func sendCommandOkResp(_ cmd: ChatCommand, _ ctrl: chat_ctrl? = nil) async throws {
|
||||
let r = await chatSendCmd(cmd, ctrl)
|
||||
if case .cmdOk = r { return }
|
||||
throw r
|
||||
}
|
||||
@@ -1249,6 +1312,7 @@ func initializeChat(start: Bool, confirmStart: Bool = false, dbKey: String? = ni
|
||||
defer { m.ctrlInitInProgress = false }
|
||||
(m.chatDbEncrypted, m.chatDbStatus) = chatMigrateInit(dbKey, confirmMigrations: confirmMigrations)
|
||||
if m.chatDbStatus != .ok { return }
|
||||
NetworkObserver.shared.restartMonitor()
|
||||
// If we migrated successfully means previous re-encryption process on database level finished successfully too
|
||||
if encryptionStartedDefault.get() {
|
||||
encryptionStartedDefault.set(false)
|
||||
@@ -1256,7 +1320,7 @@ func initializeChat(start: Bool, confirmStart: Bool = false, dbKey: String? = ni
|
||||
try apiSetTempFolder(tempFolder: getTempFilesDirectory().path)
|
||||
try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path)
|
||||
try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get())
|
||||
try apiSetPQEnabled(pqExperimentalEnabledDefault.get())
|
||||
try apiSetPQEncryption(pqExperimentalEnabledDefault.get())
|
||||
m.chatInitialized = true
|
||||
m.currentUser = try apiGetActiveUser()
|
||||
if m.currentUser == nil {
|
||||
@@ -1336,6 +1400,16 @@ func startChat(refreshInvitations: Bool = true) throws {
|
||||
chatLastStartGroupDefault.set(Date.now)
|
||||
}
|
||||
|
||||
func startChatWithTemporaryDatabase(ctrl: chat_ctrl) throws -> User? {
|
||||
logger.debug("startChatWithTemporaryDatabase")
|
||||
let migrationActiveUser = try? apiGetActiveUser(ctrl: ctrl) ?? apiCreateActiveUser(Profile(displayName: "Temp", fullName: ""), ctrl: ctrl)
|
||||
try setNetworkConfig(getNetCfg(), ctrl: ctrl)
|
||||
try apiSetTempFolder(tempFolder: getMigrationTempFilesDirectory().path, ctrl: ctrl)
|
||||
try apiSetFilesFolder(filesFolder: getMigrationTempFilesDirectory().path, ctrl: ctrl)
|
||||
_ = try apiStartChat(ctrl: ctrl)
|
||||
return migrationActiveUser
|
||||
}
|
||||
|
||||
func changeActiveUser(_ userId: Int64, viewPwd: String?) {
|
||||
do {
|
||||
try changeActiveUser_(userId, viewPwd: viewPwd)
|
||||
@@ -1404,6 +1478,8 @@ class ChatReceiver {
|
||||
private var receiveMessages = true
|
||||
private var _lastMsgTime = Date.now
|
||||
|
||||
var messagesChannel: ((ChatResponse) -> Void)? = nil
|
||||
|
||||
static let shared = ChatReceiver()
|
||||
|
||||
var lastMsgTime: Date { get { _lastMsgTime } }
|
||||
@@ -1417,14 +1493,15 @@ class ChatReceiver {
|
||||
}
|
||||
|
||||
func receiveMsgLoop() async {
|
||||
// TODO use function that has timeout
|
||||
if let msg = await chatRecvMsg() {
|
||||
self._lastMsgTime = .now
|
||||
await processReceivedMsg(msg)
|
||||
}
|
||||
if self.receiveMessages {
|
||||
while self.receiveMessages {
|
||||
if let msg = await chatRecvMsg() {
|
||||
self._lastMsgTime = .now
|
||||
await processReceivedMsg(msg)
|
||||
if let messagesChannel {
|
||||
messagesChannel(msg)
|
||||
}
|
||||
}
|
||||
_ = try? await Task.sleep(nanoseconds: 7_500_000)
|
||||
await receiveMsgLoop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1512,34 +1589,30 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
||||
m.removeChat(mergedContact.id)
|
||||
}
|
||||
}
|
||||
case let .contactsSubscribed(_, contactRefs):
|
||||
await updateContactsStatus(contactRefs, status: .connected)
|
||||
case let .contactsDisconnected(_, contactRefs):
|
||||
await updateContactsStatus(contactRefs, status: .disconnected)
|
||||
case let .contactSubSummary(_, contactSubscriptions):
|
||||
await MainActor.run {
|
||||
for sub in contactSubscriptions {
|
||||
// no need to update contact here, and it is slow
|
||||
// if active(user) {
|
||||
// m.updateContact(sub.contact)
|
||||
// }
|
||||
if let err = sub.contactError {
|
||||
processContactSubError(sub.contact, err)
|
||||
} else {
|
||||
m.setContactNetworkStatus(sub.contact, .connected)
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .networkStatus(status, connections):
|
||||
await MainActor.run {
|
||||
// dispatch queue to synchronize access
|
||||
networkStatusesLock.sync {
|
||||
var ns = m.networkStatuses
|
||||
// slow loop is on the background thread
|
||||
for cId in connections {
|
||||
m.networkStatuses[cId] = status
|
||||
ns[cId] = status
|
||||
}
|
||||
// fast model update is on the main thread
|
||||
DispatchQueue.main.sync {
|
||||
m.networkStatuses = ns
|
||||
}
|
||||
}
|
||||
case let .networkStatuses(_, statuses): ()
|
||||
await MainActor.run {
|
||||
// dispatch queue to synchronize access
|
||||
networkStatusesLock.sync {
|
||||
var ns = m.networkStatuses
|
||||
// slow loop is on the background thread
|
||||
for s in statuses {
|
||||
m.networkStatuses[s.agentConnId] = s.networkStatus
|
||||
ns[s.agentConnId] = s.networkStatus
|
||||
}
|
||||
// fast model update is on the main thread
|
||||
DispatchQueue.main.sync {
|
||||
m.networkStatuses = ns
|
||||
}
|
||||
}
|
||||
case let .newChatItem(user, aChatItem):
|
||||
@@ -1714,27 +1787,36 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
||||
case let .rcvFileSndCancelled(user, aChatItem, _):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupFile(aChatItem) }
|
||||
case let .rcvFileProgressXFTP(user, aChatItem, _, _):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
case let .rcvFileError(user, aChatItem):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupFile(aChatItem) }
|
||||
case let .rcvFileProgressXFTP(user, aChatItem, _, _, _):
|
||||
if let aChatItem = aChatItem {
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
}
|
||||
case let .rcvFileError(user, aChatItem, _):
|
||||
if let aChatItem = aChatItem {
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupFile(aChatItem) }
|
||||
}
|
||||
case let .sndFileStart(user, aChatItem, _):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
case let .sndFileComplete(user, aChatItem, _):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupDirectFile(aChatItem) }
|
||||
case let .sndFileRcvCancelled(user, aChatItem, _):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupDirectFile(aChatItem) }
|
||||
if let aChatItem = aChatItem {
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupDirectFile(aChatItem) }
|
||||
}
|
||||
case let .sndFileProgressXFTP(user, aChatItem, _, _, _):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
if let aChatItem = aChatItem {
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
}
|
||||
case let .sndFileCompleteXFTP(user, aChatItem, _):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupFile(aChatItem) }
|
||||
case let .sndFileError(user, aChatItem):
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupFile(aChatItem) }
|
||||
case let .sndFileError(user, aChatItem, _):
|
||||
if let aChatItem = aChatItem {
|
||||
await chatItemSimpleUpdate(user, aChatItem)
|
||||
Task { cleanupFile(aChatItem) }
|
||||
}
|
||||
case let .callInvitation(invitation):
|
||||
await MainActor.run {
|
||||
m.callInvitations[invitation.contact.id] = invitation
|
||||
@@ -1834,7 +1916,7 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
||||
case let .contactPQEnabled(user, contact, _):
|
||||
if active(user) {
|
||||
await MainActor.run {
|
||||
m.updateContact(contact) // or updateContactConnectionStats?
|
||||
m.updateContact(contact)
|
||||
}
|
||||
}
|
||||
default:
|
||||
@@ -1880,26 +1962,6 @@ func chatItemSimpleUpdate(_ user: any UserLike, _ aChatItem: AChatItem) async {
|
||||
}
|
||||
}
|
||||
|
||||
func updateContactsStatus(_ contactRefs: [ContactRef], status: NetworkStatus) async {
|
||||
let m = ChatModel.shared
|
||||
await MainActor.run {
|
||||
for c in contactRefs {
|
||||
m.networkStatuses[c.agentConnId] = status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processContactSubError(_ contact: Contact, _ chatError: ChatError) {
|
||||
let m = ChatModel.shared
|
||||
var err: String
|
||||
switch chatError {
|
||||
case .errorAgent(agentError: .BROKER(_, .NETWORK)): err = "network"
|
||||
case .errorAgent(agentError: .SMP(smpErr: .AUTH)): err = "contact deleted"
|
||||
default: err = String(describing: chatError)
|
||||
}
|
||||
m.setContactNetworkStatus(contact, .error(connectionError: err))
|
||||
}
|
||||
|
||||
func refreshCallInvitations() throws {
|
||||
let m = ChatModel.shared
|
||||
let callInvitations = try justRefreshCallInvitations()
|
||||
|
||||
@@ -44,7 +44,12 @@ struct SimpleXApp: App {
|
||||
chatModel.appOpenUrl = url
|
||||
}
|
||||
.onAppear() {
|
||||
if kcAppPassword.get() == nil || kcSelfDestructPassword.get() == nil {
|
||||
// Present screen for continue migration if it wasn't finished yet
|
||||
if chatModel.migrationState != nil {
|
||||
// It's important, otherwise, user may be locked in undefined state
|
||||
onboardingStageDefault.set(.step1_SimpleXInfo)
|
||||
chatModel.onboardingStage = onboardingStageDefault.get()
|
||||
} else if kcAppPassword.get() == nil || kcSelfDestructPassword.get() == nil {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
|
||||
initChatAndMigrate()
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import SwiftUI
|
||||
import WebKit
|
||||
import SimpleXChat
|
||||
import AVFoundation
|
||||
|
||||
struct ActiveCallView: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@@ -21,6 +22,7 @@ struct ActiveCallView: View {
|
||||
@Binding var canConnectCall: Bool
|
||||
@State var prevColorScheme: ColorScheme = .dark
|
||||
@State var pipShown = false
|
||||
@State var wasConnected = false
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .topLeading) {
|
||||
@@ -69,6 +71,11 @@ struct ActiveCallView: View {
|
||||
Task { await m.callCommand.setClient(nil) }
|
||||
AppDelegate.keepScreenOn(false)
|
||||
client?.endCall()
|
||||
CallSoundsPlayer.shared.stop()
|
||||
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient)
|
||||
if (wasConnected) {
|
||||
CallSoundsPlayer.shared.vibrate(long: true)
|
||||
}
|
||||
}
|
||||
.background(m.activeCallViewIsCollapsed ? .clear : .black)
|
||||
// Quite a big delay when opening/closing the view when a scheme changes (globally) this way. It's not needed when CallKit is used since status bar is green with white text on it
|
||||
@@ -103,6 +110,11 @@ struct ActiveCallView: View {
|
||||
call.callState = .invitationSent
|
||||
call.localCapabilities = capabilities
|
||||
}
|
||||
if call.supportsVideo {
|
||||
try? AVAudioSession.sharedInstance().setCategory(.playback, options: .defaultToSpeaker)
|
||||
}
|
||||
CallSoundsPlayer.shared.startConnectingCallSound()
|
||||
activeCallWaitDeliveryReceipt()
|
||||
}
|
||||
case let .offer(offer, iceCandidates, capabilities):
|
||||
Task {
|
||||
@@ -126,6 +138,8 @@ struct ActiveCallView: View {
|
||||
}
|
||||
await MainActor.run {
|
||||
call.callState = .negotiated
|
||||
CallSoundsPlayer.shared.stop()
|
||||
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient)
|
||||
}
|
||||
}
|
||||
case let .ice(iceCandidates):
|
||||
@@ -144,6 +158,10 @@ struct ActiveCallView: View {
|
||||
: CallController.shared.reportIncomingCall(call: call, connectedAt: nil)
|
||||
call.callState = .connected
|
||||
call.connectedAt = .now
|
||||
if !wasConnected {
|
||||
CallSoundsPlayer.shared.vibrate(long: false)
|
||||
wasConnected = true
|
||||
}
|
||||
}
|
||||
if state.connectionState == "closed" {
|
||||
closeCallView(client)
|
||||
@@ -161,6 +179,10 @@ struct ActiveCallView: View {
|
||||
call.callState = .connected
|
||||
call.connectionInfo = connectionInfo
|
||||
call.connectedAt = .now
|
||||
if !wasConnected {
|
||||
CallSoundsPlayer.shared.vibrate(long: false)
|
||||
wasConnected = true
|
||||
}
|
||||
case .ended:
|
||||
closeCallView(client)
|
||||
call.callState = .ended
|
||||
@@ -187,6 +209,22 @@ struct ActiveCallView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func activeCallWaitDeliveryReceipt() {
|
||||
ChatReceiver.shared.messagesChannel = { msg in
|
||||
guard let call = ChatModel.shared.activeCall, call.callState == .invitationSent else {
|
||||
ChatReceiver.shared.messagesChannel = nil
|
||||
return
|
||||
}
|
||||
if case let .chatItemStatusUpdated(_, msg) = msg,
|
||||
msg.chatInfo.id == call.contact.id,
|
||||
case .sndCall = msg.chatItem.content,
|
||||
case .sndRcvd = msg.chatItem.meta.itemStatus {
|
||||
CallSoundsPlayer.shared.startInCallSound()
|
||||
ChatReceiver.shared.messagesChannel = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func closeCallView(_ client: WebRTCClient) {
|
||||
if m.activeCall != nil {
|
||||
m.showCallView = false
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
import UIKit
|
||||
|
||||
class SoundPlayer {
|
||||
static let shared = SoundPlayer()
|
||||
@@ -43,3 +44,63 @@ class SoundPlayer {
|
||||
audioPlayer = nil
|
||||
}
|
||||
}
|
||||
|
||||
class CallSoundsPlayer {
|
||||
static let shared = CallSoundsPlayer()
|
||||
private var audioPlayer: AVAudioPlayer?
|
||||
private var playerTask: Task = Task {}
|
||||
|
||||
private func start(_ soundName: String, delayMs: Double) {
|
||||
audioPlayer?.stop()
|
||||
playerTask.cancel()
|
||||
logger.debug("start \(soundName)")
|
||||
guard let path = Bundle.main.path(forResource: soundName, ofType: "mp3", inDirectory: "sounds") else {
|
||||
logger.debug("start: file not found")
|
||||
return
|
||||
}
|
||||
do {
|
||||
let player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
|
||||
if player.prepareToPlay() {
|
||||
audioPlayer = player
|
||||
}
|
||||
} catch {
|
||||
logger.debug("start: AVAudioPlayer error \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
playerTask = Task {
|
||||
while let player = audioPlayer {
|
||||
player.play()
|
||||
do {
|
||||
try await Task.sleep(nanoseconds: UInt64((player.duration * 1_000_000_000) + delayMs * 1_000_000))
|
||||
} catch {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func startConnectingCallSound() {
|
||||
start("connecting_call", delayMs: 0)
|
||||
}
|
||||
|
||||
func startInCallSound() {
|
||||
// Taken from https://github.com/TelegramOrg/Telegram-Android
|
||||
// https://github.com/TelegramOrg/Telegram-Android/blob/master/LICENSE
|
||||
start("in_call", delayMs: 1000)
|
||||
}
|
||||
|
||||
func stop() {
|
||||
playerTask.cancel()
|
||||
audioPlayer?.stop()
|
||||
audioPlayer = nil
|
||||
}
|
||||
|
||||
func vibrate(long: Bool) {
|
||||
// iOS just don't want to vibrate more than once after a short period of time, and all 'styles' feel the same
|
||||
if long {
|
||||
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)
|
||||
} else {
|
||||
UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,17 +431,18 @@ struct RTCIceServer: Codable, Equatable {
|
||||
}
|
||||
|
||||
// the servers are expected in this format:
|
||||
// stun:stun.simplex.im:443?transport=tcp
|
||||
// turn:private:yleob6AVkiNI87hpR94Z@turn.simplex.im:443?transport=tcp
|
||||
// stuns:stun.simplex.im:443?transport=tcp
|
||||
// turns:private2:Hxuq2QxUjnhj96Zq2r4HjqHRj@turn.simplex.im:443?transport=tcp
|
||||
func parseRTCIceServer(_ str: String) -> RTCIceServer? {
|
||||
var s = replaceScheme(str, "stun:")
|
||||
s = replaceScheme(s, "stuns:")
|
||||
s = replaceScheme(s, "turn:")
|
||||
s = replaceScheme(s, "turns:")
|
||||
if let u: URL = URL(string: s),
|
||||
let scheme = u.scheme,
|
||||
let host = u.host,
|
||||
let port = u.port,
|
||||
u.path == "" && (scheme == "stun" || scheme == "turn" || scheme == "turns") {
|
||||
u.path == "" && (scheme == "stun" || scheme == "stuns" || scheme == "turn" || scheme == "turns") {
|
||||
let query = u.query == nil || u.query == "" ? "" : "?" + (u.query ?? "")
|
||||
return RTCIceServer(
|
||||
urls: ["\(scheme):\(host):\(port)\(query)"],
|
||||
|
||||
@@ -49,7 +49,7 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
|
||||
}
|
||||
|
||||
private let rtcAudioSession = RTCAudioSession.sharedInstance()
|
||||
private let audioQueue = DispatchQueue(label: "audio")
|
||||
private let audioQueue = DispatchQueue(label: "chat.simplex.app.audio")
|
||||
private var sendCallResponse: (WVAPIMessage) async -> Void
|
||||
var activeCall: Binding<Call?>
|
||||
private var localRendererAspectRatio: Binding<CGFloat?>
|
||||
@@ -65,14 +65,14 @@ final class WebRTCClient: NSObject, RTCVideoViewDelegate, RTCFrameEncryptorDeleg
|
||||
self.localRendererAspectRatio = localRendererAspectRatio
|
||||
rtcAudioSession.useManualAudio = CallController.useCallKit()
|
||||
rtcAudioSession.isAudioEnabled = !CallController.useCallKit()
|
||||
logger.debug("WebRTCClient: rtcAudioSession has manual audio \(self.rtcAudioSession.useManualAudio) and audio enabled \(self.rtcAudioSession.isAudioEnabled)}")
|
||||
logger.debug("WebRTCClient: rtcAudioSession has manual audio \(self.rtcAudioSession.useManualAudio) and audio enabled \(self.rtcAudioSession.isAudioEnabled)")
|
||||
super.init()
|
||||
}
|
||||
|
||||
let defaultIceServers: [WebRTC.RTCIceServer] = [
|
||||
WebRTC.RTCIceServer(urlStrings: ["stun:stun.simplex.im:443"]),
|
||||
WebRTC.RTCIceServer(urlStrings: ["turn:turn.simplex.im:443?transport=udp"], username: "private", credential: "yleob6AVkiNI87hpR94Z"),
|
||||
WebRTC.RTCIceServer(urlStrings: ["turn:turn.simplex.im:443?transport=tcp"], username: "private", credential: "yleob6AVkiNI87hpR94Z"),
|
||||
WebRTC.RTCIceServer(urlStrings: ["stuns:stun.simplex.im:443"]),
|
||||
//WebRTC.RTCIceServer(urlStrings: ["turns:turn.simplex.im:443?transport=udp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj"),
|
||||
WebRTC.RTCIceServer(urlStrings: ["turns:turn.simplex.im:443?transport=tcp"], username: "private2", credential: "Hxuq2QxUjnhj96Zq2r4HjqHRj"),
|
||||
]
|
||||
|
||||
func initializeCall(_ iceServers: [WebRTC.RTCIceServer]?, _ mediaType: CallMediaType, _ aesKey: String?, _ relay: Bool?) -> Call {
|
||||
|
||||
@@ -171,15 +171,15 @@ struct ChatInfoView: View {
|
||||
if pqExperimentalEnabled,
|
||||
let conn = contact.activeConn {
|
||||
Section {
|
||||
infoRow(Text(String("PQ E2E encryption")), conn.connPQEnabled ? "Enabled" : "Disabled")
|
||||
if !conn.enablePQ {
|
||||
infoRow(Text(String("E2E encryption")), conn.connPQEnabled ? "Quantum resistant" : "Standard")
|
||||
if !conn.pqEncryption {
|
||||
allowPQButton()
|
||||
}
|
||||
} header: {
|
||||
Text(String("Post-quantum E2E encryption"))
|
||||
Text(String("Quantum resistant E2E encryption"))
|
||||
} footer: {
|
||||
if !conn.enablePQ {
|
||||
Text(String("After allowing post-quantum encryption, it will be enabled after several messages if your contact also allows it."))
|
||||
if !conn.pqEncryption {
|
||||
Text(String("After allowing quantum resistant encryption, it will be enabled after several messages if your contact also allows it."))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -576,14 +576,14 @@ struct ChatInfoView: View {
|
||||
private func allowContactPQEncryption() {
|
||||
Task {
|
||||
do {
|
||||
let ct = try await apiAllowContactPQ(contact.apiId)
|
||||
let ct = try await apiSetContactPQ(contact.apiId, true)
|
||||
contact = ct
|
||||
await MainActor.run {
|
||||
chatModel.updateContact(contact)
|
||||
chatModel.updateContact(ct)
|
||||
dismiss()
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("allowContactPQEncryption apiAllowContactPQ error: \(responseError(error))")
|
||||
logger.error("allowContactPQEncryption apiSetContactPQ error: \(responseError(error))")
|
||||
let a = getErrorAlert(error, "Error allowing contact PQ encryption")
|
||||
await MainActor.run {
|
||||
alert = .error(title: a.title, error: a.message)
|
||||
@@ -594,8 +594,8 @@ struct ChatInfoView: View {
|
||||
|
||||
func allowContactPQEncryptionAlert() -> Alert {
|
||||
Alert(
|
||||
title: Text(String("Allow post-quantum encryption?")),
|
||||
message: Text(String("This is an experimental feature, it is not recommended to enable it for high importance communications. It may result in connection errors!")),
|
||||
title: Text(String("Allow quantum resistant encryption?")),
|
||||
message: Text(String("This is an experimental feature, it is not recommended to enable it for important chats.")),
|
||||
primaryButton: .destructive(Text(String("Allow")), action: allowContactPQEncryption),
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
|
||||
@@ -11,6 +11,7 @@ import SimpleXChat
|
||||
|
||||
struct CIChatFeatureView: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@ObservedObject var chat: Chat
|
||||
var chatItem: ChatItem
|
||||
@Binding var revealed: Bool
|
||||
var feature: Feature
|
||||
@@ -18,7 +19,7 @@ struct CIChatFeatureView: View {
|
||||
var iconColor: Color
|
||||
|
||||
var body: some View {
|
||||
if !revealed, let fs = mergedFeautures() {
|
||||
if !revealed, let fs = mergedFeatures() {
|
||||
HStack {
|
||||
ForEach(fs, content: featureIconView)
|
||||
}
|
||||
@@ -47,7 +48,7 @@ struct CIChatFeatureView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func mergedFeautures() -> [FeatureInfo]? {
|
||||
private func mergedFeatures() -> [FeatureInfo]? {
|
||||
var fs: [FeatureInfo] = []
|
||||
var icons: Set<String> = []
|
||||
if var i = m.getChatItemIndex(chatItem) {
|
||||
@@ -67,8 +68,8 @@ struct CIChatFeatureView: View {
|
||||
switch ci.content {
|
||||
case let .rcvChatFeature(feature, enabled, param): FeatureInfo(feature, enabled.iconColor, param)
|
||||
case let .sndChatFeature(feature, enabled, param): FeatureInfo(feature, enabled.iconColor, param)
|
||||
case let .rcvGroupFeature(feature, preference, param): FeatureInfo(feature, preference.enable.iconColor, param)
|
||||
case let .sndGroupFeature(feature, preference, param): FeatureInfo(feature, preference.enable.iconColor, param)
|
||||
case let .rcvGroupFeature(feature, preference, param, role): FeatureInfo(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor, param)
|
||||
case let .sndGroupFeature(feature, preference, param, role): FeatureInfo(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor, param)
|
||||
default: nil
|
||||
}
|
||||
}
|
||||
@@ -103,6 +104,6 @@ struct CIChatFeatureView: View {
|
||||
struct CIChatFeatureView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let enabled = FeatureEnabled(forUser: false, forContact: false)
|
||||
CIChatFeatureView(chatItem: ChatItem.getChatFeatureSample(.fullDelete, enabled), revealed: Binding.constant(true), feature: ChatFeature.fullDelete, iconColor: enabled.iconColor)
|
||||
CIChatFeatureView(chat: Chat.sampleData, chatItem: ChatItem.getChatFeatureSample(.fullDelete, enabled), revealed: Binding.constant(true), feature: ChatFeature.fullDelete, iconColor: enabled.iconColor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ struct CIEventView: View {
|
||||
.padding(.horizontal, 6)
|
||||
.padding(.vertical, 4)
|
||||
.textSelection(.disabled)
|
||||
.lineLimit(3)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,19 +69,12 @@ struct CIFileView: View {
|
||||
return false
|
||||
}
|
||||
|
||||
private func fileSizeValid() -> Bool {
|
||||
if let file = file {
|
||||
return file.fileSize <= getMaxFileSize(file.fileProtocol)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private func fileAction() {
|
||||
logger.debug("CIFileView fileAction")
|
||||
if let file = file {
|
||||
switch (file.fileStatus) {
|
||||
case .rcvInvitation:
|
||||
if fileSizeValid() {
|
||||
if fileSizeValid(file) {
|
||||
Task {
|
||||
logger.debug("CIFileView fileAction - in .rcvInvitation, in Task")
|
||||
if let user = m.currentUser {
|
||||
@@ -143,7 +136,7 @@ struct CIFileView: View {
|
||||
case .sndCancelled: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
|
||||
case .sndError: fileIcon("doc.fill", innerIcon: "xmark", innerIconSize: 10)
|
||||
case .rcvInvitation:
|
||||
if fileSizeValid() {
|
||||
if fileSizeValid(file) {
|
||||
fileIcon("arrow.down.doc.fill", color: .accentColor)
|
||||
} else {
|
||||
fileIcon("doc.fill", color: .orange, innerIcon: "exclamationmark", innerIconSize: 12)
|
||||
@@ -201,6 +194,13 @@ struct CIFileView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func fileSizeValid(_ file: CIFile?) -> Bool {
|
||||
if let file = file {
|
||||
return file.fileSize <= getMaxFileSize(file.fileProtocol)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func saveCryptoFile(_ fileSource: CryptoFile) {
|
||||
if let cfArgs = fileSource.cryptoArgs {
|
||||
let url = getAppFilePath(fileSource.filePath)
|
||||
|
||||
@@ -70,14 +70,14 @@ struct CIImageView: View {
|
||||
}
|
||||
|
||||
private func imageView(_ img: UIImage) -> some View {
|
||||
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : img.imageData == nil ? .infinity : maxWidth
|
||||
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : maxWidth
|
||||
DispatchQueue.main.async { imgWidth = w }
|
||||
return ZStack(alignment: .topTrailing) {
|
||||
if img.imageData == nil {
|
||||
Image(uiImage: img)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: w)
|
||||
.frame(width: w)
|
||||
} else {
|
||||
SwiftyGif(image: img)
|
||||
.frame(width: w, height: w * img.size.height / img.size.width)
|
||||
|
||||
@@ -126,7 +126,7 @@ struct CIVideoView: View {
|
||||
if !decryptionInProgress {
|
||||
Button {
|
||||
decrypt(file: file) {
|
||||
if let decrypted = urlDecrypted {
|
||||
if urlDecrypted != nil {
|
||||
videoPlaying = true
|
||||
player?.play()
|
||||
}
|
||||
@@ -243,13 +243,13 @@ struct CIVideoView: View {
|
||||
}
|
||||
|
||||
private func imageView(_ img: UIImage) -> some View {
|
||||
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : .infinity
|
||||
let w = img.size.width <= img.size.height ? maxWidth * 0.75 : maxWidth
|
||||
DispatchQueue.main.async { videoWidth = w }
|
||||
return ZStack(alignment: .topTrailing) {
|
||||
Image(uiImage: img)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: w)
|
||||
.frame(width: w)
|
||||
loadingIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ struct FramedItemView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let itemForwarded = chatItem.meta.itemForwarded {
|
||||
framedItemHeader(icon: "arrowshape.turn.up.forward", caption: Text(itemForwarded.text(chat.chatInfo.chatType)).italic(), pad: true)
|
||||
}
|
||||
|
||||
ChatItemContentView(chat: chat, chatItem: chatItem, revealed: $revealed, msgContentView: framedMsgContentView)
|
||||
@@ -163,7 +165,7 @@ struct FramedItemView: View {
|
||||
)
|
||||
}
|
||||
|
||||
@ViewBuilder func framedItemHeader(icon: String? = nil, caption: Text) -> some View {
|
||||
@ViewBuilder func framedItemHeader(icon: String? = nil, caption: Text, pad: Bool = false) -> some View {
|
||||
let v = HStack(spacing: 6) {
|
||||
if let icon = icon {
|
||||
Image(systemName: icon)
|
||||
@@ -178,7 +180,7 @@ struct FramedItemView: View {
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.top, 6)
|
||||
.padding(.bottom, chatItem.quotedItem == nil ? 6 : 0) // TODO think how to regroup
|
||||
.padding(.bottom, pad || (chatItem.quotedItem == nil && chatItem.meta.itemForwarded == nil) ? 6 : 0)
|
||||
.overlay(DetermineWidth())
|
||||
.frame(minWidth: msgWidth, alignment: .leading)
|
||||
.background(chatItemFrameContextColor(chatItem, colorScheme))
|
||||
@@ -253,6 +255,7 @@ struct FramedItemView: View {
|
||||
ciQuotedMsgTextView(qi, lines: 3)
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.padding(.top, 6)
|
||||
.padding(.horizontal, 12)
|
||||
}
|
||||
@@ -352,9 +355,9 @@ private struct MetaColorPreferenceKey: PreferenceKey {
|
||||
|
||||
func onlyImageOrVideo(_ ci: ChatItem) -> Bool {
|
||||
if case let .image(text, _) = ci.content.msgContent {
|
||||
return ci.meta.itemDeleted == nil && !ci.meta.isLive && ci.quotedItem == nil && text == ""
|
||||
return ci.meta.itemDeleted == nil && !ci.meta.isLive && ci.quotedItem == nil && ci.meta.itemForwarded == nil && text == ""
|
||||
} else if case let .video(text, _, _) = ci.content.msgContent {
|
||||
return ci.meta.itemDeleted == nil && !ci.meta.isLive && ci.quotedItem == nil && text == ""
|
||||
return ci.meta.itemDeleted == nil && !ci.meta.isLive && ci.quotedItem == nil && ci.meta.itemForwarded == nil && text == ""
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// ChatItemForwardingView.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by spaced4ndy on 12.04.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
struct ChatItemForwardingView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var ci: ChatItem
|
||||
var fromChatInfo: ChatInfo
|
||||
@Binding var composeState: ComposeState
|
||||
|
||||
@State private var searchText: String = ""
|
||||
@FocusState private var searchFocused
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
forwardListView()
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .principal) {
|
||||
Text("Forward")
|
||||
.bold()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func forwardListView() -> some View {
|
||||
VStack(alignment: .leading) {
|
||||
let chatsToForwardTo = filterChatsToForwardTo()
|
||||
if !chatsToForwardTo.isEmpty {
|
||||
ScrollView {
|
||||
LazyVStack(alignment: .leading, spacing: 8) {
|
||||
searchFieldView(text: $searchText, focussed: $searchFocused)
|
||||
.padding(.leading, 2)
|
||||
let s = searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
|
||||
let chats = s == "" ? chatsToForwardTo : chatsToForwardTo.filter { filterChatSearched($0, s) }
|
||||
ForEach(chats) { chat in
|
||||
Divider()
|
||||
forwardListNavLinkView(chat)
|
||||
.disabled(chatModel.deletedChats.contains(chat.chatInfo.id))
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.background(Color(uiColor: .systemBackground))
|
||||
.cornerRadius(12)
|
||||
.padding(.horizontal)
|
||||
}
|
||||
.background(Color(.systemGroupedBackground))
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func filterChatsToForwardTo() -> [Chat] {
|
||||
var filteredChats = chatModel.chats.filter({ canForwardToChat($0) })
|
||||
if let index = filteredChats.firstIndex(where: { $0.chatInfo.chatType == .local }) {
|
||||
let privateNotes = filteredChats.remove(at: index)
|
||||
filteredChats.insert(privateNotes, at: 0)
|
||||
}
|
||||
return filteredChats
|
||||
}
|
||||
|
||||
private func filterChatSearched(_ chat: Chat, _ searchStr: String) -> Bool {
|
||||
let cInfo = chat.chatInfo
|
||||
return switch cInfo {
|
||||
case let .direct(contact):
|
||||
viewNameContains(cInfo, searchStr) ||
|
||||
contact.profile.displayName.localizedLowercase.contains(searchStr) ||
|
||||
contact.fullName.localizedLowercase.contains(searchStr)
|
||||
default:
|
||||
viewNameContains(cInfo, searchStr)
|
||||
}
|
||||
|
||||
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
|
||||
cInfo.chatViewName.localizedLowercase.contains(s)
|
||||
}
|
||||
}
|
||||
|
||||
private func canForwardToChat(_ chat: Chat) -> Bool {
|
||||
switch chat.chatInfo {
|
||||
case let .direct(contact): contact.sendMsgEnabled && !contact.nextSendGrpInv
|
||||
case let .group(groupInfo): groupInfo.sendMsgEnabled
|
||||
case let .local(noteFolder): noteFolder.sendMsgEnabled
|
||||
case .contactRequest: false
|
||||
case .contactConnection: false
|
||||
case .invalidJSON: false
|
||||
}
|
||||
}
|
||||
|
||||
private func emptyList() -> some View {
|
||||
Text("No filtered chats")
|
||||
.foregroundColor(.secondary)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
@ViewBuilder private func forwardListNavLinkView(_ chat: Chat) -> some View {
|
||||
Button {
|
||||
dismiss()
|
||||
if chat.id == fromChatInfo.id {
|
||||
composeState = ComposeState(
|
||||
message: composeState.message,
|
||||
preview: composeState.linkPreview != nil ? composeState.preview : .noPreview,
|
||||
contextItem: .forwardingItem(chatItem: ci, fromChatInfo: fromChatInfo)
|
||||
)
|
||||
} else {
|
||||
composeState = ComposeState.init(forwardingItem: ci, fromChatInfo: fromChatInfo)
|
||||
chatModel.chatId = chat.id
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
ChatInfoImage(chat: chat)
|
||||
.frame(width: 30, height: 30)
|
||||
.padding(.trailing, 2)
|
||||
Text(chat.chatInfo.chatViewName)
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(1)
|
||||
if chat.chatInfo.incognito {
|
||||
Spacer()
|
||||
Image(systemName: "theatermasks")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 22, height: 22)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ChatItemForwardingView(
|
||||
ci: ChatItem.getSample(1, .directSnd, .now, "hello"),
|
||||
fromChatInfo: .direct(contact: Contact.sampleData),
|
||||
composeState: Binding.constant(ComposeState(message: "hello"))
|
||||
)
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import SimpleXChat
|
||||
|
||||
struct ChatItemInfoView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
var ci: ChatItem
|
||||
@Binding var chatItemInfo: ChatItemInfo?
|
||||
@@ -21,6 +22,7 @@ struct ChatItemInfoView: View {
|
||||
enum CIInfoTab {
|
||||
case history
|
||||
case quote
|
||||
case forwarded
|
||||
case delivery
|
||||
}
|
||||
|
||||
@@ -68,9 +70,20 @@ struct ChatItemInfoView: View {
|
||||
if ci.quotedItem != nil {
|
||||
numTabs += 1
|
||||
}
|
||||
if chatItemInfo?.forwardedFromChatItem != nil {
|
||||
numTabs += 1
|
||||
}
|
||||
return numTabs
|
||||
}
|
||||
|
||||
private var local: Bool {
|
||||
switch ci.chatDir {
|
||||
case .localSnd: true
|
||||
case .localRcv: true
|
||||
default: false
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func itemInfoView() -> some View {
|
||||
if numTabs > 1 {
|
||||
TabView(selection: $selection) {
|
||||
@@ -93,6 +106,13 @@ struct ChatItemInfoView: View {
|
||||
}
|
||||
.tag(CIInfoTab.quote)
|
||||
}
|
||||
if let forwardedFromItem = chatItemInfo?.forwardedFromChatItem {
|
||||
forwardedFromTab(forwardedFromItem)
|
||||
.tabItem {
|
||||
Label(local ? "Saved" : "Forwarded", systemImage: "arrowshape.turn.up.forward")
|
||||
}
|
||||
.tag(CIInfoTab.forwarded)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
if chatItemInfo?.memberDeliveryStatuses != nil {
|
||||
@@ -275,6 +295,75 @@ struct ChatItemInfoView: View {
|
||||
: Color(uiColor: .tertiarySystemGroupedBackground)
|
||||
}
|
||||
|
||||
@ViewBuilder private func forwardedFromTab(_ forwardedFromItem: AChatItem) -> some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
details()
|
||||
Divider().padding(.vertical)
|
||||
Text(local ? "Saved from" : "Forwarded from")
|
||||
.font(.title2)
|
||||
.padding(.bottom, 4)
|
||||
forwardedFromView(forwardedFromItem)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.frame(maxHeight: .infinity, alignment: .top)
|
||||
}
|
||||
|
||||
private func forwardedFromView(_ forwardedFromItem: AChatItem) -> some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Button {
|
||||
Task {
|
||||
await MainActor.run {
|
||||
chatModel.chatId = forwardedFromItem.chatInfo.id
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
forwardedFromSender(forwardedFromItem)
|
||||
}
|
||||
|
||||
if !local {
|
||||
Divider().padding(.top, 32)
|
||||
Text("Recipient(s) can't see who this message is from.")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func forwardedFromSender(_ forwardedFromItem: AChatItem) -> some View {
|
||||
HStack {
|
||||
ChatInfoImage(chat: Chat(chatInfo: forwardedFromItem.chatInfo))
|
||||
.frame(width: 48, height: 48)
|
||||
.padding(.trailing, 6)
|
||||
|
||||
if forwardedFromItem.chatItem.chatDir.sent {
|
||||
VStack(alignment: .leading) {
|
||||
Text("you")
|
||||
.italic()
|
||||
.foregroundColor(.primary)
|
||||
Text(forwardedFromItem.chatInfo.chatViewName)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
} else if case let .groupRcv(groupMember) = forwardedFromItem.chatItem.chatDir {
|
||||
VStack(alignment: .leading) {
|
||||
Text(groupMember.chatViewName)
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(1)
|
||||
Text(forwardedFromItem.chatInfo.chatViewName)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
} else {
|
||||
Text(forwardedFromItem.chatInfo.chatViewName)
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func deliveryTab(_ memberDeliveryStatuses: [MemberDeliveryStatus]) -> some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
|
||||
@@ -46,7 +46,7 @@ struct ChatItemView: View {
|
||||
let ci = chatItem
|
||||
if chatItem.meta.itemDeleted != nil && (!revealed || chatItem.isDeletedContent) {
|
||||
MarkedDeletedItemView(chat: chat, chatItem: chatItem, revealed: $revealed)
|
||||
} else if ci.quotedItem == nil && ci.meta.itemDeleted == nil && !ci.meta.isLive {
|
||||
} else if ci.quotedItem == nil && ci.meta.itemForwarded == nil && ci.meta.itemDeleted == nil && !ci.meta.isLive {
|
||||
if let mc = ci.content.msgContent, mc.isText && isShortEmoji(ci.content.text) {
|
||||
EmojiItemView(chat: chat, chatItem: ci)
|
||||
} else if ci.content.text.isEmpty, case let .voice(_, duration) = ci.content.msgContent {
|
||||
@@ -102,20 +102,19 @@ struct ChatItemContentView<Content: View>: View {
|
||||
case let .rcvChatPreference(feature, allowed, param):
|
||||
CIFeaturePreferenceView(chat: chat, chatItem: chatItem, feature: feature, allowed: allowed, param: param)
|
||||
case let .sndChatPreference(feature, _, _):
|
||||
CIChatFeatureView(chatItem: chatItem, revealed: $revealed, feature: feature, icon: feature.icon, iconColor: .secondary)
|
||||
case let .rcvGroupFeature(feature, preference, _): chatFeatureView(feature, preference.enable.iconColor)
|
||||
case let .sndGroupFeature(feature, preference, _): chatFeatureView(feature, preference.enable.iconColor)
|
||||
CIChatFeatureView(chat: chat, chatItem: chatItem, revealed: $revealed, feature: feature, icon: feature.icon, iconColor: .secondary)
|
||||
case let .rcvGroupFeature(feature, preference, _, role): chatFeatureView(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor)
|
||||
case let .sndGroupFeature(feature, preference, _, role): chatFeatureView(feature, preference.enabled(role, for: chat.chatInfo.groupInfo?.membership).iconColor)
|
||||
case let .rcvChatFeatureRejected(feature): chatFeatureView(feature, .red)
|
||||
case let .rcvGroupFeatureRejected(feature): chatFeatureView(feature, .red)
|
||||
case .sndModerated: deletedItemView()
|
||||
case .rcvModerated: deletedItemView()
|
||||
case .rcvBlocked: deletedItemView()
|
||||
case let .sndDirectE2EEInfo(e2eeInfo): CIEventView(eventText: directE2EEInfoText(e2eeInfo))
|
||||
case let .rcvDirectE2EEInfo(e2eeInfo): CIEventView(eventText: directE2EEInfoText(e2eeInfo))
|
||||
case .sndGroupE2EEInfo: CIEventView(eventText: e2eeInfoNoPQText())
|
||||
case .rcvGroupE2EEInfo: CIEventView(eventText: e2eeInfoNoPQText())
|
||||
case let .invalidJSON(json): CIInvalidJSONView(json: json)
|
||||
// TODO proper items
|
||||
case .sndDirectE2EEInfo: CIEventView(eventText: Text(chatItem.content.text))
|
||||
case .rcvDirectE2EEInfo: CIEventView(eventText: Text(chatItem.content.text))
|
||||
case .sndGroupE2EEInfo: CIEventView(eventText: Text(chatItem.content.text))
|
||||
case .rcvGroupE2EEInfo: CIEventView(eventText: Text(chatItem.content.text))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +149,7 @@ struct ChatItemContentView<Content: View>: View {
|
||||
}
|
||||
|
||||
private func chatFeatureView(_ feature: Feature, _ iconColor: Color) -> some View {
|
||||
CIChatFeatureView(chatItem: chatItem, revealed: $revealed, feature: feature, iconColor: iconColor)
|
||||
CIChatFeatureView(chat: chat, chatItem: chatItem, revealed: $revealed, feature: feature, iconColor: iconColor)
|
||||
}
|
||||
|
||||
private var mergedGroupEventText: Text? {
|
||||
@@ -175,6 +174,22 @@ struct ChatItemContentView<Content: View>: View {
|
||||
Text(members)
|
||||
}
|
||||
}
|
||||
|
||||
private func directE2EEInfoText(_ info: E2EEInfo) -> Text {
|
||||
info.pqEnabled
|
||||
? Text("Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.fontWeight(.light)
|
||||
: e2eeInfoNoPQText()
|
||||
}
|
||||
|
||||
private func e2eeInfoNoPQText() -> Text {
|
||||
Text("Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.fontWeight(.light)
|
||||
}
|
||||
}
|
||||
|
||||
func chatEventText(_ text: Text) -> Text {
|
||||
|
||||
@@ -17,6 +17,7 @@ struct ChatView: View {
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
@Environment(\.scenePhase) var scenePhase
|
||||
@State @ObservedObject var chat: Chat
|
||||
@State private var showChatInfoSheet: Bool = false
|
||||
@State private var showAddMembersSheet: Bool = false
|
||||
@@ -82,7 +83,11 @@ struct ChatView: View {
|
||||
initChatView()
|
||||
}
|
||||
.onChange(of: chatModel.chatId) { cId in
|
||||
if cId != nil {
|
||||
showChatInfoSheet = false
|
||||
if let cId {
|
||||
if let c = chatModel.getChat(cId) {
|
||||
chat = c
|
||||
}
|
||||
initChatView()
|
||||
} else {
|
||||
dismiss()
|
||||
@@ -178,7 +183,7 @@ struct ChatView: View {
|
||||
.disabled(!contact.ready || !contact.active)
|
||||
}
|
||||
searchButton()
|
||||
toggleNtfsButton(chat)
|
||||
ToggleNtfsButton(chat: chat)
|
||||
.disabled(!contact.ready || !contact.active)
|
||||
} label: {
|
||||
Image(systemName: "ellipsis")
|
||||
@@ -207,7 +212,7 @@ struct ChatView: View {
|
||||
}
|
||||
Menu {
|
||||
searchButton()
|
||||
toggleNtfsButton(chat)
|
||||
ToggleNtfsButton(chat: chat)
|
||||
} label: {
|
||||
Image(systemName: "ellipsis")
|
||||
}
|
||||
@@ -234,7 +239,9 @@ struct ChatView: View {
|
||||
|
||||
private func initChatView() {
|
||||
let cInfo = chat.chatInfo
|
||||
if case let .direct(contact) = cInfo {
|
||||
// This check prevents the call to apiContactInfo after the app is suspended, and the database is closed.
|
||||
if case .active = scenePhase,
|
||||
case let .direct(contact) = cInfo {
|
||||
Task {
|
||||
do {
|
||||
let (stats, _) = try await apiContactInfo(chat.chatInfo.apiId)
|
||||
@@ -248,7 +255,8 @@ struct ChatView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
if chatModel.draftChatId == cInfo.id, let draft = chatModel.draft {
|
||||
if chatModel.draftChatId == cInfo.id && !composeState.forwarding,
|
||||
let draft = chatModel.draft {
|
||||
composeState = draft
|
||||
}
|
||||
if chat.chatStats.unreadChat {
|
||||
@@ -293,7 +301,7 @@ struct ChatView: View {
|
||||
}
|
||||
|
||||
private func voiceWithoutFrame(_ ci: ChatItem) -> Bool {
|
||||
ci.content.msgContent?.isVoice == true && ci.content.text.count == 0 && ci.quotedItem == nil
|
||||
ci.content.msgContent?.isVoice == true && ci.content.text.count == 0 && ci.quotedItem == nil && ci.meta.itemForwarded == nil
|
||||
}
|
||||
|
||||
private func chatItemsList() -> some View {
|
||||
@@ -339,8 +347,8 @@ struct ChatView: View {
|
||||
.onChange(of: searchText) { _ in
|
||||
loadChat(chat: chat, search: searchText)
|
||||
}
|
||||
.onChange(of: chatModel.chatId) { _ in
|
||||
if let chatId = chatModel.chatId, let c = chatModel.getChat(chatId) {
|
||||
.onChange(of: chatModel.chatId) { chatId in
|
||||
if let chatId, let c = chatModel.getChat(chatId) {
|
||||
chat = c
|
||||
showChatInfoSheet = false
|
||||
loadChat(chat: c)
|
||||
@@ -511,6 +519,7 @@ struct ChatView: View {
|
||||
chat: chat,
|
||||
chatItem: ci,
|
||||
maxWidth: maxWidth,
|
||||
itemWidth: maxWidth,
|
||||
composeState: $composeState,
|
||||
selectedMember: $selectedMember,
|
||||
chatView: self
|
||||
@@ -523,6 +532,7 @@ struct ChatView: View {
|
||||
@ObservedObject var chat: Chat
|
||||
var chatItem: ChatItem
|
||||
var maxWidth: CGFloat
|
||||
@State var itemWidth: CGFloat
|
||||
@Binding var composeState: ComposeState
|
||||
@Binding var selectedMember: GMember?
|
||||
var chatView: ChatView
|
||||
@@ -534,6 +544,7 @@ struct ChatView: View {
|
||||
@State private var revealed = false
|
||||
@State private var showChatItemInfoSheet: Bool = false
|
||||
@State private var chatItemInfo: ChatItemInfo?
|
||||
@State private var showForwardingSheet: Bool = false
|
||||
|
||||
@State private var allowMenu: Bool = true
|
||||
|
||||
@@ -557,7 +568,12 @@ struct ChatView: View {
|
||||
chatItemView(ci, nil, prev)
|
||||
}
|
||||
} else {
|
||||
chatItemView(chatItem, range, prevItem)
|
||||
// Switch branches just to work around context menu problem when 'revealed' changes but size of item isn't
|
||||
if revealed {
|
||||
chatItemView(chatItem, range, prevItem)
|
||||
} else {
|
||||
chatItemView(chatItem, range, prevItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -646,7 +662,7 @@ struct ChatView: View {
|
||||
playbackState: $playbackState,
|
||||
playbackTime: $playbackTime
|
||||
)
|
||||
.uiKitContextMenu(menu: uiMenu, allowMenu: $allowMenu)
|
||||
.uiKitContextMenu(hasImageOrVideo: ci.content.msgContent?.isImageOrVideo == true, maxWidth: maxWidth, itemWidth: $itemWidth, menu: uiMenu, allowMenu: $allowMenu)
|
||||
.accessibilityLabel("")
|
||||
if ci.content.msgContent != nil && (ci.meta.itemDeleted == nil || revealed) && ci.reactions.count > 0 {
|
||||
chatItemReactions(ci)
|
||||
@@ -657,7 +673,7 @@ struct ChatView: View {
|
||||
Button("Delete for me", role: .destructive) {
|
||||
deleteMessage(.cidmInternal)
|
||||
}
|
||||
if let di = deletingItem, di.meta.editable && !di.localNote {
|
||||
if let di = deletingItem, di.meta.deletable && !di.localNote {
|
||||
Button(broadcastDeleteButtonText, role: .destructive) {
|
||||
deleteMessage(.cidmBroadcast)
|
||||
}
|
||||
@@ -683,6 +699,14 @@ struct ChatView: View {
|
||||
}) {
|
||||
ChatItemInfoView(ci: ci, chatItemInfo: $chatItemInfo)
|
||||
}
|
||||
.sheet(isPresented: $showForwardingSheet) {
|
||||
if #available(iOS 16.0, *) {
|
||||
ChatItemForwardingView(ci: ci, fromChatInfo: chat.chatInfo, composeState: $composeState)
|
||||
.presentationDetents([.fraction(0.8)])
|
||||
} else {
|
||||
ChatItemForwardingView(ci: ci, fromChatInfo: chat.chatInfo, composeState: $composeState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func showMemberImage(_ member: GroupMember, _ prevItem: ChatItem?) -> Bool {
|
||||
@@ -761,10 +785,17 @@ struct ChatView: View {
|
||||
} else {
|
||||
menu.append(saveFileAction(fileSource))
|
||||
}
|
||||
} else if let file = ci.file, case .rcvInvitation = file.fileStatus, fileSizeValid(file) {
|
||||
menu.append(downloadFileAction(file))
|
||||
}
|
||||
if ci.meta.editable && !mc.isVoice && !live {
|
||||
menu.append(editAction(ci))
|
||||
}
|
||||
if ci.meta.itemDeleted == nil
|
||||
&& (ci.file == nil || (fileSource != nil && fileExists))
|
||||
&& !ci.isLiveDummy && !live {
|
||||
menu.append(forwardUIAction(ci))
|
||||
}
|
||||
if !ci.isLiveDummy {
|
||||
menu.append(viewInfoUIAction(ci))
|
||||
}
|
||||
@@ -816,6 +847,15 @@ struct ChatView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func forwardUIAction(_ ci: ChatItem) -> UIAction {
|
||||
UIAction(
|
||||
title: NSLocalizedString("Forward", comment: "chat item action"),
|
||||
image: UIImage(systemName: "arrowshape.turn.up.forward")
|
||||
) { _ in
|
||||
showForwardingSheet = true
|
||||
}
|
||||
}
|
||||
|
||||
private func reactionUIMenuPreiOS16(_ rs: [UIAction]) -> UIMenu {
|
||||
UIMenu(
|
||||
title: NSLocalizedString("React…", comment: "chat item menu"),
|
||||
@@ -913,7 +953,21 @@ struct ChatView: View {
|
||||
saveCryptoFile(fileSource)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func downloadFileAction(_ file: CIFile) -> UIAction {
|
||||
UIAction(
|
||||
title: NSLocalizedString("Download", comment: "chat item action"),
|
||||
image: UIImage(systemName: "arrow.down.doc")
|
||||
) { _ in
|
||||
Task {
|
||||
logger.debug("ChatView downloadFileAction, in Task")
|
||||
if let user = m.currentUser {
|
||||
await receiveFile(user: user, fileId: file.fileId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func editAction(_ ci: ChatItem) -> UIAction {
|
||||
UIAction(
|
||||
title: NSLocalizedString("Edit", comment: "chat item action"),
|
||||
@@ -1162,14 +1216,18 @@ struct ChatView: View {
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder func toggleNtfsButton(_ chat: Chat) -> some View {
|
||||
Button {
|
||||
toggleNotifications(chat, enableNtfs: !chat.chatInfo.ntfsEnabled)
|
||||
} label: {
|
||||
if chat.chatInfo.ntfsEnabled {
|
||||
Label("Mute", systemImage: "speaker.slash")
|
||||
} else {
|
||||
Label("Unmute", systemImage: "speaker.wave.2")
|
||||
struct ToggleNtfsButton: View {
|
||||
@ObservedObject var chat: Chat
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
toggleNotifications(chat, enableNtfs: !chat.chatInfo.ntfsEnabled)
|
||||
} label: {
|
||||
if chat.chatInfo.ntfsEnabled {
|
||||
Label("Mute", systemImage: "speaker.slash")
|
||||
} else {
|
||||
Label("Unmute", systemImage: "speaker.wave.2")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ enum ComposeContextItem {
|
||||
case noContextItem
|
||||
case quotedItem(chatItem: ChatItem)
|
||||
case editingItem(chatItem: ChatItem)
|
||||
case forwardingItem(chatItem: ChatItem, fromChatInfo: ChatInfo)
|
||||
}
|
||||
|
||||
enum VoiceMessageRecordingState {
|
||||
@@ -72,6 +73,13 @@ struct ComposeState {
|
||||
}
|
||||
}
|
||||
|
||||
init(forwardingItem: ChatItem, fromChatInfo: ChatInfo) {
|
||||
self.message = ""
|
||||
self.preview = .noPreview
|
||||
self.contextItem = .forwardingItem(chatItem: forwardingItem, fromChatInfo: fromChatInfo)
|
||||
self.voiceMessageRecordingState = .noRecording
|
||||
}
|
||||
|
||||
func copy(
|
||||
message: String? = nil,
|
||||
liveMessage: LiveMessage? = nil,
|
||||
@@ -102,12 +110,19 @@ struct ComposeState {
|
||||
}
|
||||
}
|
||||
|
||||
var forwarding: Bool {
|
||||
switch contextItem {
|
||||
case .forwardingItem: return true
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
var sendEnabled: Bool {
|
||||
switch preview {
|
||||
case let .mediaPreviews(media): return !media.isEmpty
|
||||
case .voicePreview: return voiceMessageRecordingState == .finished
|
||||
case .filePreview: return true
|
||||
default: return !message.isEmpty || liveMessage != nil
|
||||
default: return !message.isEmpty || forwarding || liveMessage != nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +168,7 @@ struct ComposeState {
|
||||
}
|
||||
|
||||
var attachmentDisabled: Bool {
|
||||
if editing || liveMessage != nil || inProgress { return true }
|
||||
if editing || forwarding || liveMessage != nil || inProgress { return true }
|
||||
switch preview {
|
||||
case .noPreview: return false
|
||||
case .linkPreview: return false
|
||||
@@ -161,6 +176,16 @@ struct ComposeState {
|
||||
}
|
||||
}
|
||||
|
||||
var attachmentPreview: Bool {
|
||||
switch preview {
|
||||
case .noPreview: false
|
||||
case .linkPreview: false
|
||||
case let .mediaPreviews(mediaPreviews): !mediaPreviews.isEmpty
|
||||
case .voicePreview: false
|
||||
case .filePreview: true
|
||||
}
|
||||
}
|
||||
|
||||
var empty: Bool {
|
||||
message == "" && noPreview
|
||||
}
|
||||
@@ -234,6 +259,7 @@ struct ComposeView: View {
|
||||
@Binding var keyboardVisible: Bool
|
||||
|
||||
@State var linkUrl: URL? = nil
|
||||
@State var hasSimplexLink: Bool = false
|
||||
@State var prevLinkUrl: URL? = nil
|
||||
@State var pendingLinkUrl: URL? = nil
|
||||
@State var cancelledLinks: Set<String> = []
|
||||
@@ -260,6 +286,16 @@ struct ComposeView: View {
|
||||
if chat.chatInfo.contact?.nextSendGrpInv ?? false {
|
||||
ContextInvitingContactMemberView()
|
||||
}
|
||||
let simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks)
|
||||
let fileProhibited = composeState.attachmentPreview && !chat.groupFeatureEnabled(.files)
|
||||
let voiceProhibited = composeState.voicePreview && !chat.chatInfo.featureEnabled(.voice)
|
||||
if simplexLinkProhibited {
|
||||
msgNotAllowedView("SimpleX links not allowed", icon: "link")
|
||||
} else if fileProhibited {
|
||||
msgNotAllowedView("Files and media not allowed", icon: "doc")
|
||||
} else if voiceProhibited {
|
||||
msgNotAllowedView("Voice messages not allowed", icon: "mic")
|
||||
}
|
||||
contextItemView()
|
||||
switch (composeState.editing, composeState.preview) {
|
||||
case (true, .filePreview): EmptyView()
|
||||
@@ -278,7 +314,7 @@ struct ComposeView: View {
|
||||
.padding(.bottom, 12)
|
||||
.padding(.leading, 12)
|
||||
if case let .group(g) = chat.chatInfo,
|
||||
!g.fullGroupPreferences.files.on {
|
||||
!g.fullGroupPreferences.files.on(for: g.membership) {
|
||||
b.disabled(true).onTapGesture {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title: "Files and media prohibited!",
|
||||
@@ -303,6 +339,7 @@ struct ComposeView: View {
|
||||
},
|
||||
nextSendGrpInv: chat.chatInfo.contact?.nextSendGrpInv ?? false,
|
||||
voiceMessageAllowed: chat.chatInfo.featureEnabled(.voice),
|
||||
disableSendButton: simplexLinkProhibited || fileProhibited || voiceProhibited,
|
||||
showEnableVoiceMessagesAlert: chat.chatInfo.showEnableVoiceMessagesAlert,
|
||||
startVoiceMessageRecording: {
|
||||
Task {
|
||||
@@ -337,13 +374,18 @@ struct ComposeView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: composeState.message) { _ in
|
||||
.onChange(of: composeState.message) { msg in
|
||||
if composeState.linkPreviewAllowed {
|
||||
if composeState.message.count > 0 {
|
||||
showLinkPreview(composeState.message)
|
||||
if msg.count > 0 {
|
||||
showLinkPreview(msg)
|
||||
} else {
|
||||
resetLinkPreview()
|
||||
hasSimplexLink = false
|
||||
}
|
||||
} else if msg.count > 0 && !chat.groupFeatureEnabled(.simplexLinks) {
|
||||
(_, hasSimplexLink) = parseMessage(msg)
|
||||
} else {
|
||||
hasSimplexLink = false
|
||||
}
|
||||
}
|
||||
.onChange(of: chat.userCanSend) { canSend in
|
||||
@@ -610,6 +652,18 @@ struct ComposeView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func msgNotAllowedView(_ reason: LocalizedStringKey, icon: String) -> some View {
|
||||
HStack {
|
||||
Image(systemName: icon).foregroundColor(.secondary)
|
||||
Text(reason).italic()
|
||||
}
|
||||
.padding(12)
|
||||
.frame(minHeight: 50)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(Color(uiColor: .tertiarySystemGroupedBackground))
|
||||
.padding(.top, 8)
|
||||
}
|
||||
|
||||
@ViewBuilder private func contextItemView() -> some View {
|
||||
switch composeState.contextItem {
|
||||
case .noContextItem:
|
||||
@@ -628,6 +682,14 @@ struct ComposeView: View {
|
||||
contextIcon: "pencil",
|
||||
cancelContextItem: { clearState() }
|
||||
)
|
||||
case let .forwardingItem(chatItem: forwardedItem, _):
|
||||
ContextItemView(
|
||||
chat: chat,
|
||||
contextItem: forwardedItem,
|
||||
contextIcon: "arrowshape.turn.up.forward",
|
||||
cancelContextItem: { composeState = composeState.copy(contextItem: .noContextItem) },
|
||||
showSender: false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,6 +711,11 @@ struct ComposeView: View {
|
||||
}
|
||||
if chat.chatInfo.contact?.nextSendGrpInv ?? false {
|
||||
await sendMemberContactInvitation()
|
||||
} else if case let .forwardingItem(ci, fromChatInfo) = composeState.contextItem {
|
||||
sent = await forwardItem(ci, fromChatInfo)
|
||||
if !composeState.message.isEmpty {
|
||||
sent = await send(checkLinkPreview(), quoted: sent?.id, live: false, ttl: nil)
|
||||
}
|
||||
} else if case let .editingItem(ci) = composeState.contextItem {
|
||||
sent = await updateMessage(ci, live: live)
|
||||
} else if let liveMessage = liveMessage, liveMessage.sentMsg != nil {
|
||||
@@ -694,7 +761,15 @@ struct ComposeView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
await MainActor.run { clearState(live: live) }
|
||||
await MainActor.run {
|
||||
let wasForwarding = composeState.forwarding
|
||||
clearState(live: live)
|
||||
if wasForwarding,
|
||||
chatModel.draftChatId == chat.chatInfo.id,
|
||||
let draft = chatModel.draft {
|
||||
composeState = draft
|
||||
}
|
||||
}
|
||||
return sent
|
||||
|
||||
func sending() async {
|
||||
@@ -815,10 +890,26 @@ struct ComposeView: View {
|
||||
return nil
|
||||
}
|
||||
|
||||
func forwardItem(_ forwardedItem: ChatItem, _ fromChatInfo: ChatInfo) async -> ChatItem? {
|
||||
if let chatItem = await apiForwardChatItem(
|
||||
toChatType: chat.chatInfo.chatType,
|
||||
toChatId: chat.chatInfo.apiId,
|
||||
fromChatType: fromChatInfo.chatType,
|
||||
fromChatId: fromChatInfo.apiId,
|
||||
itemId: forwardedItem.id
|
||||
) {
|
||||
await MainActor.run {
|
||||
chatModel.addChatItem(chat.chatInfo, chatItem)
|
||||
}
|
||||
return chatItem
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkLinkPreview() -> MsgContent {
|
||||
switch (composeState.preview) {
|
||||
case let .linkPreview(linkPreview: linkPreview):
|
||||
if let url = parseMessage(msgText),
|
||||
if let url = parseMessage(msgText).url,
|
||||
let linkPreview = linkPreview,
|
||||
url == linkPreview.uri {
|
||||
return .link(text: msgText, preview: linkPreview)
|
||||
@@ -947,7 +1038,7 @@ struct ComposeView: View {
|
||||
|
||||
private func showLinkPreview(_ s: String) {
|
||||
prevLinkUrl = linkUrl
|
||||
linkUrl = parseMessage(s)
|
||||
(linkUrl, hasSimplexLink) = parseMessage(s)
|
||||
if let url = linkUrl {
|
||||
if url != composeState.linkPreview?.uri && url != pendingLinkUrl {
|
||||
pendingLinkUrl = url
|
||||
@@ -964,13 +1055,17 @@ struct ComposeView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func parseMessage(_ msg: String) -> URL? {
|
||||
let parsedMsg = parseSimpleXMarkdown(msg)
|
||||
let uri = parsedMsg?.first(where: { ft in
|
||||
private func parseMessage(_ msg: String) -> (url: URL?, hasSimplexLink: Bool) {
|
||||
guard let parsedMsg = parseSimpleXMarkdown(msg) else { return (nil, false) }
|
||||
let url: URL? = if let uri = parsedMsg.first(where: { ft in
|
||||
ft.format == .uri && !cancelledLinks.contains(ft.text) && !isSimplexLink(ft.text)
|
||||
})
|
||||
if let uri = uri { return URL(string: uri.text) }
|
||||
else { return nil }
|
||||
}) {
|
||||
URL(string: uri.text)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
let simplexLink = parsedMsg.contains(where: { ft in ft.format?.isSimplexLink ?? false })
|
||||
return (url, simplexLink)
|
||||
}
|
||||
|
||||
private func isSimplexLink(_ link: String) -> Bool {
|
||||
|
||||
@@ -15,6 +15,7 @@ struct ContextItemView: View {
|
||||
let contextItem: ChatItem
|
||||
let contextIcon: String
|
||||
let cancelContextItem: () -> Void
|
||||
var showSender: Bool = true
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
@@ -23,7 +24,7 @@ struct ContextItemView: View {
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 16, height: 16)
|
||||
.foregroundColor(.secondary)
|
||||
if let sender = contextItem.memberDisplayName {
|
||||
if showSender, let sender = contextItem.memberDisplayName {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(sender).font(.caption).foregroundColor(.secondary)
|
||||
msgContentView(lines: 2)
|
||||
@@ -48,14 +49,26 @@ struct ContextItemView: View {
|
||||
}
|
||||
|
||||
private func msgContentView(lines: Int) -> some View {
|
||||
MsgContentView(
|
||||
chat: chat,
|
||||
text: contextItem.text,
|
||||
formattedText: contextItem.formattedText,
|
||||
showSecrets: false
|
||||
)
|
||||
.multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading)
|
||||
.lineLimit(lines)
|
||||
contextMsgPreview()
|
||||
.multilineTextAlignment(isRightToLeft(contextItem.text) ? .trailing : .leading)
|
||||
.lineLimit(lines)
|
||||
}
|
||||
|
||||
private func contextMsgPreview() -> Text {
|
||||
return attachment() + messageText(contextItem.text, contextItem.formattedText, nil, preview: true, showSecrets: false)
|
||||
|
||||
func attachment() -> Text {
|
||||
switch contextItem.content.msgContent {
|
||||
case .file: return image("doc.fill")
|
||||
case .image: return image("photo")
|
||||
case .voice: return image("play.fill")
|
||||
default: return Text("")
|
||||
}
|
||||
}
|
||||
|
||||
func image(_ s: String) -> Text {
|
||||
Text(Image(systemName: s)).foregroundColor(Color(uiColor: .tertiaryLabel)) + Text(" ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ struct NativeTextEditor: UIViewRepresentable {
|
||||
@Binding var disableEditing: Bool
|
||||
@Binding var height: CGFloat
|
||||
@Binding var focused: Bool
|
||||
let alignment: TextAlignment
|
||||
let onImagesAdded: ([UploadContent]) -> Void
|
||||
|
||||
private let minHeight: CGFloat = 37
|
||||
@@ -30,13 +29,16 @@ struct NativeTextEditor: UIViewRepresentable {
|
||||
func makeUIView(context: Context) -> UITextView {
|
||||
let field = CustomUITextField(height: _height)
|
||||
field.text = text
|
||||
field.textAlignment = alignment == .leading ? .left : .right
|
||||
field.textAlignment = alignment(text)
|
||||
field.autocapitalizationType = .sentences
|
||||
field.setOnTextChangedListener { newText, images in
|
||||
if !disableEditing {
|
||||
// Speed up the process of updating layout, reduce jumping content on screen
|
||||
if !isShortEmoji(newText) { updateHeight(field) }
|
||||
text = newText
|
||||
field.textAlignment = alignment(text)
|
||||
updateFont(field)
|
||||
// Speed up the process of updating layout, reduce jumping content on screen
|
||||
updateHeight(field)
|
||||
self.height = field.frame.size.height
|
||||
} else {
|
||||
field.text = text
|
||||
}
|
||||
@@ -53,10 +55,12 @@ struct NativeTextEditor: UIViewRepresentable {
|
||||
}
|
||||
|
||||
func updateUIView(_ field: UITextView, context: Context) {
|
||||
field.text = text
|
||||
field.textAlignment = alignment == .leading ? .left : .right
|
||||
updateFont(field)
|
||||
updateHeight(field)
|
||||
if field.markedTextRange == nil && field.text != text {
|
||||
field.text = text
|
||||
field.textAlignment = alignment(text)
|
||||
updateFont(field)
|
||||
updateHeight(field)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateHeight(_ field: UITextView) {
|
||||
@@ -73,12 +77,19 @@ struct NativeTextEditor: UIViewRepresentable {
|
||||
}
|
||||
|
||||
private func updateFont(_ field: UITextView) {
|
||||
field.font = isShortEmoji(field.text)
|
||||
let newFont = isShortEmoji(field.text)
|
||||
? (field.text.count < 4 ? largeEmojiUIFont : mediumEmojiUIFont)
|
||||
: UIFont.preferredFont(forTextStyle: .body)
|
||||
if field.font != newFont {
|
||||
field.font = newFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func alignment(_ text: String) -> NSTextAlignment {
|
||||
isRightToLeft(text) ? .right : .left
|
||||
}
|
||||
|
||||
private class CustomUITextField: UITextView, UITextViewDelegate {
|
||||
var height: Binding<CGFloat>
|
||||
var newHeight: CGFloat = 0
|
||||
@@ -205,7 +216,6 @@ struct NativeTextEditor_Previews: PreviewProvider{
|
||||
disableEditing: Binding.constant(false),
|
||||
height: Binding.constant(100),
|
||||
focused: Binding.constant(false),
|
||||
alignment: TextAlignment.leading,
|
||||
onImagesAdded: { _ in }
|
||||
)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
@@ -20,6 +20,7 @@ struct SendMessageView: View {
|
||||
var nextSendGrpInv: Bool = false
|
||||
var showVoiceMessageButton: Bool = true
|
||||
var voiceMessageAllowed: Bool = true
|
||||
var disableSendButton = false
|
||||
var showEnableVoiceMessagesAlert: ChatInfo.ShowEnableVoiceMessagesAlert = .other
|
||||
var startVoiceMessageRecording: (() -> Void)? = nil
|
||||
var finishVoiceMessageRecording: (() -> Void)? = nil
|
||||
@@ -53,13 +54,11 @@ struct SendMessageView: View {
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity)
|
||||
} else {
|
||||
let alignment: TextAlignment = isRightToLeft(composeState.message) ? .trailing : .leading
|
||||
NativeTextEditor(
|
||||
text: $composeState.message,
|
||||
disableEditing: $composeState.inProgress,
|
||||
height: $teHeight,
|
||||
focused: $keyboardVisible,
|
||||
alignment: alignment,
|
||||
onImagesAdded: onMediaAdded
|
||||
)
|
||||
.allowsTightening(false)
|
||||
@@ -109,6 +108,7 @@ struct SendMessageView: View {
|
||||
} else if showVoiceMessageButton
|
||||
&& composeState.message.isEmpty
|
||||
&& !composeState.editing
|
||||
&& !composeState.forwarding
|
||||
&& composeState.liveMessage == nil
|
||||
&& ((composeState.noPreview && vmrs == .noRecording)
|
||||
|| (vmrs == .recording && holdingVMR)) {
|
||||
@@ -184,7 +184,8 @@ struct SendMessageView: View {
|
||||
!composeState.sendEnabled ||
|
||||
composeState.inProgress ||
|
||||
(!voiceMessageAllowed && composeState.voicePreview) ||
|
||||
composeState.endLiveDisabled
|
||||
composeState.endLiveDisabled ||
|
||||
disableSendButton
|
||||
)
|
||||
.frame(width: 29, height: 29)
|
||||
.contextMenu{
|
||||
@@ -223,7 +224,8 @@ struct SendMessageView: View {
|
||||
|
||||
@ViewBuilder private func sendButtonContextMenuItems() -> some View {
|
||||
if composeState.liveMessage == nil,
|
||||
!composeState.editing {
|
||||
!composeState.editing,
|
||||
!composeState.forwarding {
|
||||
if case .noContextItem = composeState.contextItem,
|
||||
!composeState.voicePreview,
|
||||
let send = sendLiveMessage,
|
||||
|
||||
@@ -35,7 +35,7 @@ struct ContactPreferencesView: View {
|
||||
.disabled(currentFeaturesAllowed == featuresAllowed)
|
||||
}
|
||||
}
|
||||
.modifier(BackButton {
|
||||
.modifier(BackButton(disabled: Binding.constant(false)) {
|
||||
if currentFeaturesAllowed == featuresAllowed {
|
||||
dismiss()
|
||||
} else {
|
||||
|
||||
@@ -62,7 +62,7 @@ struct GroupChatInfoView: View {
|
||||
NavigationView {
|
||||
let members = chatModel.groupMembers
|
||||
.filter { m in let status = m.wrapped.memberStatus; return status != .memLeft && status != .memRemoved }
|
||||
.sorted { $0.displayName.lowercased() < $1.displayName.lowercased() }
|
||||
.sorted { $0.wrapped.memberRole > $1.wrapped.memberRole }
|
||||
|
||||
List {
|
||||
groupInfoHeader()
|
||||
|
||||
@@ -83,7 +83,7 @@ struct GroupMemberInfoView: View {
|
||||
Section {
|
||||
if let contactId = member.memberContactId, let chat = knownDirectChat(contactId) {
|
||||
knownDirectChatButton(chat)
|
||||
} else if groupInfo.fullGroupPreferences.directMessages.on {
|
||||
} else if groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
|
||||
if let contactId = member.memberContactId {
|
||||
newDirectChatButton(contactId)
|
||||
} else if member.activeConn?.peerChatVRange.isCompatibleRange(CREATE_MEMBER_CONTACT_VRANGE) ?? false {
|
||||
@@ -110,7 +110,7 @@ struct GroupMemberInfoView: View {
|
||||
Label("Share address", systemImage: "square.and.arrow.up")
|
||||
}
|
||||
if let contactId = member.memberContactId {
|
||||
if knownDirectChat(contactId) == nil && !groupInfo.fullGroupPreferences.directMessages.on {
|
||||
if knownDirectChat(contactId) == nil && !groupInfo.fullGroupPreferences.directMessages.on(for: groupInfo.membership) {
|
||||
connectViaAddressButton(contactLink)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
private let featureRoles: [(role: GroupMemberRole?, text: LocalizedStringKey)] = [
|
||||
(nil, "all members"),
|
||||
(.admin, "admins"),
|
||||
(.owner, "owners")
|
||||
]
|
||||
|
||||
struct GroupPreferencesView: View {
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
@@ -24,10 +30,12 @@ struct GroupPreferencesView: View {
|
||||
List {
|
||||
featureSection(.timedMessages, $preferences.timedMessages.enable)
|
||||
featureSection(.fullDelete, $preferences.fullDelete.enable)
|
||||
featureSection(.directMessages, $preferences.directMessages.enable)
|
||||
featureSection(.directMessages, $preferences.directMessages.enable, $preferences.directMessages.role)
|
||||
featureSection(.reactions, $preferences.reactions.enable)
|
||||
featureSection(.voice, $preferences.voice.enable)
|
||||
featureSection(.files, $preferences.files.enable)
|
||||
featureSection(.voice, $preferences.voice.enable, $preferences.voice.role)
|
||||
featureSection(.files, $preferences.files.enable, $preferences.files.role)
|
||||
// TODO enable simplexLinks preference in 5.8
|
||||
// featureSection(.simplexLinks, $preferences.simplexLinks.enable, $preferences.simplexLinks.role)
|
||||
featureSection(.history, $preferences.history.enable)
|
||||
|
||||
if groupInfo.canEdit {
|
||||
@@ -48,7 +56,7 @@ struct GroupPreferencesView: View {
|
||||
preferences.timedMessages.ttl = currentPreferences.timedMessages.ttl
|
||||
}
|
||||
}
|
||||
.modifier(BackButton {
|
||||
.modifier(BackButton(disabled: Binding.constant(false)) {
|
||||
if currentPreferences == preferences {
|
||||
dismiss()
|
||||
} else {
|
||||
@@ -64,7 +72,7 @@ struct GroupPreferencesView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func featureSection(_ feature: GroupFeature, _ enableFeature: Binding<GroupFeatureEnabled>) -> some View {
|
||||
private func featureSection(_ feature: GroupFeature, _ enableFeature: Binding<GroupFeatureEnabled>, _ enableForRole: Binding<GroupMemberRole?>? = nil) -> some View {
|
||||
Section {
|
||||
let color: Color = enableFeature.wrappedValue == .on ? .green : .secondary
|
||||
let icon = enableFeature.wrappedValue == .on ? feature.iconFilled : feature.icon
|
||||
@@ -87,6 +95,16 @@ struct GroupPreferencesView: View {
|
||||
)
|
||||
.frame(height: 36)
|
||||
}
|
||||
if enableFeature.wrappedValue == .on, let enableForRole {
|
||||
Picker("Enabled for", selection: enableForRole) {
|
||||
ForEach(featureRoles, id: \.role) { fr in
|
||||
Text(fr.text)
|
||||
}
|
||||
}
|
||||
.frame(height: 36)
|
||||
// remove in v5.8
|
||||
.disabled(true)
|
||||
}
|
||||
} else {
|
||||
settingsRow(icon, color: color) {
|
||||
infoRow(Text(feature.text), enableFeature.wrappedValue.text)
|
||||
@@ -94,10 +112,26 @@ struct GroupPreferencesView: View {
|
||||
if timedOn {
|
||||
infoRow("Delete after", timeText(preferences.timedMessages.ttl))
|
||||
}
|
||||
if enableFeature.wrappedValue == .on, let enableForRole {
|
||||
HStack {
|
||||
Text("Enabled for").foregroundColor(.secondary)
|
||||
Spacer()
|
||||
Text(
|
||||
featureRoles.first(where: { fr in fr.role == enableForRole.wrappedValue })?.text
|
||||
?? "all members"
|
||||
)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
} footer: {
|
||||
Text(feature.enableDescription(enableFeature.wrappedValue, groupInfo.canEdit))
|
||||
}
|
||||
.onChange(of: enableFeature.wrappedValue) { enabled in
|
||||
if case .off = enabled {
|
||||
enableForRole?.wrappedValue = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func savePreferences() {
|
||||
|
||||
@@ -24,7 +24,7 @@ struct GroupWelcomeView: View {
|
||||
VStack {
|
||||
if groupInfo.canEdit {
|
||||
editorView()
|
||||
.modifier(BackButton {
|
||||
.modifier(BackButton(disabled: Binding.constant(false)) {
|
||||
if welcomeTextUnchanged() {
|
||||
dismiss()
|
||||
} else {
|
||||
|
||||
@@ -92,7 +92,7 @@ struct ChatListNavLink: View {
|
||||
.swipeActions(edge: .leading, allowsFullSwipe: true) {
|
||||
markReadButton()
|
||||
toggleFavoriteButton()
|
||||
toggleNtfsButton(chat)
|
||||
ToggleNtfsButton(chat: chat)
|
||||
}
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||
if !chat.chatItems.isEmpty {
|
||||
@@ -181,7 +181,7 @@ struct ChatListNavLink: View {
|
||||
.swipeActions(edge: .leading, allowsFullSwipe: true) {
|
||||
markReadButton()
|
||||
toggleFavoriteButton()
|
||||
toggleNtfsButton(chat)
|
||||
ToggleNtfsButton(chat: chat)
|
||||
}
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||
if !chat.chatItems.isEmpty {
|
||||
|
||||
@@ -264,7 +264,9 @@ struct ChatListView: View {
|
||||
}
|
||||
|
||||
func filtered(_ chat: Chat) -> Bool {
|
||||
(chat.chatInfo.chatSettings?.favorite ?? false) || chat.chatStats.unreadCount > 0 || chat.chatStats.unreadChat
|
||||
(chat.chatInfo.chatSettings?.favorite ?? false) ||
|
||||
chat.chatStats.unreadChat ||
|
||||
(chat.chatInfo.ntfsEnabled && chat.chatStats.unreadCount > 0)
|
||||
}
|
||||
|
||||
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
|
||||
|
||||
@@ -12,6 +12,7 @@ private let fillColorLight = Color(uiColor: UIColor(red: 0.99, green: 0.99, blue
|
||||
struct UserPicker: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
@Environment(\.scenePhase) var scenePhase
|
||||
@Binding var showSettings: Bool
|
||||
@Binding var showConnectDesktop: Bool
|
||||
@Binding var userPickerVisible: Bool
|
||||
@@ -91,7 +92,10 @@ struct UserPicker: View {
|
||||
.opacity(userPickerVisible ? 1.0 : 0.0)
|
||||
.onAppear {
|
||||
do {
|
||||
m.users = try listUsers()
|
||||
// This check prevents the call of listUsers after the app is suspended, and the database is closed.
|
||||
if case .active = scenePhase {
|
||||
m.users = try listUsers()
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("Error loading users \(responseError(error))")
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ enum DatabaseEncryptionAlert: Identifiable {
|
||||
struct DatabaseEncryptionView: View {
|
||||
@EnvironmentObject private var m: ChatModel
|
||||
@Binding var useKeychain: Bool
|
||||
var migration: Bool
|
||||
@State private var alert: DatabaseEncryptionAlert? = nil
|
||||
@State private var progressIndicator = false
|
||||
@State private var useKeychainToggle = storeDBPassphraseGroupDefault.get()
|
||||
@@ -48,7 +49,12 @@ struct DatabaseEncryptionView: View {
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
databaseEncryptionView()
|
||||
List {
|
||||
if migration {
|
||||
chatStoppedView()
|
||||
}
|
||||
databaseEncryptionView()
|
||||
}
|
||||
if progressIndicator {
|
||||
ProgressView().scaleEffect(2)
|
||||
}
|
||||
@@ -56,72 +62,71 @@ struct DatabaseEncryptionView: View {
|
||||
}
|
||||
|
||||
private func databaseEncryptionView() -> some View {
|
||||
List {
|
||||
Section {
|
||||
settingsRow(storedKey ? "key.fill" : "key", color: storedKey ? .green : .secondary) {
|
||||
Toggle("Save passphrase in Keychain", isOn: $useKeychainToggle)
|
||||
Section {
|
||||
settingsRow(storedKey ? "key.fill" : "key", color: storedKey ? .green : .secondary) {
|
||||
Toggle("Save passphrase in Keychain", isOn: $useKeychainToggle)
|
||||
.onChange(of: useKeychainToggle) { _ in
|
||||
if useKeychainToggle {
|
||||
setUseKeychain(true)
|
||||
} else if storedKey {
|
||||
} else if storedKey && !migration {
|
||||
// Don't show in migration process since it will remove the key after successfull encryption
|
||||
alert = .keychainRemoveKey
|
||||
} else {
|
||||
setUseKeychain(false)
|
||||
}
|
||||
}
|
||||
.disabled(initialRandomDBPassphrase)
|
||||
}
|
||||
.disabled(initialRandomDBPassphrase && !migration)
|
||||
}
|
||||
|
||||
if !initialRandomDBPassphrase && m.chatDbEncrypted == true {
|
||||
PassphraseField(key: $currentKey, placeholder: "Current passphrase…", valid: validKey(currentKey))
|
||||
}
|
||||
if !initialRandomDBPassphrase && m.chatDbEncrypted == true {
|
||||
PassphraseField(key: $currentKey, placeholder: "Current passphrase…", valid: validKey(currentKey))
|
||||
}
|
||||
|
||||
PassphraseField(key: $newKey, placeholder: "New passphrase…", valid: validKey(newKey), showStrength: true)
|
||||
PassphraseField(key: $confirmNewKey, placeholder: "Confirm new passphrase…", valid: confirmNewKey == "" || newKey == confirmNewKey)
|
||||
PassphraseField(key: $newKey, placeholder: "New passphrase…", valid: validKey(newKey), showStrength: true)
|
||||
PassphraseField(key: $confirmNewKey, placeholder: "Confirm new passphrase…", valid: confirmNewKey == "" || newKey == confirmNewKey)
|
||||
|
||||
settingsRow("lock.rotation") {
|
||||
Button("Update database passphrase") {
|
||||
alert = currentKey == ""
|
||||
? (useKeychain ? .encryptDatabaseSaved : .encryptDatabase)
|
||||
: (useKeychain ? .changeDatabaseKeySaved : .changeDatabaseKey)
|
||||
}
|
||||
settingsRow("lock.rotation") {
|
||||
Button(migration ? "Set passphrase" : "Update database passphrase") {
|
||||
alert = currentKey == ""
|
||||
? (useKeychain ? .encryptDatabaseSaved : .encryptDatabase)
|
||||
: (useKeychain ? .changeDatabaseKeySaved : .changeDatabaseKey)
|
||||
}
|
||||
.disabled(
|
||||
(m.chatDbEncrypted == true && currentKey == "") ||
|
||||
currentKey == newKey ||
|
||||
newKey != confirmNewKey ||
|
||||
newKey == "" ||
|
||||
!validKey(currentKey) ||
|
||||
!validKey(newKey)
|
||||
)
|
||||
} header: {
|
||||
Text("")
|
||||
} footer: {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
if m.chatDbEncrypted == false {
|
||||
Text("Your chat database is not encrypted - set passphrase to encrypt it.")
|
||||
} else if useKeychain {
|
||||
if storedKey {
|
||||
Text("iOS Keychain is used to securely store passphrase - it allows receiving push notifications.")
|
||||
if initialRandomDBPassphrase {
|
||||
Text("Database is encrypted using a random passphrase, you can change it.")
|
||||
} else {
|
||||
Text("**Please note**: you will NOT be able to recover or change passphrase if you lose it.")
|
||||
}
|
||||
}
|
||||
.disabled(
|
||||
(m.chatDbEncrypted == true && currentKey == "") ||
|
||||
currentKey == newKey ||
|
||||
newKey != confirmNewKey ||
|
||||
newKey == "" ||
|
||||
!validKey(currentKey) ||
|
||||
!validKey(newKey)
|
||||
)
|
||||
} header: {
|
||||
Text(migration ? "Database passphrase" : "")
|
||||
} footer: {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
if m.chatDbEncrypted == false {
|
||||
Text("Your chat database is not encrypted - set passphrase to encrypt it.")
|
||||
} else if useKeychain {
|
||||
if storedKey {
|
||||
Text("iOS Keychain is used to securely store passphrase - it allows receiving push notifications.")
|
||||
if initialRandomDBPassphrase && !migration {
|
||||
Text("Database is encrypted using a random passphrase, you can change it.")
|
||||
} else {
|
||||
Text("iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications.")
|
||||
Text("**Please note**: you will NOT be able to recover or change passphrase if you lose it.")
|
||||
}
|
||||
} else {
|
||||
Text("You have to enter passphrase every time the app starts - it is not stored on the device.")
|
||||
Text("**Please note**: you will NOT be able to recover or change passphrase if you lose it.")
|
||||
if m.notificationMode == .instant && m.notificationPreview != .hidden {
|
||||
Text("**Warning**: Instant push notifications require passphrase saved in Keychain.")
|
||||
}
|
||||
Text("iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications.")
|
||||
}
|
||||
} else {
|
||||
Text("You have to enter passphrase every time the app starts - it is not stored on the device.")
|
||||
Text("**Please note**: you will NOT be able to recover or change passphrase if you lose it.")
|
||||
if m.notificationMode == .instant && m.notificationPreview != .hidden && !migration {
|
||||
Text("**Warning**: Instant push notifications require passphrase saved in Keychain.")
|
||||
}
|
||||
}
|
||||
.padding(.top, 1)
|
||||
.font(.callout)
|
||||
}
|
||||
.padding(.top, 1)
|
||||
.font(.callout)
|
||||
}
|
||||
.onAppear {
|
||||
if initialRandomDBPassphrase { currentKey = kcDatabasePassword.get() ?? "" }
|
||||
@@ -136,9 +141,15 @@ struct DatabaseEncryptionView: View {
|
||||
do {
|
||||
encryptionStartedDefault.set(true)
|
||||
encryptionStartedAtDefault.set(Date.now)
|
||||
if !m.chatDbChanged {
|
||||
try apiSaveAppSettings(settings: AppSettings.current.prepareForExport())
|
||||
}
|
||||
try await apiStorageEncryption(currentKey: currentKey, newKey: newKey)
|
||||
encryptionStartedDefault.set(false)
|
||||
initialRandomDBPassphraseGroupDefault.set(false)
|
||||
if migration {
|
||||
storeDBPassphraseGroupDefault.set(useKeychain)
|
||||
}
|
||||
if useKeychain {
|
||||
if kcDatabasePassword.set(newKey) {
|
||||
await resetFormAfterEncryption(true)
|
||||
@@ -148,6 +159,9 @@ struct DatabaseEncryptionView: View {
|
||||
await operationEnded(.error(title: "Keychain error", error: "Error saving passphrase to keychain"))
|
||||
}
|
||||
} else {
|
||||
if migration {
|
||||
removePassphraseFromKeyChain()
|
||||
}
|
||||
await resetFormAfterEncryption()
|
||||
await operationEnded(.databaseEncrypted)
|
||||
}
|
||||
@@ -174,7 +188,10 @@ struct DatabaseEncryptionView: View {
|
||||
|
||||
private func setUseKeychain(_ value: Bool) {
|
||||
useKeychain = value
|
||||
storeDBPassphraseGroupDefault.set(value)
|
||||
// Postpone it when migrating to the end of encryption process
|
||||
if !migration {
|
||||
storeDBPassphraseGroupDefault.set(value)
|
||||
}
|
||||
}
|
||||
|
||||
private func databaseEncryptionAlert(_ alertItem: DatabaseEncryptionAlert) -> Alert {
|
||||
@@ -184,13 +201,7 @@ struct DatabaseEncryptionView: View {
|
||||
title: Text("Remove passphrase from keychain?"),
|
||||
message: Text("Instant push notifications will be hidden!\n") + storeSecurelyDanger(),
|
||||
primaryButton: .destructive(Text("Remove")) {
|
||||
if kcDatabasePassword.remove() {
|
||||
logger.debug("passphrase removed from keychain")
|
||||
setUseKeychain(false)
|
||||
storedKey = false
|
||||
} else {
|
||||
alert = .error(title: "Keychain error", error: "Failed to remove passphrase")
|
||||
}
|
||||
removePassphraseFromKeyChain()
|
||||
},
|
||||
secondaryButton: .cancel() {
|
||||
withAnimation { useKeychainToggle = true }
|
||||
@@ -236,6 +247,16 @@ struct DatabaseEncryptionView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func removePassphraseFromKeyChain() {
|
||||
if kcDatabasePassword.remove() {
|
||||
logger.debug("passphrase removed from keychain")
|
||||
setUseKeychain(false)
|
||||
storedKey = false
|
||||
} else {
|
||||
alert = .error(title: "Keychain error", error: "Failed to remove passphrase")
|
||||
}
|
||||
}
|
||||
|
||||
private func storeSecurelySaved() -> Text {
|
||||
Text("Please store passphrase securely, you will NOT be able to change it if you lose it.")
|
||||
}
|
||||
@@ -346,6 +367,6 @@ func validKey(_ s: String) -> Bool {
|
||||
|
||||
struct DatabaseEncryptionView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
DatabaseEncryptionView(useKeychain: Binding.constant(true))
|
||||
DatabaseEncryptionView(useKeychain: Binding.constant(true), migration: false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ struct DatabaseErrorView: View {
|
||||
case let .migrationError(mtrError):
|
||||
titleText("Incompatible database version")
|
||||
fileNameText(dbFile)
|
||||
Text("Error: ") + Text(mtrErrorDescription(mtrError))
|
||||
Text("Error: ") + Text(DatabaseErrorView.mtrErrorDescription(mtrError))
|
||||
}
|
||||
case let .errorSQL(dbFile, migrationSQLError):
|
||||
titleText("Database error")
|
||||
@@ -105,7 +105,7 @@ struct DatabaseErrorView: View {
|
||||
Text("Migrations: \(ms.joined(separator: ", "))")
|
||||
}
|
||||
|
||||
private func mtrErrorDescription(_ err: MTRError) -> LocalizedStringKey {
|
||||
static func mtrErrorDescription(_ err: MTRError) -> LocalizedStringKey {
|
||||
switch err {
|
||||
case let .noDown(dbMigrations):
|
||||
return "database version is newer than the app, but no down migration for: \(dbMigrations.joined(separator: ", "))"
|
||||
|
||||
@@ -116,7 +116,7 @@ struct DatabaseView: View {
|
||||
let color: Color = unencrypted ? .orange : .secondary
|
||||
settingsRow(unencrypted ? "lock.open" : useKeychain ? "key" : "lock", color: color) {
|
||||
NavigationLink {
|
||||
DatabaseEncryptionView(useKeychain: $useKeychain)
|
||||
DatabaseEncryptionView(useKeychain: $useKeychain, migration: false)
|
||||
.navigationTitle("Database passphrase")
|
||||
} label: {
|
||||
Text("Database passphrase")
|
||||
@@ -485,6 +485,10 @@ func deleteChatAsync() async throws {
|
||||
_ = kcDatabasePassword.remove()
|
||||
storeDBPassphraseGroupDefault.set(true)
|
||||
deleteAppDatabaseAndFiles()
|
||||
// Clean state so when creating new user the app will start chat automatically (see CreateProfile:createProfile())
|
||||
DispatchQueue.main.async {
|
||||
ChatModel.shared.users = []
|
||||
}
|
||||
}
|
||||
|
||||
struct DatabaseView_Previews: PreviewProvider {
|
||||
|
||||
@@ -188,6 +188,7 @@ struct MigrateToAppGroupView: View {
|
||||
let config = ArchiveConfig(archivePath: getDocumentsDirectory().appendingPathComponent(archiveName).path)
|
||||
Task {
|
||||
do {
|
||||
try apiSaveAppSettings(settings: AppSettings.current.prepareForExport())
|
||||
try await apiExportArchive(config: config)
|
||||
await MainActor.run { setV3DBMigration(.exported) }
|
||||
} catch let error {
|
||||
@@ -204,7 +205,11 @@ struct MigrateToAppGroupView: View {
|
||||
resetChatCtrl()
|
||||
try await MainActor.run { try initializeChat(start: false) }
|
||||
let _ = try await apiImportArchive(config: config)
|
||||
await MainActor.run { setV3DBMigration(.migrated) }
|
||||
let appSettings = try apiGetAppSettings(settings: AppSettings.current.prepareForExport())
|
||||
await MainActor.run {
|
||||
appSettings.importIntoApp()
|
||||
setV3DBMigration(.migrated)
|
||||
}
|
||||
} catch let error {
|
||||
dbContainerGroupDefault.set(.documents)
|
||||
await MainActor.run {
|
||||
@@ -216,16 +221,22 @@ struct MigrateToAppGroupView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func exportChatArchive() async throws -> URL {
|
||||
func exportChatArchive(_ storagePath: URL? = nil) async throws -> URL {
|
||||
let archiveTime = Date.now
|
||||
let ts = archiveTime.ISO8601Format(Date.ISO8601FormatStyle(timeSeparator: .omitted))
|
||||
let archiveName = "simplex-chat.\(ts).zip"
|
||||
let archivePath = getDocumentsDirectory().appendingPathComponent(archiveName)
|
||||
let archivePath = (storagePath ?? getDocumentsDirectory()).appendingPathComponent(archiveName)
|
||||
let config = ArchiveConfig(archivePath: archivePath.path)
|
||||
// Settings should be saved before changing a passphrase, otherwise the database needs to be migrated first
|
||||
if !ChatModel.shared.chatDbChanged {
|
||||
try apiSaveAppSettings(settings: AppSettings.current.prepareForExport())
|
||||
}
|
||||
try await apiExportArchive(config: config)
|
||||
deleteOldArchive()
|
||||
UserDefaults.standard.set(archiveName, forKey: DEFAULT_CHAT_ARCHIVE_NAME)
|
||||
chatArchiveTimeDefault.set(archiveTime)
|
||||
if storagePath == nil {
|
||||
deleteOldArchive()
|
||||
UserDefaults.standard.set(archiveName, forKey: DEFAULT_CHAT_ARCHIVE_NAME)
|
||||
chatArchiveTimeDefault.set(archiveTime)
|
||||
}
|
||||
return archivePath
|
||||
}
|
||||
|
||||
|
||||
@@ -11,28 +11,43 @@ import UIKit
|
||||
import SwiftUI
|
||||
|
||||
extension View {
|
||||
func uiKitContextMenu(menu: Binding<UIMenu>, allowMenu: Binding<Bool>) -> some View {
|
||||
self.overlay {
|
||||
if allowMenu.wrappedValue {
|
||||
self.overlay(Color(uiColor: .systemBackground)).overlay(InteractionView(content: self, menu: menu))
|
||||
func uiKitContextMenu(hasImageOrVideo: Bool, maxWidth: CGFloat, itemWidth: Binding<CGFloat>, menu: Binding<UIMenu>, allowMenu: Binding<Bool>) -> some View {
|
||||
Group {
|
||||
if allowMenu.wrappedValue {
|
||||
if hasImageOrVideo {
|
||||
InteractionView(content:
|
||||
self.environmentObject(ChatModel.shared)
|
||||
.overlay(DetermineWidthImageVideoItem())
|
||||
.onPreferenceChange(DetermineWidthImageVideoItem.Key.self) { itemWidth.wrappedValue = $0 == 0 ? maxWidth : $0 }
|
||||
, maxWidth: maxWidth, itemWidth: itemWidth, menu: menu)
|
||||
.frame(maxWidth: itemWidth.wrappedValue)
|
||||
} else {
|
||||
InteractionView(content: self.environmentObject(ChatModel.shared), maxWidth: maxWidth, itemWidth: itemWidth, menu: menu)
|
||||
.fixedSize(horizontal: true, vertical: false)
|
||||
}
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct InteractionConfig<Content: View> {
|
||||
let content: Content
|
||||
let menu: UIMenu
|
||||
private class HostingViewHolder: UIView {
|
||||
var contentSize: CGSize = CGSizeMake(0, 0)
|
||||
override var intrinsicContentSize: CGSize { get { contentSize } }
|
||||
}
|
||||
|
||||
private struct InteractionView<Content: View>: UIViewRepresentable {
|
||||
struct InteractionView<Content: View>: UIViewRepresentable {
|
||||
let content: Content
|
||||
var maxWidth: CGFloat
|
||||
var itemWidth: Binding<CGFloat>
|
||||
@Binding var menu: UIMenu
|
||||
|
||||
func makeUIView(context: Context) -> UIView {
|
||||
let view = UIView()
|
||||
let view = HostingViewHolder()
|
||||
view.backgroundColor = .clear
|
||||
let hostView = UIHostingController(rootView: content)
|
||||
view.contentSize = hostView.view.intrinsicContentSize
|
||||
hostView.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
let constraints = [
|
||||
hostView.view.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
@@ -44,12 +59,20 @@ private struct InteractionView<Content: View>: UIViewRepresentable {
|
||||
]
|
||||
view.addSubview(hostView.view)
|
||||
view.addConstraints(constraints)
|
||||
view.layer.cornerRadius = 18
|
||||
hostView.view.layer.cornerRadius = 18
|
||||
let menuInteraction = UIContextMenuInteraction(delegate: context.coordinator)
|
||||
view.addInteraction(menuInteraction)
|
||||
return view
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIView, context: Context) {}
|
||||
func updateUIView(_ uiView: UIView, context: Context) {
|
||||
let was = (uiView as! HostingViewHolder).contentSize
|
||||
(uiView as! HostingViewHolder).contentSize = uiView.subviews[0].sizeThatFits(CGSizeMake(itemWidth.wrappedValue, .infinity))
|
||||
if was != (uiView as! HostingViewHolder).contentSize {
|
||||
uiView.invalidateIntrinsicContentSize()
|
||||
}
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
|
||||
@@ -21,6 +21,19 @@ struct DetermineWidth: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct DetermineWidthImageVideoItem: View {
|
||||
typealias Key = MaximumWidthImageVideoPreferenceKey
|
||||
var body: some View {
|
||||
GeometryReader { proxy in
|
||||
Color.clear
|
||||
.preference(
|
||||
key: MaximumWidthImageVideoPreferenceKey.self,
|
||||
value: proxy.size.width
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MaximumWidthPreferenceKey: PreferenceKey {
|
||||
static var defaultValue: CGFloat = 0
|
||||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
||||
@@ -28,6 +41,13 @@ struct MaximumWidthPreferenceKey: PreferenceKey {
|
||||
}
|
||||
}
|
||||
|
||||
struct MaximumWidthImageVideoPreferenceKey: PreferenceKey {
|
||||
static var defaultValue: CGFloat = 0
|
||||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
||||
value = max(value, nextValue())
|
||||
}
|
||||
}
|
||||
|
||||
struct DetermineWidth_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
DetermineWidth()
|
||||
|
||||
@@ -0,0 +1,734 @@
|
||||
//
|
||||
// MigrateFromDevice.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 14.02.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
private enum MigrationFromState: Equatable {
|
||||
case chatStopInProgress
|
||||
case chatStopFailed(reason: String)
|
||||
case passphraseNotSet
|
||||
case passphraseConfirmation
|
||||
case uploadConfirmation
|
||||
case archiving
|
||||
case uploadProgress(uploadedBytes: Int64, totalBytes: Int64, fileId: Int64, archivePath: URL, ctrl: chat_ctrl?)
|
||||
case uploadFailed(totalBytes: Int64, archivePath: URL)
|
||||
case linkCreation
|
||||
case linkShown(fileId: Int64, link: String, archivePath: URL, ctrl: chat_ctrl)
|
||||
case finished(chatDeletion: Bool)
|
||||
}
|
||||
|
||||
private enum MigrateFromDeviceViewAlert: Identifiable {
|
||||
case deleteChat(_ title: LocalizedStringKey = "Delete chat profile?", _ text: LocalizedStringKey = "This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost.")
|
||||
case startChat(_ title: LocalizedStringKey = "Start chat?", _ text: LocalizedStringKey = "Warning: starting chat on multiple devices is not supported and will cause message delivery failures")
|
||||
|
||||
case wrongPassphrase(title: LocalizedStringKey = "Wrong passphrase!", message: LocalizedStringKey = "Enter correct passphrase.")
|
||||
case invalidConfirmation(title: LocalizedStringKey = "Invalid migration confirmation")
|
||||
case keychainError(_ title: LocalizedStringKey = "Keychain error")
|
||||
case databaseError(_ title: LocalizedStringKey = "Database error", message: String)
|
||||
case unknownError(_ title: LocalizedStringKey = "Unknown error", message: String)
|
||||
|
||||
case error(title: LocalizedStringKey, error: String = "")
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case let .deleteChat(title, text): return "\(title) \(text)"
|
||||
case let .startChat(title, text): return "\(title) \(text)"
|
||||
|
||||
case .wrongPassphrase: return "wrongPassphrase"
|
||||
case .invalidConfirmation: return "invalidConfirmation"
|
||||
case .keychainError: return "keychainError"
|
||||
case let .databaseError(title, message): return "\(title) \(message)"
|
||||
case let .unknownError(title, message): return "\(title) \(message)"
|
||||
|
||||
case let .error(title, _): return "error \(title)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MigrateFromDevice: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@Binding var showSettings: Bool
|
||||
@Binding var showProgressOnSettings: Bool
|
||||
@State private var migrationState: MigrationFromState = .chatStopInProgress
|
||||
@State private var useKeychain = storeDBPassphraseGroupDefault.get()
|
||||
@AppStorage(GROUP_DEFAULT_INITIAL_RANDOM_DB_PASSPHRASE, store: groupDefaults) private var initialRandomDBPassphrase: Bool = false
|
||||
@State private var alert: MigrateFromDeviceViewAlert?
|
||||
@State private var authorized = !UserDefaults.standard.bool(forKey: DEFAULT_PERFORM_LA)
|
||||
private let tempDatabaseUrl = urlForTemporaryDatabase()
|
||||
@State private var chatReceiver: MigrationChatReceiver? = nil
|
||||
@State private var backDisabled: Bool = false
|
||||
|
||||
var body: some View {
|
||||
if authorized {
|
||||
migrateView()
|
||||
} else {
|
||||
Button(action: runAuth) { Label("Unlock", systemImage: "lock") }
|
||||
.onAppear(perform: runAuth)
|
||||
}
|
||||
}
|
||||
|
||||
private func runAuth() { authorize(NSLocalizedString("Open migration to another device", comment: "authentication reason"), $authorized) }
|
||||
|
||||
func migrateView() -> some View {
|
||||
VStack {
|
||||
switch migrationState {
|
||||
case .chatStopInProgress:
|
||||
chatStopInProgressView()
|
||||
case let .chatStopFailed(reason):
|
||||
chatStopFailedView(reason)
|
||||
case .passphraseNotSet:
|
||||
passphraseNotSetView()
|
||||
case .passphraseConfirmation:
|
||||
PassphraseConfirmationView(migrationState: $migrationState, alert: $alert)
|
||||
case .uploadConfirmation:
|
||||
uploadConfirmationView()
|
||||
case .archiving:
|
||||
archivingView()
|
||||
case let .uploadProgress(uploaded, total, _, archivePath, _):
|
||||
uploadProgressView(uploaded, totalBytes: total, archivePath)
|
||||
case let .uploadFailed(total, archivePath):
|
||||
uploadFailedView(totalBytes: total, archivePath)
|
||||
case .linkCreation:
|
||||
linkCreationView()
|
||||
case let .linkShown(fileId, link, archivePath, ctrl):
|
||||
linkShownView(fileId, link, archivePath, ctrl)
|
||||
case let .finished(chatDeletion):
|
||||
finishedView(chatDeletion)
|
||||
}
|
||||
}
|
||||
.modifier(BackButton(label: "Back", disabled: $backDisabled) {
|
||||
dismiss()
|
||||
})
|
||||
.onChange(of: migrationState) { state in
|
||||
backDisabled = switch migrationState {
|
||||
case .chatStopInProgress, .archiving, .linkShown, .finished: true
|
||||
case .chatStopFailed, .passphraseNotSet, .passphraseConfirmation, .uploadConfirmation, .uploadProgress, .uploadFailed, .linkCreation: false
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
stopChat()
|
||||
}
|
||||
.onDisappear {
|
||||
Task {
|
||||
if !backDisabled {
|
||||
await MainActor.run {
|
||||
showProgressOnSettings = true
|
||||
}
|
||||
await startChatAndDismiss(false)
|
||||
await MainActor.run {
|
||||
showProgressOnSettings = false
|
||||
}
|
||||
}
|
||||
if case let .uploadProgress(_, _, fileId, _, ctrl) = migrationState, let ctrl {
|
||||
await cancelUploadedArchive(fileId, ctrl)
|
||||
}
|
||||
chatReceiver?.stopAndCleanUp()
|
||||
try? FileManager.default.removeItem(at: getMigrationTempFilesDirectory())
|
||||
}
|
||||
}
|
||||
.alert(item: $alert) { alert in
|
||||
switch alert {
|
||||
case let .startChat(title, text):
|
||||
return Alert(
|
||||
title: Text(title),
|
||||
message: Text(text),
|
||||
primaryButton: .destructive(Text("Start chat")) {
|
||||
Task {
|
||||
await startChatAndDismiss()
|
||||
}
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
case let .deleteChat(title, text):
|
||||
return Alert(
|
||||
title: Text(title),
|
||||
message: Text(text),
|
||||
primaryButton: .default(Text("Delete")) {
|
||||
deleteChatAndDismiss()
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
case let .wrongPassphrase(title, message):
|
||||
return Alert(title: Text(title), message: Text(message))
|
||||
case let .invalidConfirmation(title):
|
||||
return Alert(title: Text(title))
|
||||
case let .keychainError(title):
|
||||
return Alert(title: Text(title))
|
||||
case let .databaseError(title, message):
|
||||
return Alert(title: Text(title), message: Text(message))
|
||||
case let .unknownError(title, message):
|
||||
return Alert(title: Text(title), message: Text(message))
|
||||
case let .error(title, error):
|
||||
return Alert(title: Text(title), message: Text(error))
|
||||
}
|
||||
}
|
||||
.interactiveDismissDisabled(backDisabled)
|
||||
}
|
||||
|
||||
private func chatStopInProgressView() -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {} header: {
|
||||
Text("Stopping chat")
|
||||
}
|
||||
}
|
||||
progressView()
|
||||
}
|
||||
}
|
||||
|
||||
private func chatStopFailedView(_ reason: String) -> some View {
|
||||
List {
|
||||
Section {
|
||||
Text(reason)
|
||||
Button(action: stopChat) {
|
||||
settingsRow("stop.fill") {
|
||||
Text("Stop chat").foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Error stopping chat")
|
||||
} footer: {
|
||||
Text("In order to continue, chat should be stopped.")
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func passphraseNotSetView() -> some View {
|
||||
DatabaseEncryptionView(useKeychain: $useKeychain, migration: true)
|
||||
.onChange(of: initialRandomDBPassphrase) { initial in
|
||||
if !initial {
|
||||
migrationState = .uploadConfirmation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadConfirmationView() -> some View {
|
||||
List {
|
||||
Section {
|
||||
Button(action: { migrationState = .archiving }) {
|
||||
settingsRow("tray.and.arrow.up") {
|
||||
Text("Archive and upload").foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Confirm upload")
|
||||
} footer: {
|
||||
Text("All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.")
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func archivingView() -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {} header: {
|
||||
Text("Archiving database")
|
||||
}
|
||||
}
|
||||
progressView()
|
||||
}
|
||||
.onAppear {
|
||||
exportArchive()
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadProgressView(_ uploadedBytes: Int64, totalBytes: Int64, _ archivePath: URL) -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {} header: {
|
||||
Text("Uploading archive")
|
||||
}
|
||||
}
|
||||
let ratio = Float(uploadedBytes) / Float(totalBytes)
|
||||
MigrateFromDevice.largeProgressView(ratio, "\(Int(ratio * 100))%", "\(ByteCountFormatter.string(fromByteCount: uploadedBytes, countStyle: .binary)) uploaded")
|
||||
}
|
||||
.onAppear {
|
||||
startUploading(totalBytes, archivePath)
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadFailedView(totalBytes: Int64, _ archivePath: URL) -> some View {
|
||||
List {
|
||||
Section {
|
||||
Button(action: {
|
||||
migrationState = .uploadProgress(uploadedBytes: 0, totalBytes: totalBytes, fileId: 0, archivePath: archivePath, ctrl: nil)
|
||||
}) {
|
||||
settingsRow("tray.and.arrow.up") {
|
||||
Text("Repeat upload").foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Upload failed")
|
||||
} footer: {
|
||||
Text("You can give another try.")
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
chatReceiver?.stopAndCleanUp()
|
||||
}
|
||||
}
|
||||
|
||||
private func linkCreationView() -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {} header: {
|
||||
Text("Creating archive link")
|
||||
}
|
||||
}
|
||||
progressView()
|
||||
}
|
||||
}
|
||||
|
||||
private func linkShownView(_ fileId: Int64, _ link: String, _ archivePath: URL, _ ctrl: chat_ctrl) -> some View {
|
||||
List {
|
||||
Section {
|
||||
Button(action: { cancelMigration(fileId, ctrl) }) {
|
||||
settingsRow("multiply") {
|
||||
Text("Cancel migration").foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
Button(action: { finishMigration(fileId, ctrl) }) {
|
||||
settingsRow("checkmark") {
|
||||
Text("Finalize migration").foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
} footer: {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Text("**Warning**: the archive will be removed.")
|
||||
Text("Choose _Migrate from another device_ on the new device and scan QR code.")
|
||||
}
|
||||
.font(.callout)
|
||||
}
|
||||
Section("Show QR code") {
|
||||
SimpleXLinkQRCode(uri: link)
|
||||
.padding()
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12, style: .continuous)
|
||||
.fill(Color(uiColor: .secondarySystemGroupedBackground))
|
||||
)
|
||||
.padding(.horizontal)
|
||||
.listRowBackground(Color.clear)
|
||||
.listRowSeparator(.hidden)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
}
|
||||
|
||||
Section("Or securely share this file link") {
|
||||
shareLinkView(link)
|
||||
}
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 10))
|
||||
}
|
||||
}
|
||||
|
||||
private func finishedView(_ chatDeletion: Bool) -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {
|
||||
Button(action: { alert = .startChat() }) {
|
||||
settingsRow("play.fill") {
|
||||
Text("Start chat").foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
Button(action: { alert = .deleteChat() }) {
|
||||
settingsRow("trash.fill") {
|
||||
Text("Delete database from this device").foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Migration complete")
|
||||
} footer: {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Text("You **must not** use the same database on two devices.")
|
||||
Text("**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.")
|
||||
}
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
if chatDeletion {
|
||||
progressView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func shareLinkView(_ link: String) -> some View {
|
||||
HStack {
|
||||
linkTextView(link)
|
||||
Button {
|
||||
showShareSheet(items: [link])
|
||||
} label: {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
.padding(.top, -7)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
private func linkTextView(_ link: String) -> some View {
|
||||
Text(link)
|
||||
.lineLimit(1)
|
||||
.font(.caption)
|
||||
.truncationMode(.middle)
|
||||
}
|
||||
|
||||
static func largeProgressView(_ value: Float, _ title: String, _ description: LocalizedStringKey) -> some View {
|
||||
ZStack {
|
||||
VStack {
|
||||
Text(description)
|
||||
.font(.title3)
|
||||
.hidden()
|
||||
|
||||
Text(title)
|
||||
.font(.system(size: 54))
|
||||
.bold()
|
||||
.foregroundColor(.accentColor)
|
||||
|
||||
Text(description)
|
||||
.font(.title3)
|
||||
}
|
||||
|
||||
Circle()
|
||||
.trim(from: 0, to: CGFloat(value))
|
||||
.stroke(
|
||||
Color.accentColor,
|
||||
style: StrokeStyle(lineWidth: 27)
|
||||
)
|
||||
.rotationEffect(.degrees(180))
|
||||
.animation(.linear, value: value)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.horizontal)
|
||||
.padding(.horizontal)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
private func stopChat() {
|
||||
Task {
|
||||
do {
|
||||
try await stopChatAsync()
|
||||
do {
|
||||
try apiSaveAppSettings(settings: AppSettings.current.prepareForExport())
|
||||
await MainActor.run {
|
||||
migrationState = initialRandomDBPassphraseGroupDefault.get() ? .passphraseNotSet : .passphraseConfirmation
|
||||
}
|
||||
} catch let error {
|
||||
alert = .error(title: "Error saving settings", error: error.localizedDescription)
|
||||
migrationState = .chatStopFailed(reason: NSLocalizedString("Error saving settings", comment: "when migrating"))
|
||||
}
|
||||
} catch let e {
|
||||
await MainActor.run {
|
||||
migrationState = .chatStopFailed(reason: e.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func exportArchive() {
|
||||
Task {
|
||||
do {
|
||||
try? FileManager.default.createDirectory(at: getMigrationTempFilesDirectory(), withIntermediateDirectories: true)
|
||||
let archivePath = try await exportChatArchive(getMigrationTempFilesDirectory())
|
||||
if let attrs = try? FileManager.default.attributesOfItem(atPath: archivePath.path),
|
||||
let totalBytes = attrs[.size] as? Int64 {
|
||||
await MainActor.run {
|
||||
migrationState = .uploadProgress(uploadedBytes: 0, totalBytes: totalBytes, fileId: 0, archivePath: archivePath, ctrl: nil)
|
||||
}
|
||||
} else {
|
||||
await MainActor.run {
|
||||
alert = .error(title: "Exported file doesn't exist")
|
||||
migrationState = .uploadConfirmation
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
await MainActor.run {
|
||||
alert = .error(title: "Error exporting chat database", error: responseError(error))
|
||||
migrationState = .uploadConfirmation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func initTemporaryDatabase() -> (chat_ctrl, User)? {
|
||||
let (status, ctrl) = chatInitTemporaryDatabase(url: tempDatabaseUrl)
|
||||
showErrorOnMigrationIfNeeded(status, $alert)
|
||||
do {
|
||||
if let ctrl, let user = try startChatWithTemporaryDatabase(ctrl: ctrl) {
|
||||
return (ctrl, user)
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("Error while starting chat in temporary database: \(error.localizedDescription)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func startUploading(_ totalBytes: Int64, _ archivePath: URL) {
|
||||
Task {
|
||||
guard let ctrlAndUser = initTemporaryDatabase() else {
|
||||
return migrationState = .uploadFailed(totalBytes: totalBytes, archivePath: archivePath)
|
||||
}
|
||||
let (ctrl, user) = ctrlAndUser
|
||||
chatReceiver = MigrationChatReceiver(ctrl: ctrl, databaseUrl: tempDatabaseUrl) { msg in
|
||||
await MainActor.run {
|
||||
switch msg {
|
||||
case let .sndFileProgressXFTP(_, _, fileTransferMeta, sentSize, totalSize):
|
||||
if case let .uploadProgress(uploaded, total, _, _, _) = migrationState, uploaded != total {
|
||||
migrationState = .uploadProgress(uploadedBytes: sentSize, totalBytes: totalSize, fileId: fileTransferMeta.fileId, archivePath: archivePath, ctrl: ctrl)
|
||||
}
|
||||
case .sndFileRedirectStartXFTP:
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
migrationState = .linkCreation
|
||||
}
|
||||
case let .sndStandaloneFileComplete(_, fileTransferMeta, rcvURIs):
|
||||
let cfg = getNetCfg()
|
||||
let data = MigrationFileLinkData.init(
|
||||
networkConfig: MigrationFileLinkData.NetworkConfig(
|
||||
socksProxy: cfg.socksProxy,
|
||||
hostMode: cfg.hostMode,
|
||||
requiredHostMode: cfg.requiredHostMode
|
||||
)
|
||||
)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
migrationState = .linkShown(fileId: fileTransferMeta.fileId, link: data.addToLink(link: rcvURIs[0]), archivePath: archivePath, ctrl: ctrl)
|
||||
}
|
||||
case .sndFileError:
|
||||
alert = .error(title: "Upload failed", error: "Check your internet connection and try again")
|
||||
migrationState = .uploadFailed(totalBytes: totalBytes, archivePath: archivePath)
|
||||
default:
|
||||
logger.debug("unsupported event: \(msg.responseType)")
|
||||
}
|
||||
}
|
||||
}
|
||||
chatReceiver?.start()
|
||||
|
||||
let (res, error) = await uploadStandaloneFile(user: user, file: CryptoFile.plain(archivePath.lastPathComponent), ctrl: ctrl)
|
||||
await MainActor.run {
|
||||
guard let res = res else {
|
||||
migrationState = .uploadFailed(totalBytes: totalBytes, archivePath: archivePath)
|
||||
return alert = .error(title: "Error uploading the archive", error: error ?? "")
|
||||
}
|
||||
migrationState = .uploadProgress(uploadedBytes: 0, totalBytes: res.fileSize, fileId: res.fileId, archivePath: archivePath, ctrl: ctrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func cancelUploadedArchive(_ fileId: Int64, _ ctrl: chat_ctrl) async {
|
||||
_ = await apiCancelFile(fileId: fileId, ctrl: ctrl)
|
||||
}
|
||||
|
||||
private func cancelMigration(_ fileId: Int64, _ ctrl: chat_ctrl) {
|
||||
Task {
|
||||
await cancelUploadedArchive(fileId, ctrl)
|
||||
await startChatAndDismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private func finishMigration(_ fileId: Int64, _ ctrl: chat_ctrl) {
|
||||
Task {
|
||||
await cancelUploadedArchive(fileId, ctrl)
|
||||
await MainActor.run {
|
||||
migrationState = .finished(chatDeletion: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func deleteChatAndDismiss() {
|
||||
Task {
|
||||
do {
|
||||
try await deleteChatAsync()
|
||||
m.chatDbChanged = true
|
||||
m.chatInitialized = false
|
||||
migrationState = .finished(chatDeletion: true)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()) {
|
||||
resetChatCtrl()
|
||||
do {
|
||||
try initializeChat(start: false)
|
||||
m.chatDbChanged = false
|
||||
AppChatState.shared.set(.active)
|
||||
} catch let error {
|
||||
fatalError("Error starting chat \(responseError(error))")
|
||||
}
|
||||
showSettings = false
|
||||
}
|
||||
} catch let error {
|
||||
alert = .error(title: "Error deleting database", error: responseError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func startChatAndDismiss(_ dismiss: Bool = true) async {
|
||||
AppChatState.shared.set(.active)
|
||||
do {
|
||||
if m.chatDbChanged {
|
||||
resetChatCtrl()
|
||||
try initializeChat(start: true)
|
||||
m.chatDbChanged = false
|
||||
} else {
|
||||
try startChat(refreshInvitations: true)
|
||||
}
|
||||
} catch let error {
|
||||
alert = .error(title: "Error starting chat", error: responseError(error))
|
||||
}
|
||||
// Hide settings anyway if chatDbStatus is not ok, probably passphrase needs to be entered
|
||||
if dismiss || m.chatDbStatus != .ok {
|
||||
await MainActor.run {
|
||||
showSettings = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static func urlForTemporaryDatabase() -> URL {
|
||||
URL(fileURLWithPath: generateNewFileName(getMigrationTempFilesDirectory().path + "/" + "migration", "db", fullPath: true))
|
||||
}
|
||||
}
|
||||
|
||||
private struct PassphraseConfirmationView: View {
|
||||
@Binding var migrationState: MigrationFromState
|
||||
@State private var useKeychain = storeDBPassphraseGroupDefault.get()
|
||||
@State private var currentKey: String = ""
|
||||
@State private var verifyingPassphrase: Bool = false
|
||||
@FocusState private var keyboardVisible: Bool
|
||||
@Binding var alert: MigrateFromDeviceViewAlert?
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
List {
|
||||
chatStoppedView()
|
||||
Section {
|
||||
PassphraseField(key: $currentKey, placeholder: "Current passphrase…", valid: validKey(currentKey))
|
||||
.focused($keyboardVisible)
|
||||
Button(action: {
|
||||
verifyingPassphrase = true
|
||||
hideKeyboard()
|
||||
Task {
|
||||
await verifyDatabasePassphrase(currentKey)
|
||||
verifyingPassphrase = false
|
||||
}
|
||||
}) {
|
||||
settingsRow(useKeychain ? "key" : "lock", color: .secondary) {
|
||||
Text("Verify passphrase")
|
||||
}
|
||||
}
|
||||
.disabled(verifyingPassphrase || currentKey.isEmpty)
|
||||
} header: {
|
||||
Text("Verify database passphrase")
|
||||
} footer: {
|
||||
Text("Confirm that you remember database passphrase to migrate it.")
|
||||
.font(.callout)
|
||||
}
|
||||
.onAppear {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
keyboardVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if verifyingPassphrase {
|
||||
progressView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func verifyDatabasePassphrase(_ dbKey: String) async {
|
||||
do {
|
||||
try await testStorageEncryption(key: dbKey)
|
||||
await MainActor.run {
|
||||
migrationState = .uploadConfirmation
|
||||
}
|
||||
} catch let error {
|
||||
if case .chatCmdError(_, .errorDatabase(.errorOpen(.errorNotADatabase))) = error as? ChatResponse {
|
||||
showErrorOnMigrationIfNeeded(.errorNotADatabase(dbFile: ""), $alert)
|
||||
} else {
|
||||
alert = .error(title: "Error", error: NSLocalizedString("Error verifying passphrase:", comment: "") + " " + String(String(describing: error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func showErrorOnMigrationIfNeeded(_ status: DBMigrationResult, _ alert: Binding<MigrateFromDeviceViewAlert?>) {
|
||||
switch status {
|
||||
case .invalidConfirmation:
|
||||
alert.wrappedValue = .invalidConfirmation()
|
||||
case .errorNotADatabase:
|
||||
alert.wrappedValue = .wrongPassphrase()
|
||||
case .errorKeychain:
|
||||
alert.wrappedValue = .keychainError()
|
||||
case let .errorSQL(_, error):
|
||||
alert.wrappedValue = .databaseError(message: error)
|
||||
case let .unknown(error):
|
||||
alert.wrappedValue = .unknownError(message: error)
|
||||
case .errorMigration: ()
|
||||
case .ok: ()
|
||||
}
|
||||
}
|
||||
|
||||
private func progressView() -> some View {
|
||||
VStack {
|
||||
ProgressView().scaleEffect(2)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity )
|
||||
}
|
||||
|
||||
func chatStoppedView() -> some View {
|
||||
settingsRow("exclamationmark.octagon.fill", color: .red) {
|
||||
Text("Chat is stopped")
|
||||
}
|
||||
}
|
||||
|
||||
private class MigrationChatReceiver {
|
||||
let ctrl: chat_ctrl
|
||||
let databaseUrl: URL
|
||||
let processReceivedMsg: (ChatResponse) async -> Void
|
||||
private var receiveLoop: Task<Void, Never>?
|
||||
private var receiveMessages = true
|
||||
|
||||
init(ctrl: chat_ctrl, databaseUrl: URL, _ processReceivedMsg: @escaping (ChatResponse) async -> Void) {
|
||||
self.ctrl = ctrl
|
||||
self.databaseUrl = databaseUrl
|
||||
self.processReceivedMsg = processReceivedMsg
|
||||
}
|
||||
|
||||
func start() {
|
||||
logger.debug("MigrationChatReceiver.start")
|
||||
receiveMessages = true
|
||||
if receiveLoop != nil { return }
|
||||
receiveLoop = Task { await receiveMsgLoop() }
|
||||
}
|
||||
|
||||
func receiveMsgLoop() async {
|
||||
// TODO use function that has timeout
|
||||
if let msg = await chatRecvMsg(ctrl) {
|
||||
Task {
|
||||
await TerminalItems.shared.add(.resp(.now, msg))
|
||||
}
|
||||
logger.debug("processReceivedMsg: \(msg.responseType)")
|
||||
await processReceivedMsg(msg)
|
||||
}
|
||||
if self.receiveMessages {
|
||||
_ = try? await Task.sleep(nanoseconds: 7_500_000)
|
||||
await receiveMsgLoop()
|
||||
}
|
||||
}
|
||||
|
||||
func stopAndCleanUp() {
|
||||
logger.debug("MigrationChatReceiver.stop")
|
||||
receiveMessages = false
|
||||
receiveLoop?.cancel()
|
||||
receiveLoop = nil
|
||||
chat_close_store(ctrl)
|
||||
try? FileManager.default.removeItem(atPath: "\(databaseUrl.path)_chat.db")
|
||||
try? FileManager.default.removeItem(atPath: "\(databaseUrl.path)_agent.db")
|
||||
}
|
||||
}
|
||||
|
||||
struct MigrateFromDevice_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MigrateFromDevice(showSettings: Binding.constant(true), showProgressOnSettings: Binding.constant(false))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,717 @@
|
||||
//
|
||||
// MigrateToDevice.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 23.02.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
enum MigrationToDeviceState: Codable, Equatable {
|
||||
case downloadProgress(link: String, archiveName: String)
|
||||
case archiveImport(archiveName: String)
|
||||
case passphrase
|
||||
|
||||
// Here we check whether it's needed to show migration process after app restart or not
|
||||
// It's important to NOT show the process when archive was corrupted/not fully downloaded
|
||||
static func makeMigrationState() -> MigrationToState? {
|
||||
let state: MigrationToDeviceState? = UserDefaults.standard.string(forKey: DEFAULT_MIGRATION_TO_STAGE) != nil ? decodeJSON(UserDefaults.standard.string(forKey: DEFAULT_MIGRATION_TO_STAGE)!) : nil
|
||||
var initial: MigrationToState? = .pasteOrScanLink
|
||||
//logger.debug("Inited with migrationState: \(String(describing: state))")
|
||||
switch state {
|
||||
case nil:
|
||||
initial = nil
|
||||
case .downloadProgress:
|
||||
// No migration happens at the moment actually since archive were not downloaded fully
|
||||
logger.debug("MigrateToDevice: archive wasn't fully downloaded, removed broken file")
|
||||
initial = nil
|
||||
case let .archiveImport(archiveName):
|
||||
let archivePath = getMigrationTempFilesDirectory().path + "/" + archiveName
|
||||
initial = .archiveImportFailed(archivePath: archivePath)
|
||||
case .passphrase:
|
||||
initial = .passphrase(passphrase: "")
|
||||
}
|
||||
if initial == nil {
|
||||
UserDefaults.standard.removeObject(forKey: DEFAULT_MIGRATION_TO_STAGE)
|
||||
try? FileManager.default.removeItem(at: getMigrationTempFilesDirectory())
|
||||
}
|
||||
return initial
|
||||
}
|
||||
|
||||
static func save(_ state: MigrationToDeviceState?) {
|
||||
if let state {
|
||||
UserDefaults.standard.setValue(encodeJSON(state), forKey: DEFAULT_MIGRATION_TO_STAGE)
|
||||
} else {
|
||||
UserDefaults.standard.removeObject(forKey: DEFAULT_MIGRATION_TO_STAGE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum MigrationToState: Equatable {
|
||||
case pasteOrScanLink
|
||||
case linkDownloading(link: String)
|
||||
case downloadProgress(downloadedBytes: Int64, totalBytes: Int64, fileId: Int64, link: String, archivePath: String, ctrl: chat_ctrl?)
|
||||
case downloadFailed(totalBytes: Int64, link: String, archivePath: String)
|
||||
case archiveImport(archivePath: String)
|
||||
case archiveImportFailed(archivePath: String)
|
||||
case passphrase(passphrase: String)
|
||||
case migrationConfirmation(status: DBMigrationResult, passphrase: String, useKeychain: Bool)
|
||||
case migration(passphrase: String, confirmation: MigrationConfirmation, useKeychain: Bool)
|
||||
case onion(appSettings: AppSettings)
|
||||
}
|
||||
|
||||
private enum MigrateToDeviceViewAlert: Identifiable {
|
||||
case chatImportedWithErrors(title: LocalizedStringKey = "Chat database imported",
|
||||
text: LocalizedStringKey = "Some non-fatal errors occurred during import - you may see Chat console for more details.")
|
||||
|
||||
case wrongPassphrase(title: LocalizedStringKey = "Wrong passphrase!", message: LocalizedStringKey = "Enter correct passphrase.")
|
||||
case invalidConfirmation(title: LocalizedStringKey = "Invalid migration confirmation")
|
||||
case keychainError(_ title: LocalizedStringKey = "Keychain error")
|
||||
case databaseError(_ title: LocalizedStringKey = "Database error", message: String)
|
||||
case unknownError(_ title: LocalizedStringKey = "Unknown error", message: String)
|
||||
|
||||
case error(title: LocalizedStringKey, error: String = "")
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case .chatImportedWithErrors: return "chatImportedWithErrors"
|
||||
|
||||
case .wrongPassphrase: return "wrongPassphrase"
|
||||
case .invalidConfirmation: return "invalidConfirmation"
|
||||
case .keychainError: return "keychainError"
|
||||
case let .databaseError(title, message): return "\(title) \(message)"
|
||||
case let .unknownError(title, message): return "\(title) \(message)"
|
||||
|
||||
case let .error(title, _): return "error \(title)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MigrateToDevice: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
|
||||
@Binding var migrationState: MigrationToState?
|
||||
@State private var useKeychain = storeDBPassphraseGroupDefault.get()
|
||||
@State private var alert: MigrateToDeviceViewAlert?
|
||||
private let tempDatabaseUrl = urlForTemporaryDatabase()
|
||||
@State private var chatReceiver: MigrationChatReceiver? = nil
|
||||
// Prevent from hiding the view until migration is finished or app deleted
|
||||
@State private var backDisabled: Bool = false
|
||||
@State private var showQRCodeScanner: Bool = true
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
switch migrationState {
|
||||
case nil: EmptyView()
|
||||
case .pasteOrScanLink:
|
||||
pasteOrScanLinkView()
|
||||
case let .linkDownloading(link):
|
||||
linkDownloadingView(link)
|
||||
case let .downloadProgress(downloaded, total, _, _, _, _):
|
||||
downloadProgressView(downloaded, totalBytes: total)
|
||||
case let .downloadFailed(total, link, archivePath):
|
||||
downloadFailedView(totalBytes: total, link, archivePath)
|
||||
case let .archiveImport(archivePath):
|
||||
archiveImportView(archivePath)
|
||||
case let .archiveImportFailed(archivePath):
|
||||
archiveImportFailedView(archivePath)
|
||||
case let .passphrase(passphrase):
|
||||
PassphraseEnteringView(migrationState: $migrationState, currentKey: passphrase, alert: $alert)
|
||||
case let .migrationConfirmation(status, passphrase, useKeychain):
|
||||
migrationConfirmationView(status, passphrase, useKeychain)
|
||||
case let .migration(passphrase, confirmation, useKeychain):
|
||||
migrationView(passphrase, confirmation, useKeychain)
|
||||
case let .onion(appSettings):
|
||||
OnionView(appSettings: appSettings, finishMigration: finishMigration)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
backDisabled = switch migrationState {
|
||||
case nil, .pasteOrScanLink, .linkDownloading, .downloadProgress, .downloadFailed, .archiveImportFailed: false
|
||||
case .archiveImport, .passphrase, .migrationConfirmation, .migration, .onion: true
|
||||
}
|
||||
}
|
||||
.onChange(of: migrationState) { state in
|
||||
backDisabled = switch state {
|
||||
case nil, .pasteOrScanLink, .linkDownloading, .downloadProgress, .downloadFailed, .archiveImportFailed: false
|
||||
case .archiveImport, .passphrase, .migrationConfirmation, .migration, .onion: true
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
Task {
|
||||
if case .archiveImportFailed = migrationState {
|
||||
// Original database is not exist, nothing is setup correctly for showing to a user yet. Return to clean state
|
||||
deleteAppDatabaseAndFiles()
|
||||
initChatAndMigrate()
|
||||
} else if case let .downloadProgress(_, _, fileId, _, _, ctrl) = migrationState, let ctrl {
|
||||
await stopArchiveDownloading(fileId, ctrl)
|
||||
}
|
||||
chatReceiver?.stopAndCleanUp()
|
||||
if !backDisabled {
|
||||
try? FileManager.default.removeItem(at: getMigrationTempFilesDirectory())
|
||||
MigrationToDeviceState.save(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert(item: $alert) { alert in
|
||||
switch alert {
|
||||
case let .chatImportedWithErrors(title, text):
|
||||
return Alert(title: Text(title), message: Text(text))
|
||||
case let .wrongPassphrase(title, message):
|
||||
return Alert(title: Text(title), message: Text(message))
|
||||
case let .invalidConfirmation(title):
|
||||
return Alert(title: Text(title))
|
||||
case let .keychainError(title):
|
||||
return Alert(title: Text(title))
|
||||
case let .databaseError(title, message):
|
||||
return Alert(title: Text(title), message: Text(message))
|
||||
case let .unknownError(title, message):
|
||||
return Alert(title: Text(title), message: Text(message))
|
||||
case let .error(title, error):
|
||||
return Alert(title: Text(title), message: Text(error))
|
||||
}
|
||||
}
|
||||
.interactiveDismissDisabled(backDisabled)
|
||||
}
|
||||
|
||||
private func pasteOrScanLinkView() -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section("Scan QR code") {
|
||||
ScannerInView(showQRCodeScanner: $showQRCodeScanner) { resp in
|
||||
switch resp {
|
||||
case let .success(r):
|
||||
let link = r.string
|
||||
if strHasSimplexFileLink(link.trimmingCharacters(in: .whitespaces)) {
|
||||
migrationState = .linkDownloading(link: link.trimmingCharacters(in: .whitespaces))
|
||||
} else {
|
||||
alert = .error(title: "Invalid link", error: "The text you pasted is not a SimpleX link.")
|
||||
}
|
||||
case let .failure(e):
|
||||
logger.error("processQRCode QR code error: \(e.localizedDescription)")
|
||||
alert = .error(title: "Invalid link", error: "The text you pasted is not a SimpleX link.")
|
||||
}
|
||||
}
|
||||
}
|
||||
if developerTools {
|
||||
Section("Or paste archive link") {
|
||||
pasteLinkView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func pasteLinkView() -> some View {
|
||||
Button {
|
||||
if let str = UIPasteboard.general.string {
|
||||
if strHasSimplexFileLink(str.trimmingCharacters(in: .whitespaces)) {
|
||||
migrationState = .linkDownloading(link: str.trimmingCharacters(in: .whitespaces))
|
||||
} else {
|
||||
alert = .error(title: "Invalid link", error: "The text you pasted is not a SimpleX link.")
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Text("Tap to paste link")
|
||||
}
|
||||
.disabled(!ChatModel.shared.pasteboardHasStrings)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
|
||||
private func linkDownloadingView(_ link: String) -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {} header: {
|
||||
Text("Downloading link details")
|
||||
}
|
||||
}
|
||||
progressView()
|
||||
}
|
||||
.onAppear {
|
||||
downloadLinkDetails(link)
|
||||
}
|
||||
}
|
||||
|
||||
private func downloadProgressView(_ downloadedBytes: Int64, totalBytes: Int64) -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {} header: {
|
||||
Text("Downloading archive")
|
||||
}
|
||||
}
|
||||
let ratio = Float(downloadedBytes) / Float(max(totalBytes, 1))
|
||||
MigrateFromDevice.largeProgressView(ratio, "\(Int(ratio * 100))%", "\(ByteCountFormatter.string(fromByteCount: downloadedBytes, countStyle: .binary)) downloaded")
|
||||
}
|
||||
}
|
||||
|
||||
private func downloadFailedView(totalBytes: Int64, _ link: String, _ archivePath: String) -> some View {
|
||||
List {
|
||||
Section {
|
||||
Button(action: {
|
||||
try? FileManager.default.removeItem(atPath: archivePath)
|
||||
migrationState = .linkDownloading(link: link)
|
||||
}) {
|
||||
settingsRow("tray.and.arrow.down") {
|
||||
Text("Repeat download").foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Download failed")
|
||||
} footer: {
|
||||
Text("You can give another try.")
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
chatReceiver?.stopAndCleanUp()
|
||||
try? FileManager.default.removeItem(atPath: archivePath)
|
||||
MigrationToDeviceState.save(nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func archiveImportView(_ archivePath: String) -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {} header: {
|
||||
Text("Importing archive")
|
||||
}
|
||||
}
|
||||
progressView()
|
||||
}
|
||||
.onAppear {
|
||||
importArchive(archivePath)
|
||||
}
|
||||
}
|
||||
|
||||
private func archiveImportFailedView(_ archivePath: String) -> some View {
|
||||
List {
|
||||
Section {
|
||||
Button(action: {
|
||||
migrationState = .archiveImport(archivePath: archivePath)
|
||||
}) {
|
||||
settingsRow("square.and.arrow.down") {
|
||||
Text("Repeat import").foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Import failed")
|
||||
} footer: {
|
||||
Text("You can give another try.")
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func migrationConfirmationView(_ status: DBMigrationResult, _ passphrase: String, _ useKeychain: Bool) -> some View {
|
||||
List {
|
||||
let (header, button, footer, confirmation): (LocalizedStringKey, LocalizedStringKey?, String, MigrationConfirmation?) = switch status {
|
||||
case let .errorMigration(_, migrationError):
|
||||
switch migrationError {
|
||||
case .upgrade:
|
||||
("Database upgrade",
|
||||
"Upgrade and open chat",
|
||||
"",
|
||||
.yesUp)
|
||||
case .downgrade:
|
||||
("Database downgrade",
|
||||
"Downgrade and open chat",
|
||||
NSLocalizedString("Warning: you may lose some data!", comment: ""),
|
||||
.yesUpDown)
|
||||
case let .migrationError(mtrError):
|
||||
("Incompatible database version",
|
||||
nil,
|
||||
"\(NSLocalizedString("Error: ", comment: "")) \(DatabaseErrorView.mtrErrorDescription(mtrError))",
|
||||
nil)
|
||||
}
|
||||
default: ("Error", nil, "Unknown error", nil)
|
||||
}
|
||||
Section {
|
||||
if let button, let confirmation {
|
||||
Button(action: {
|
||||
migrationState = .migration(passphrase: passphrase, confirmation: confirmation, useKeychain: useKeychain)
|
||||
}) {
|
||||
settingsRow("square.and.arrow.down") {
|
||||
Text(button).foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
} header: {
|
||||
Text(header)
|
||||
} footer: {
|
||||
Text(footer)
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func migrationView(_ passphrase: String, _ confirmation: MigrationConfirmation, _ useKeychain: Bool) -> some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {} header: {
|
||||
Text("Migrating")
|
||||
}
|
||||
}
|
||||
progressView()
|
||||
}
|
||||
.onAppear {
|
||||
startChat(passphrase, confirmation, useKeychain)
|
||||
}
|
||||
}
|
||||
|
||||
struct OnionView: View {
|
||||
@State var appSettings: AppSettings
|
||||
@State private var onionHosts: OnionHosts = .no
|
||||
var finishMigration: (AppSettings) -> Void
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section {
|
||||
Button(action: {
|
||||
var updated = appSettings.networkConfig!
|
||||
let (hostMode, requiredHostMode) = onionHosts.hostMode
|
||||
updated.hostMode = hostMode
|
||||
updated.requiredHostMode = requiredHostMode
|
||||
updated.socksProxy = nil
|
||||
appSettings.networkConfig = updated
|
||||
finishMigration(appSettings)
|
||||
}) {
|
||||
settingsRow("checkmark") {
|
||||
Text("Apply").foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Confirm network settings")
|
||||
} footer: {
|
||||
Text("Please confirm that network settings are correct for this device.")
|
||||
.font(.callout)
|
||||
}
|
||||
|
||||
Section("Network settings") {
|
||||
Picker("Use .onion hosts", selection: $onionHosts) {
|
||||
ForEach(OnionHosts.values, id: \.self) { Text($0.text) }
|
||||
}
|
||||
.frame(height: 36)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func downloadLinkDetails(_ link: String) {
|
||||
let archiveTime = Date.now
|
||||
let ts = archiveTime.ISO8601Format(Date.ISO8601FormatStyle(timeSeparator: .omitted))
|
||||
let archiveName = "simplex-chat.\(ts).zip"
|
||||
let archivePath = getMigrationTempFilesDirectory().appendingPathComponent(archiveName)
|
||||
|
||||
startDownloading(0, link, archivePath.path)
|
||||
}
|
||||
|
||||
private func initTemporaryDatabase() -> (chat_ctrl, User)? {
|
||||
let (status, ctrl) = chatInitTemporaryDatabase(url: tempDatabaseUrl)
|
||||
showErrorOnMigrationIfNeeded(status, $alert)
|
||||
do {
|
||||
if let ctrl, let user = try startChatWithTemporaryDatabase(ctrl: ctrl) {
|
||||
return (ctrl, user)
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("Error while starting chat in temporary database: \(error.localizedDescription)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func startDownloading(_ totalBytes: Int64, _ link: String, _ archivePath: String) {
|
||||
Task {
|
||||
guard let ctrlAndUser = initTemporaryDatabase() else {
|
||||
return migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath)
|
||||
}
|
||||
let (ctrl, user) = ctrlAndUser
|
||||
chatReceiver = MigrationChatReceiver(ctrl: ctrl, databaseUrl: tempDatabaseUrl) { msg in
|
||||
await MainActor.run {
|
||||
switch msg {
|
||||
case let .rcvFileProgressXFTP(_, _, receivedSize, totalSize, rcvFileTransfer):
|
||||
migrationState = .downloadProgress(downloadedBytes: receivedSize, totalBytes: totalSize, fileId: rcvFileTransfer.fileId, link: link, archivePath: archivePath, ctrl: ctrl)
|
||||
MigrationToDeviceState.save(.downloadProgress(link: link, archiveName: URL(fileURLWithPath: archivePath).lastPathComponent))
|
||||
case .rcvStandaloneFileComplete:
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
// User closed the whole screen before new state was saved
|
||||
if migrationState == nil {
|
||||
MigrationToDeviceState.save(nil)
|
||||
} else {
|
||||
migrationState = .archiveImport(archivePath: archivePath)
|
||||
MigrationToDeviceState.save(.archiveImport(archiveName: URL(fileURLWithPath: archivePath).lastPathComponent))
|
||||
}
|
||||
}
|
||||
case .rcvFileError:
|
||||
alert = .error(title: "Download failed", error: "File was deleted or link is invalid")
|
||||
migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath)
|
||||
case .chatError(_, .error(.noRcvFileUser)):
|
||||
alert = .error(title: "Download failed", error: "File was deleted or link is invalid")
|
||||
migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath)
|
||||
default:
|
||||
logger.debug("unsupported event: \(msg.responseType)")
|
||||
}
|
||||
}
|
||||
}
|
||||
chatReceiver?.start()
|
||||
|
||||
let (res, error) = await downloadStandaloneFile(user: user, url: link, file: CryptoFile.plain(URL(fileURLWithPath: archivePath).lastPathComponent), ctrl: ctrl)
|
||||
if res == nil {
|
||||
await MainActor.run {
|
||||
migrationState = .downloadFailed(totalBytes: totalBytes, link: link, archivePath: archivePath)
|
||||
}
|
||||
return alert = .error(title: "Error downloading the archive", error: error ?? "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func importArchive(_ archivePath: String) {
|
||||
Task {
|
||||
do {
|
||||
if !hasChatCtrl() {
|
||||
chatInitControllerRemovingDatabases()
|
||||
}
|
||||
try await apiDeleteStorage()
|
||||
do {
|
||||
let config = ArchiveConfig(archivePath: archivePath)
|
||||
let archiveErrors = try await apiImportArchive(config: config)
|
||||
if !archiveErrors.isEmpty {
|
||||
alert = .chatImportedWithErrors()
|
||||
}
|
||||
await MainActor.run {
|
||||
migrationState = .passphrase(passphrase: "")
|
||||
MigrationToDeviceState.save(.passphrase)
|
||||
}
|
||||
} catch let error {
|
||||
await MainActor.run {
|
||||
migrationState = .archiveImportFailed(archivePath: archivePath)
|
||||
}
|
||||
alert = .error(title: "Error importing chat database", error: responseError(error))
|
||||
}
|
||||
} catch let error {
|
||||
await MainActor.run {
|
||||
migrationState = .archiveImportFailed(archivePath: archivePath)
|
||||
}
|
||||
alert = .error(title: "Error deleting chat database", error: responseError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func stopArchiveDownloading(_ fileId: Int64, _ ctrl: chat_ctrl) async {
|
||||
_ = await apiCancelFile(fileId: fileId, ctrl: ctrl)
|
||||
}
|
||||
|
||||
private func startChat(_ passphrase: String, _ confirmation: MigrationConfirmation, _ useKeychain: Bool) {
|
||||
if useKeychain {
|
||||
_ = kcDatabasePassword.set(passphrase)
|
||||
} else {
|
||||
_ = kcDatabasePassword.remove()
|
||||
}
|
||||
storeDBPassphraseGroupDefault.set(useKeychain)
|
||||
initialRandomDBPassphraseGroupDefault.set(false)
|
||||
AppChatState.shared.set(.active)
|
||||
Task {
|
||||
do {
|
||||
resetChatCtrl()
|
||||
try initializeChat(start: false, confirmStart: false, dbKey: passphrase, refreshInvitations: true, confirmMigrations: confirmation)
|
||||
var appSettings = try apiGetAppSettings(settings: AppSettings.current.prepareForExport())
|
||||
let hasOnionConfigured = appSettings.networkConfig?.socksProxy != nil || appSettings.networkConfig?.hostMode == .onionHost
|
||||
appSettings.networkConfig?.socksProxy = nil
|
||||
appSettings.networkConfig?.hostMode = .publicHost
|
||||
appSettings.networkConfig?.requiredHostMode = true
|
||||
await MainActor.run {
|
||||
if hasOnionConfigured {
|
||||
migrationState = .onion(appSettings: appSettings)
|
||||
} else {
|
||||
finishMigration(appSettings)
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
hideView()
|
||||
AlertManager.shared.showAlert(Alert(title: Text("Error starting chat"), message: Text(responseError(error))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func finishMigration(_ appSettings: AppSettings) {
|
||||
do {
|
||||
try? FileManager.default.removeItem(at: getMigrationTempFilesDirectory())
|
||||
MigrationToDeviceState.save(nil)
|
||||
appSettings.importIntoApp()
|
||||
try SimpleX.startChat(refreshInvitations: true)
|
||||
AlertManager.shared.showAlertMsg(title: "Chat migrated!", message: "Finalize migration on another device.")
|
||||
} catch let error {
|
||||
AlertManager.shared.showAlert(Alert(title: Text("Error starting chat"), message: Text(responseError(error))))
|
||||
}
|
||||
hideView()
|
||||
}
|
||||
|
||||
private func hideView() {
|
||||
onboardingStageDefault.set(.onboardingComplete)
|
||||
m.onboardingStage = .onboardingComplete
|
||||
dismiss()
|
||||
}
|
||||
|
||||
private func strHasSimplexFileLink(_ text: String) -> Bool {
|
||||
text.starts(with: "simplex:/file") || text.starts(with: "https://simplex.chat/file")
|
||||
}
|
||||
|
||||
private static func urlForTemporaryDatabase() -> URL {
|
||||
URL(fileURLWithPath: generateNewFileName(getMigrationTempFilesDirectory().path + "/" + "migration", "db", fullPath: true))
|
||||
}
|
||||
}
|
||||
|
||||
private struct PassphraseEnteringView: View {
|
||||
@Binding var migrationState: MigrationToState?
|
||||
@State private var useKeychain = true
|
||||
@State var currentKey: String
|
||||
@State private var verifyingPassphrase: Bool = false
|
||||
@FocusState private var keyboardVisible: Bool
|
||||
@Binding var alert: MigrateToDeviceViewAlert?
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
List {
|
||||
Section {
|
||||
settingsRow("key", color: .secondary) {
|
||||
Toggle("Save passphrase in Keychain", isOn: $useKeychain)
|
||||
}
|
||||
|
||||
PassphraseField(key: $currentKey, placeholder: "Current passphrase…", valid: validKey(currentKey))
|
||||
.focused($keyboardVisible)
|
||||
Button(action: {
|
||||
verifyingPassphrase = true
|
||||
hideKeyboard()
|
||||
Task {
|
||||
let (status, _) = chatInitTemporaryDatabase(url: getAppDatabasePath(), key: currentKey, confirmation: .yesUp)
|
||||
let success = switch status {
|
||||
case .ok, .invalidConfirmation: true
|
||||
default: false
|
||||
}
|
||||
if success {
|
||||
await MainActor.run {
|
||||
migrationState = .migration(passphrase: currentKey, confirmation: .yesUp, useKeychain: useKeychain)
|
||||
}
|
||||
} else if case .errorMigration = status {
|
||||
await MainActor.run {
|
||||
migrationState = .migrationConfirmation(status: status, passphrase: currentKey, useKeychain: useKeychain)
|
||||
}
|
||||
} else {
|
||||
showErrorOnMigrationIfNeeded(status, $alert)
|
||||
}
|
||||
verifyingPassphrase = false
|
||||
}
|
||||
}) {
|
||||
settingsRow("key", color: .secondary) {
|
||||
Text("Open chat")
|
||||
}
|
||||
}
|
||||
.disabled(verifyingPassphrase || currentKey.isEmpty)
|
||||
} header: {
|
||||
Text("Enter passphrase")
|
||||
} footer: {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
if useKeychain {
|
||||
Text("iOS Keychain is used to securely store passphrase - it allows receiving push notifications.")
|
||||
} else {
|
||||
Text("You have to enter passphrase every time the app starts - it is not stored on the device.")
|
||||
Text("**Please note**: you will NOT be able to recover or change passphrase if you lose it.")
|
||||
Text("**Warning**: Instant push notifications require passphrase saved in Keychain.")
|
||||
}
|
||||
}
|
||||
.font(.callout)
|
||||
.padding(.top, 1)
|
||||
.onTapGesture { keyboardVisible = false }
|
||||
}
|
||||
.onAppear {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
keyboardVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if verifyingPassphrase {
|
||||
progressView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func showErrorOnMigrationIfNeeded(_ status: DBMigrationResult, _ alert: Binding<MigrateToDeviceViewAlert?>) {
|
||||
switch status {
|
||||
case .invalidConfirmation:
|
||||
alert.wrappedValue = .invalidConfirmation()
|
||||
case .errorNotADatabase:
|
||||
alert.wrappedValue = .wrongPassphrase()
|
||||
case .errorKeychain:
|
||||
alert.wrappedValue = .keychainError()
|
||||
case let .errorSQL(_, error):
|
||||
alert.wrappedValue = .databaseError(message: error)
|
||||
case let .unknown(error):
|
||||
alert.wrappedValue = .unknownError(message: error)
|
||||
case .errorMigration: ()
|
||||
case .ok: ()
|
||||
}
|
||||
}
|
||||
|
||||
private func progressView() -> some View {
|
||||
VStack {
|
||||
ProgressView().scaleEffect(2)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity )
|
||||
}
|
||||
|
||||
private class MigrationChatReceiver {
|
||||
let ctrl: chat_ctrl
|
||||
let databaseUrl: URL
|
||||
let processReceivedMsg: (ChatResponse) async -> Void
|
||||
private var receiveLoop: Task<Void, Never>?
|
||||
private var receiveMessages = true
|
||||
|
||||
init(ctrl: chat_ctrl, databaseUrl: URL, _ processReceivedMsg: @escaping (ChatResponse) async -> Void) {
|
||||
self.ctrl = ctrl
|
||||
self.databaseUrl = databaseUrl
|
||||
self.processReceivedMsg = processReceivedMsg
|
||||
}
|
||||
|
||||
func start() {
|
||||
logger.debug("MigrationChatReceiver.start")
|
||||
receiveMessages = true
|
||||
if receiveLoop != nil { return }
|
||||
receiveLoop = Task { await receiveMsgLoop() }
|
||||
}
|
||||
|
||||
func receiveMsgLoop() async {
|
||||
// TODO use function that has timeout
|
||||
if let msg = await chatRecvMsg(ctrl) {
|
||||
Task {
|
||||
await TerminalItems.shared.add(.resp(.now, msg))
|
||||
}
|
||||
logger.debug("processReceivedMsg: \(msg.responseType)")
|
||||
await processReceivedMsg(msg)
|
||||
}
|
||||
if self.receiveMessages {
|
||||
_ = try? await Task.sleep(nanoseconds: 7_500_000)
|
||||
await receiveMsgLoop()
|
||||
}
|
||||
}
|
||||
|
||||
func stopAndCleanUp() {
|
||||
logger.debug("MigrationChatReceiver.stop")
|
||||
receiveMessages = false
|
||||
receiveLoop?.cancel()
|
||||
receiveLoop = nil
|
||||
chat_close_store(ctrl)
|
||||
try? FileManager.default.removeItem(atPath: "\(databaseUrl.path)_chat.db")
|
||||
try? FileManager.default.removeItem(atPath: "\(databaseUrl.path)_agent.db")
|
||||
}
|
||||
}
|
||||
|
||||
struct MigrateToDevice_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MigrateToDevice(migrationState: Binding.constant(.pasteOrScanLink))
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ struct NewChatView: View {
|
||||
}
|
||||
}
|
||||
if case .connect = selection {
|
||||
ConnectView(showQRCodeScanner: showQRCodeScanner, pastedLink: $pastedLink, alert: $alert)
|
||||
ConnectView(showQRCodeScanner: $showQRCodeScanner, pastedLink: $pastedLink, alert: $alert)
|
||||
.transition(.move(edge: .trailing))
|
||||
}
|
||||
}
|
||||
@@ -284,8 +284,7 @@ private struct InviteView: View {
|
||||
|
||||
private struct ConnectView: View {
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@State var showQRCodeScanner = false
|
||||
@State private var cameraAuthorizationStatus: AVAuthorizationStatus?
|
||||
@Binding var showQRCodeScanner: Bool
|
||||
@Binding var pastedLink: String
|
||||
@Binding var alert: NewChatViewAlert?
|
||||
@State private var sheet: PlanAndConnectActionSheet?
|
||||
@@ -295,32 +294,13 @@ private struct ConnectView: View {
|
||||
Section("Paste the link you received") {
|
||||
pasteLinkView()
|
||||
}
|
||||
|
||||
scanCodeView()
|
||||
Section("Or scan QR code") {
|
||||
ScannerInView(showQRCodeScanner: $showQRCodeScanner, processQRCode: processQRCode)
|
||||
}
|
||||
}
|
||||
.actionSheet(item: $sheet) { s in
|
||||
planAndConnectActionSheet(s, dismiss: true, cleanup: { pastedLink = "" })
|
||||
}
|
||||
.onAppear {
|
||||
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
||||
cameraAuthorizationStatus = status
|
||||
if showQRCodeScanner {
|
||||
switch status {
|
||||
case .notDetermined: askCameraAuthorization()
|
||||
case .restricted: showQRCodeScanner = false
|
||||
case .denied: showQRCodeScanner = false
|
||||
case .authorized: ()
|
||||
@unknown default: askCameraAuthorization()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func askCameraAuthorization(_ cb: (() -> Void)? = nil) {
|
||||
AVCaptureDevice.requestAccess(for: .video) { allowed in
|
||||
cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
|
||||
if allowed { cb?() }
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func pasteLinkView() -> some View {
|
||||
@@ -351,8 +331,45 @@ private struct ConnectView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func scanCodeView() -> some View {
|
||||
Section("Or scan QR code") {
|
||||
private func processQRCode(_ resp: Result<ScanResult, ScanError>) {
|
||||
switch resp {
|
||||
case let .success(r):
|
||||
let link = r.string
|
||||
if strIsSimplexLink(r.string) {
|
||||
connect(link)
|
||||
} else {
|
||||
alert = .newChatSomeAlert(alert: .someAlert(
|
||||
alert: mkAlert(title: "Invalid QR code", message: "The code you scanned is not a SimpleX link QR code."),
|
||||
id: "processQRCode: code is not a SimpleX link"
|
||||
))
|
||||
}
|
||||
case let .failure(e):
|
||||
logger.error("processQRCode QR code error: \(e.localizedDescription)")
|
||||
alert = .newChatSomeAlert(alert: .someAlert(
|
||||
alert: mkAlert(title: "Invalid QR code", message: "Error scanning code: \(e.localizedDescription)"),
|
||||
id: "processQRCode: failure"
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private func connect(_ link: String) {
|
||||
planAndConnect(
|
||||
link,
|
||||
showAlert: { alert = .planAndConnectAlert(alert: $0) },
|
||||
showActionSheet: { sheet = $0 },
|
||||
dismiss: true,
|
||||
incognito: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct ScannerInView: View {
|
||||
@Binding var showQRCodeScanner: Bool
|
||||
let processQRCode: (_ resp: Result<ScanResult, ScanError>) -> Void
|
||||
@State private var cameraAuthorizationStatus: AVAuthorizationStatus?
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if showQRCodeScanner, case .authorized = cameraAuthorizationStatus {
|
||||
CodeScannerView(codeTypes: [.qr], scanMode: .continuous, completion: processQRCode)
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
@@ -396,37 +413,26 @@ private struct ConnectView: View {
|
||||
.disabled(cameraAuthorizationStatus == .restricted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func processQRCode(_ resp: Result<ScanResult, ScanError>) {
|
||||
switch resp {
|
||||
case let .success(r):
|
||||
let link = r.string
|
||||
if strIsSimplexLink(r.string) {
|
||||
connect(link)
|
||||
} else {
|
||||
alert = .newChatSomeAlert(alert: .someAlert(
|
||||
alert: mkAlert(title: "Invalid QR code", message: "The code you scanned is not a SimpleX link QR code."),
|
||||
id: "processQRCode: code is not a SimpleX link"
|
||||
))
|
||||
.onAppear {
|
||||
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
||||
cameraAuthorizationStatus = status
|
||||
if showQRCodeScanner {
|
||||
switch status {
|
||||
case .notDetermined: askCameraAuthorization()
|
||||
case .restricted: showQRCodeScanner = false
|
||||
case .denied: showQRCodeScanner = false
|
||||
case .authorized: ()
|
||||
@unknown default: askCameraAuthorization()
|
||||
}
|
||||
}
|
||||
case let .failure(e):
|
||||
logger.error("processQRCode QR code error: \(e.localizedDescription)")
|
||||
alert = .newChatSomeAlert(alert: .someAlert(
|
||||
alert: mkAlert(title: "Invalid QR code", message: "Error scanning code: \(e.localizedDescription)"),
|
||||
id: "processQRCode: failure"
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private func connect(_ link: String) {
|
||||
planAndConnect(
|
||||
link,
|
||||
showAlert: { alert = .planAndConnectAlert(alert: $0) },
|
||||
showActionSheet: { sheet = $0 },
|
||||
dismiss: true,
|
||||
incognito: nil
|
||||
)
|
||||
func askCameraAuthorization(_ cb: (() -> Void)? = nil) {
|
||||
AVCaptureDevice.requestAccess(for: .video) { allowed in
|
||||
cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
|
||||
if allowed { cb?() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -166,8 +166,10 @@ private func createProfile(_ displayName: String, showAlert: (UserProfileAlert)
|
||||
)
|
||||
let m = ChatModel.shared
|
||||
do {
|
||||
AppChatState.shared.set(.active)
|
||||
m.currentUser = try apiCreateActiveUser(profile)
|
||||
if m.users.isEmpty {
|
||||
// .isEmpty check is redundant here, but it makes it clearer what is going on
|
||||
if m.users.isEmpty || m.users.allSatisfy({ $0.user.hidden }) {
|
||||
try startChat()
|
||||
withAnimation {
|
||||
onboardingStageDefault.set(.step3_CreateSimpleXAddress)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
struct SimpleXInfo: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@@ -44,6 +45,15 @@ struct SimpleXInfo: View {
|
||||
if onboarding {
|
||||
OnboardingActionButton()
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
m.migrationState = .pasteOrScanLink
|
||||
} label: {
|
||||
Label("Migrate from another device", systemImage: "tray.and.arrow.down")
|
||||
.font(.subheadline)
|
||||
}
|
||||
.padding(.bottom, 8)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
Button {
|
||||
@@ -54,9 +64,24 @@ struct SimpleXInfo: View {
|
||||
}
|
||||
.padding(.bottom, 8)
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
}
|
||||
.frame(minHeight: g.size.height)
|
||||
}
|
||||
.sheet(isPresented: Binding(
|
||||
get: { m.migrationState != nil },
|
||||
set: { _ in
|
||||
m.migrationState = nil
|
||||
MigrationToDeviceState.save(nil) }
|
||||
)) {
|
||||
NavigationView {
|
||||
VStack(alignment: .leading) {
|
||||
MigrateToDevice(migrationState: $m.migrationState)
|
||||
}
|
||||
.navigationTitle("Migrate here")
|
||||
.background(colorScheme == .light ? Color(uiColor: .tertiarySystemGroupedBackground) : .clear)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showHowItWorks) {
|
||||
HowItWorks(onboarding: onboarding)
|
||||
}
|
||||
@@ -87,6 +112,7 @@ struct SimpleXInfo: View {
|
||||
|
||||
struct OnboardingActionButton: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
var body: some View {
|
||||
if m.currentUser == nil {
|
||||
@@ -111,6 +137,21 @@ struct OnboardingActionButton: View {
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.bottom)
|
||||
}
|
||||
|
||||
private func actionButton(_ label: LocalizedStringKey, action: @escaping () -> Void) -> some View {
|
||||
Button {
|
||||
withAnimation {
|
||||
action()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
Text(label).font(.title2)
|
||||
Image(systemName: "greaterthan")
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
|
||||
struct SimpleXInfo_Previews: PreviewProvider {
|
||||
|
||||
@@ -344,6 +344,37 @@ private let versionDescriptions: [VersionDescription] = [
|
||||
description: "Thanks to the users – [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!"
|
||||
),
|
||||
]
|
||||
),
|
||||
VersionDescription(
|
||||
version: "v5.6",
|
||||
post: URL(string: "https://simplex.chat/blog/20240323-simplex-network-privacy-non-profit-v5-6-quantum-resistant-e2e-encryption-simple-migration.html"),
|
||||
features: [
|
||||
FeatureDescription(
|
||||
icon: "key",
|
||||
title: "Quantum resistant encryption",
|
||||
description: "Enable in direct chats (BETA)!"
|
||||
),
|
||||
FeatureDescription(
|
||||
icon: "tray.and.arrow.up",
|
||||
title: "App data migration",
|
||||
description: "Migrate to another device via QR code."
|
||||
),
|
||||
FeatureDescription(
|
||||
icon: "phone",
|
||||
title: "Picture-in-picture calls",
|
||||
description: "Use the app while in the call."
|
||||
),
|
||||
FeatureDescription(
|
||||
icon: "hand.raised",
|
||||
title: "Safer groups",
|
||||
description: "Admins can block a member for all."
|
||||
),
|
||||
FeatureDescription(
|
||||
icon: "character",
|
||||
title: "Hungarian interface",
|
||||
description: "Thanks to the users – [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)!"
|
||||
),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ struct ConnectDesktopView: View {
|
||||
var body: some View {
|
||||
if viaSettings {
|
||||
viewBody
|
||||
.modifier(BackButton(label: "Back") {
|
||||
.modifier(BackButton(label: "Back", disabled: Binding.constant(false)) {
|
||||
if m.activeRemoteCtrl {
|
||||
alert = .disconnectDesktop(action: .back)
|
||||
} else {
|
||||
|
||||
@@ -51,9 +51,10 @@ struct AdvancedNetworkSettings: View {
|
||||
}
|
||||
.disabled(currentNetCfg == NetCfg.proxyDefaults)
|
||||
|
||||
timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [7_500000, 10_000000, 15_000000, 20_000000, 30_000000, 45_000000], label: secondsLabel)
|
||||
timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [5_000000, 7_500000, 10_000000, 15_000000, 20_000000, 30_000000, 40_000000], label: secondsLabel)
|
||||
timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [5_000000, 7_000000, 10_000000, 15_000000, 20_000000, 30_000000], label: secondsLabel)
|
||||
timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [15_000, 30_000, 45_000, 60_000, 90_000, 120_000], label: secondsLabel)
|
||||
timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [2_500, 5_000, 10_000, 15_000, 20_000, 30_000], label: secondsLabel)
|
||||
intSettingPicker("Receiving concurrency", selection: $netCfg.rcvConcurrency, values: [1, 2, 4, 8, 12, 16, 24], label: "")
|
||||
timeoutSettingPicker("PING interval", selection: $netCfg.smpPingInterval, values: [120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000], label: secondsLabel)
|
||||
intSettingPicker("PING count", selection: $netCfg.smpPingCount, values: [1, 2, 3, 5, 8], label: "")
|
||||
Toggle("Enable TCP keep-alive", isOn: $enableKeepAlive)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// AppSettings.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 26.02.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SimpleXChat
|
||||
import SwiftUI
|
||||
|
||||
extension AppSettings {
|
||||
public func importIntoApp() {
|
||||
let def = UserDefaults.standard
|
||||
if var val = networkConfig {
|
||||
// migrating from Android/desktop BUT shouldn't be here ever because it should be changed in migration stage
|
||||
if case .onionViaSocks = val.hostMode {
|
||||
val.hostMode = .publicHost
|
||||
val.requiredHostMode = true
|
||||
}
|
||||
val.socksProxy = nil
|
||||
setNetCfg(val)
|
||||
}
|
||||
if let val = privacyEncryptLocalFiles { privacyEncryptLocalFilesGroupDefault.set(val) }
|
||||
if let val = privacyAcceptImages {
|
||||
privacyAcceptImagesGroupDefault.set(val)
|
||||
def.setValue(val, forKey: DEFAULT_PRIVACY_ACCEPT_IMAGES)
|
||||
}
|
||||
if let val = privacyLinkPreviews { def.setValue(val, forKey: DEFAULT_PRIVACY_LINK_PREVIEWS) }
|
||||
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) }
|
||||
if let val = notificationMode { ChatModel.shared.notificationMode = val.toNotificationsMode() }
|
||||
if let val = notificationPreviewMode { ntfPreviewModeGroupDefault.set(val) }
|
||||
if let val = webrtcPolicyRelay { def.setValue(val, forKey: DEFAULT_WEBRTC_POLICY_RELAY) }
|
||||
if let val = webrtcICEServers { def.setValue(val, forKey: DEFAULT_WEBRTC_ICE_SERVERS) }
|
||||
if let val = confirmRemoteSessions { def.setValue(val, forKey: DEFAULT_CONFIRM_REMOTE_SESSIONS) }
|
||||
if let val = connectRemoteViaMulticast { def.setValue(val, forKey: DEFAULT_CONNECT_REMOTE_VIA_MULTICAST) }
|
||||
if let val = connectRemoteViaMulticastAuto { def.setValue(val, forKey: DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO) }
|
||||
if let val = developerTools { def.setValue(val, forKey: DEFAULT_DEVELOPER_TOOLS) }
|
||||
if let val = confirmDBUpgrades { confirmDBUpgradesGroupDefault.set(val) }
|
||||
if let val = androidCallOnLockScreen { def.setValue(val.rawValue, forKey: ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN) }
|
||||
if let val = iosCallKitEnabled { callKitEnabledGroupDefault.set(val) }
|
||||
if let val = iosCallKitCallsInRecents { def.setValue(val, forKey: DEFAULT_CALL_KIT_CALLS_IN_RECENTS) }
|
||||
}
|
||||
|
||||
public static var current: AppSettings {
|
||||
let def = UserDefaults.standard
|
||||
var c = AppSettings.defaults
|
||||
c.networkConfig = getNetCfg()
|
||||
c.privacyEncryptLocalFiles = privacyEncryptLocalFilesGroupDefault.get()
|
||||
c.privacyAcceptImages = privacyAcceptImagesGroupDefault.get()
|
||||
c.privacyLinkPreviews = def.bool(forKey: DEFAULT_PRIVACY_LINK_PREVIEWS)
|
||||
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)
|
||||
c.notificationMode = AppSettingsNotificationMode.from(ChatModel.shared.notificationMode)
|
||||
c.notificationPreviewMode = ntfPreviewModeGroupDefault.get()
|
||||
c.webrtcPolicyRelay = def.bool(forKey: DEFAULT_WEBRTC_POLICY_RELAY)
|
||||
c.webrtcICEServers = def.stringArray(forKey: DEFAULT_WEBRTC_ICE_SERVERS)
|
||||
c.confirmRemoteSessions = def.bool(forKey: DEFAULT_CONFIRM_REMOTE_SESSIONS)
|
||||
c.connectRemoteViaMulticast = def.bool(forKey: DEFAULT_CONNECT_REMOTE_VIA_MULTICAST)
|
||||
c.connectRemoteViaMulticastAuto = def.bool(forKey: DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO)
|
||||
c.developerTools = def.bool(forKey: DEFAULT_DEVELOPER_TOOLS)
|
||||
c.confirmDBUpgrades = confirmDBUpgradesGroupDefault.get()
|
||||
c.androidCallOnLockScreen = AppSettingsLockScreenCalls(rawValue: def.string(forKey: ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN)!)
|
||||
c.iosCallKitEnabled = callKitEnabledGroupDefault.get()
|
||||
c.iosCallKitCallsInRecents = def.bool(forKey: DEFAULT_CALL_KIT_CALLS_IN_RECENTS)
|
||||
return c
|
||||
}
|
||||
}
|
||||
@@ -64,10 +64,10 @@ struct DeveloperView: View {
|
||||
|
||||
private func setPQExperimentalEnabled(_ enable: Bool) {
|
||||
do {
|
||||
try apiSetPQEnabled(enable)
|
||||
try apiSetPQEncryption(enable)
|
||||
} catch let error {
|
||||
let err = responseError(error)
|
||||
logger.error("apiSetPQEnabled \(err)")
|
||||
logger.error("apiSetPQEncryption \(err)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ private enum NetworkAlert: Identifiable {
|
||||
}
|
||||
|
||||
struct NetworkAndServers: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
|
||||
@State private var cfgLoaded = false
|
||||
@State private var currentNetCfg = NetCfg.defaults
|
||||
@@ -82,6 +83,14 @@ struct NetworkAndServers: View {
|
||||
Text("WebRTC ICE servers")
|
||||
}
|
||||
}
|
||||
|
||||
Section("Network connection") {
|
||||
HStack {
|
||||
Text(m.networkInfo.networkType.text)
|
||||
Spacer()
|
||||
Image(systemName: "circle.fill").foregroundColor(m.networkInfo.online ? .green : .red)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
|
||||
@@ -31,7 +31,7 @@ struct ProtocolServerView: View {
|
||||
ProgressView().scaleEffect(2)
|
||||
}
|
||||
}
|
||||
.modifier(BackButton(label: "Your \(proto) servers") {
|
||||
.modifier(BackButton(label: "Your \(proto) servers", disabled: Binding.constant(false)) {
|
||||
server = serverToEdit
|
||||
dismiss()
|
||||
})
|
||||
@@ -117,6 +117,7 @@ struct ProtocolServerView: View {
|
||||
|
||||
struct BackButton: ViewModifier {
|
||||
var label: LocalizedStringKey = "Back"
|
||||
@Binding var disabled: Bool
|
||||
var action: () -> Void
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
@@ -130,6 +131,7 @@ struct BackButton: ViewModifier {
|
||||
Text(label)
|
||||
}
|
||||
}
|
||||
.disabled(disabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ struct ProtocolServersView: View {
|
||||
.sheet(isPresented: $showScanProtoServer) {
|
||||
ScanProtocolServer(servers: $servers)
|
||||
}
|
||||
.modifier(BackButton {
|
||||
.modifier(BackButton(disabled: Binding.constant(false)) {
|
||||
if saveDisabled {
|
||||
dismiss()
|
||||
justOpened = false
|
||||
|
||||
@@ -27,7 +27,7 @@ let DEFAULT_NOTIFICATION_ALERT_SHOWN = "notificationAlertShown"
|
||||
let DEFAULT_WEBRTC_POLICY_RELAY = "webrtcPolicyRelay"
|
||||
let DEFAULT_WEBRTC_ICE_SERVERS = "webrtcICEServers"
|
||||
let DEFAULT_CALL_KIT_CALLS_IN_RECENTS = "callKitCallsInRecents"
|
||||
let DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages"
|
||||
let DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages" // unused. Use GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES instead
|
||||
let DEFAULT_PRIVACY_LINK_PREVIEWS = "privacyLinkPreviews"
|
||||
let DEFAULT_PRIVACY_SIMPLEX_LINK_MODE = "privacySimplexLinkMode"
|
||||
let DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS = "privacyShowChatPreviews"
|
||||
@@ -51,6 +51,8 @@ let DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE = "showHiddenProfilesNotice"
|
||||
let DEFAULT_SHOW_MUTE_PROFILE_ALERT = "showMuteProfileAlert"
|
||||
let DEFAULT_WHATS_NEW_VERSION = "defaultWhatsNewVersion"
|
||||
let DEFAULT_ONBOARDING_STAGE = "onboardingStage"
|
||||
let DEFAULT_MIGRATION_TO_STAGE = "migrationToStage"
|
||||
let DEFAULT_MIGRATION_FROM_STAGE = "migrationFromStage"
|
||||
let DEFAULT_CUSTOM_DISAPPEARING_MESSAGE_TIME = "customDisappearingMessageTime"
|
||||
let DEFAULT_SHOW_UNREAD_AND_FAVORITES = "showUnreadAndFavorites"
|
||||
let DEFAULT_DEVICE_NAME_FOR_REMOTE_ACCESS = "deviceNameForRemoteAccess"
|
||||
@@ -58,6 +60,8 @@ let DEFAULT_CONFIRM_REMOTE_SESSIONS = "confirmRemoteSessions"
|
||||
let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST = "connectRemoteViaMulticast"
|
||||
let DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO = "connectRemoteViaMulticastAuto"
|
||||
|
||||
let ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN = "androidCallOnLockScreen"
|
||||
|
||||
let appDefaults: [String: Any] = [
|
||||
DEFAULT_SHOW_LA_NOTICE: false,
|
||||
DEFAULT_LA_NOTICE_SHOWN: false,
|
||||
@@ -93,6 +97,7 @@ let appDefaults: [String: Any] = [
|
||||
DEFAULT_CONFIRM_REMOTE_SESSIONS: false,
|
||||
DEFAULT_CONNECT_REMOTE_VIA_MULTICAST: true,
|
||||
DEFAULT_CONNECT_REMOTE_VIA_MULTICAST_AUTO: true,
|
||||
ANDROID_DEFAULT_CALL_ON_LOCK_SCREEN: AppSettingsLockScreenCalls.show.rawValue
|
||||
]
|
||||
|
||||
// not used anymore
|
||||
@@ -148,10 +153,14 @@ struct SettingsView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
@EnvironmentObject var sceneDelegate: SceneDelegate
|
||||
@Binding var showSettings: Bool
|
||||
@State private var showProgress: Bool = false
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
settingsView()
|
||||
if showProgress {
|
||||
progressView()
|
||||
}
|
||||
if let la = chatModel.laRequest {
|
||||
LocalAuthView(authRequest: la)
|
||||
}
|
||||
@@ -202,9 +211,17 @@ struct SettingsView: View {
|
||||
} label: {
|
||||
settingsRow("desktopcomputer") { Text("Use from desktop") }
|
||||
}
|
||||
|
||||
NavigationLink {
|
||||
MigrateFromDevice(showSettings: $showSettings, showProgressOnSettings: $showProgress)
|
||||
.navigationTitle("Migrate device")
|
||||
.navigationBarTitleDisplayMode(.large)
|
||||
} label: {
|
||||
settingsRow("tray.and.arrow.up") { Text("Migrate to another device") }
|
||||
}
|
||||
}
|
||||
.disabled(chatModel.chatRunning != true)
|
||||
|
||||
|
||||
Section("Settings") {
|
||||
NavigationLink {
|
||||
NotificationsView()
|
||||
@@ -349,6 +366,13 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func progressView() -> some View {
|
||||
VStack {
|
||||
ProgressView().scaleEffect(2)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity )
|
||||
}
|
||||
|
||||
private enum NotificationAlert {
|
||||
case enable
|
||||
case error(LocalizedStringKey, String)
|
||||
|
||||
@@ -47,7 +47,7 @@ struct UserAddressView: View {
|
||||
userAddressScrollView()
|
||||
} else {
|
||||
userAddressScrollView()
|
||||
.modifier(BackButton {
|
||||
.modifier(BackButton(disabled: Binding.constant(false)) {
|
||||
if savedAAS == aas {
|
||||
dismiss()
|
||||
} else {
|
||||
|
||||
@@ -276,6 +276,7 @@ struct UserProfilesView: View {
|
||||
// Deleting the last visible user while having hidden one(s)
|
||||
try await deleteUser()
|
||||
try await changeActiveUserAsync_(nil, viewPwd: nil)
|
||||
try? await stopChatAsync()
|
||||
await MainActor.run {
|
||||
onboardingStageDefault.set(.step1_SimpleXInfo)
|
||||
m.onboardingStage = .step1_SimpleXInfo
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -107,6 +107,10 @@
|
||||
<target>%@ připojen</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ downloaded" xml:space="preserve">
|
||||
<source>%@ downloaded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve">
|
||||
<source>%@ is connected!</source>
|
||||
<target>%@ je připojen!</target>
|
||||
@@ -127,6 +131,10 @@
|
||||
<target>%@ servery</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ uploaded" xml:space="preserve">
|
||||
<source>%@ uploaded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve">
|
||||
<source>%@ wants to connect!</source>
|
||||
<target>%@ se chce připojit!</target>
|
||||
@@ -332,6 +340,10 @@
|
||||
<target>**Nejsoukromější**: nepoužívejte server oznámení SimpleX Chat, pravidelně kontrolujte zprávy na pozadí (závisí na tom, jak často aplikaci používáte).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
|
||||
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
|
||||
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
|
||||
<target>**Upozornění**: Pokud heslo ztratíte, NEBUDETE jej moci obnovit ani změnit.</target>
|
||||
@@ -347,6 +359,10 @@
|
||||
<target>**Upozornění**: Okamžitě doručovaná oznámení vyžadují přístupové heslo uložené v Klíčence.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
|
||||
<source>**Warning**: the archive will be removed.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
|
||||
<source>**e2e encrypted** audio call</source>
|
||||
<target>**e2e šifrovaný** audio hovor</target>
|
||||
@@ -598,6 +614,10 @@
|
||||
<target>Změna adresy bude přerušena. Budou použity staré přijímací adresy.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can block a member for all." xml:space="preserve">
|
||||
<source>Admins can block a member for all.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
|
||||
<source>Admins can create the links to join groups.</source>
|
||||
<target>Správci mohou vytvářet odkazy pro připojení ke skupinám.</target>
|
||||
@@ -651,6 +671,10 @@
|
||||
<target>Všechny vaše kontakty zůstanou připojeny. Aktualizace profilu bude odeslána vašim kontaktům.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
|
||||
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow" xml:space="preserve">
|
||||
<source>Allow</source>
|
||||
<target>Povolit</target>
|
||||
@@ -696,6 +720,10 @@
|
||||
<target>Povolit nevratné smazání odeslaných zpráv. (24 hodin)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
|
||||
<source>Allow to send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send files and media." xml:space="preserve">
|
||||
<source>Allow to send files and media.</source>
|
||||
<target>Povolit odesílání souborů a médii.</target>
|
||||
@@ -774,6 +802,10 @@
|
||||
<target>Sestavení aplikace: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App data migration" xml:space="preserve">
|
||||
<source>App data migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
|
||||
<source>App encrypts new local files (except videos).</source>
|
||||
<target>Aplikace šifruje nové místní soubory (s výjimkou videí).</target>
|
||||
@@ -809,6 +841,18 @@
|
||||
<target>Vzhled</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Apply" xml:space="preserve">
|
||||
<source>Apply</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archive and upload" xml:space="preserve">
|
||||
<source>Archive and upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archiving database" xml:space="preserve">
|
||||
<source>Archiving database</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<source>Attach</source>
|
||||
<target>Připojit</target>
|
||||
@@ -989,6 +1033,10 @@
|
||||
<target>Zrušit</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cancel migration" xml:space="preserve">
|
||||
<source>Cancel migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
|
||||
<source>Cannot access keychain to save database password</source>
|
||||
<target>Nelze získat přístup ke klíčence pro uložení hesla databáze</target>
|
||||
@@ -999,6 +1047,10 @@
|
||||
<target>Nelze přijmout soubor</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cellular" xml:space="preserve">
|
||||
<source>Cellular</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Change" xml:space="preserve">
|
||||
<source>Change</source>
|
||||
<target>Změnit</target>
|
||||
@@ -1089,6 +1141,10 @@
|
||||
<source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat migrated!" xml:space="preserve">
|
||||
<source>Chat migrated!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat preferences" xml:space="preserve">
|
||||
<source>Chat preferences</source>
|
||||
<target>Předvolby chatu</target>
|
||||
@@ -1109,6 +1165,10 @@
|
||||
<target>Čínské a Španělské rozhranní</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
|
||||
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose file" xml:space="preserve">
|
||||
<source>Choose file</source>
|
||||
<target>Vybrat soubor</target>
|
||||
@@ -1178,6 +1238,10 @@
|
||||
<target>Potvrdit aktualizaci databáze</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm network settings" xml:space="preserve">
|
||||
<source>Confirm network settings</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm new passphrase…" xml:space="preserve">
|
||||
<source>Confirm new passphrase…</source>
|
||||
<target>Potvrdit novou heslovou frázi…</target>
|
||||
@@ -1188,6 +1252,14 @@
|
||||
<target>Potvrdit heslo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
|
||||
<source>Confirm that you remember database passphrase to migrate it.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm upload" xml:space="preserve">
|
||||
<source>Confirm upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Connect" xml:space="preserve">
|
||||
<source>Connect</source>
|
||||
<target>Připojit</target>
|
||||
@@ -1428,6 +1500,10 @@ This is your own one-time link!</source>
|
||||
<target>Vytvořeno na %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating archive link" xml:space="preserve">
|
||||
<source>Creating archive link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating link…" xml:space="preserve">
|
||||
<source>Creating link…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -1643,6 +1719,10 @@ This cannot be undone!</source>
|
||||
<target>Odstranění databáze</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete database from this device" xml:space="preserve">
|
||||
<source>Delete database from this device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete file" xml:space="preserve">
|
||||
<source>Delete file</source>
|
||||
<target>Smazat soubor</target>
|
||||
@@ -1927,11 +2007,27 @@ This cannot be undone!</source>
|
||||
<target>Snížit a otevřít chat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download" xml:space="preserve">
|
||||
<source>Download</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download failed" xml:space="preserve">
|
||||
<source>Download failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download file" xml:space="preserve">
|
||||
<source>Download file</source>
|
||||
<target>Stáhnout soubor</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading archive" xml:space="preserve">
|
||||
<source>Downloading archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading link details" xml:space="preserve">
|
||||
<source>Downloading link details</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duplicate display name!" xml:space="preserve">
|
||||
<source>Duplicate display name!</source>
|
||||
<target>Duplicitní zobrazované jméno!</target>
|
||||
@@ -1986,6 +2082,10 @@ This cannot be undone!</source>
|
||||
<target>Povolit pro všechny</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
|
||||
<source>Enable in direct chats (BETA)!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable instant notifications?" xml:space="preserve">
|
||||
<source>Enable instant notifications?</source>
|
||||
<target>Povolit okamžitá oznámení?</target>
|
||||
@@ -2016,6 +2116,10 @@ This cannot be undone!</source>
|
||||
<target>Povolit sebedestrukční heslo</target>
|
||||
<note>set passcode view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled for" xml:space="preserve">
|
||||
<source>Enabled for</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt" xml:space="preserve">
|
||||
<source>Encrypt</source>
|
||||
<target>Šifrovat</target>
|
||||
@@ -2097,6 +2201,10 @@ This cannot be undone!</source>
|
||||
<source>Enter group name…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase" xml:space="preserve">
|
||||
<source>Enter passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve">
|
||||
<source>Enter passphrase…</source>
|
||||
<target>Zadejte přístupovou frázi…</target>
|
||||
@@ -2155,6 +2263,10 @@ This cannot be undone!</source>
|
||||
<target>Chyba přidávání člena(ů)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error allowing contact PQ encryption" xml:space="preserve">
|
||||
<source>Error allowing contact PQ encryption</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing address" xml:space="preserve">
|
||||
<source>Error changing address</source>
|
||||
<target>Chuba změny adresy</target>
|
||||
@@ -2244,6 +2356,10 @@ This cannot be undone!</source>
|
||||
<target>Chyba mazání uživatelského profilu</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error downloading the archive" xml:space="preserve">
|
||||
<source>Error downloading the archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
|
||||
<source>Error enabling delivery receipts!</source>
|
||||
<target>Chyba povolení potvrzení o doručení!</target>
|
||||
@@ -2318,6 +2434,10 @@ This cannot be undone!</source>
|
||||
<target>Při ukládání přístupové fráze do klíčenky došlo k chybě</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving settings" xml:space="preserve">
|
||||
<source>Error saving settings</source>
|
||||
<note>when migrating</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving user password" xml:space="preserve">
|
||||
<source>Error saving user password</source>
|
||||
<target>Chyba ukládání hesla uživatele</target>
|
||||
@@ -2387,6 +2507,14 @@ This cannot be undone!</source>
|
||||
<target>Chyba aktualizace soukromí uživatele</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error uploading the archive" xml:space="preserve">
|
||||
<source>Error uploading the archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
|
||||
<source>Error verifying passphrase:</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error: " xml:space="preserve">
|
||||
<source>Error: </source>
|
||||
<target>Chyba: </target>
|
||||
@@ -2436,6 +2564,10 @@ This cannot be undone!</source>
|
||||
<target>Exportovaný archiv databáze.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
|
||||
<source>Exported file doesn't exist</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exporting database archive…" xml:space="preserve">
|
||||
<source>Exporting database archive…</source>
|
||||
<target>Exportuji archiv databáze…</target>
|
||||
@@ -2495,6 +2627,10 @@ This cannot be undone!</source>
|
||||
<target>Soubory a média jsou zakázány v této skupině.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media not allowed" xml:space="preserve">
|
||||
<source>Files and media not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media prohibited!" xml:space="preserve">
|
||||
<source>Files and media prohibited!</source>
|
||||
<target>Soubory a média jsou zakázány!</target>
|
||||
@@ -2505,6 +2641,14 @@ This cannot be undone!</source>
|
||||
<target>Filtrovat nepřečtené a oblíbené chaty.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration" xml:space="preserve">
|
||||
<source>Finalize migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration on another device." xml:space="preserve">
|
||||
<source>Finalize migration on another device.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
|
||||
<source>Finally, we have them! 🚀</source>
|
||||
<target>Konečně je máme! 🚀</target>
|
||||
@@ -2550,6 +2694,18 @@ This cannot be undone!</source>
|
||||
<target>Pro konzoli</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forward" xml:space="preserve">
|
||||
<source>Forward</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded" xml:space="preserve">
|
||||
<source>Forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded from" xml:space="preserve">
|
||||
<source>Forwarded from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Found desktop" xml:space="preserve">
|
||||
<source>Found desktop</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2656,6 +2812,10 @@ This cannot be undone!</source>
|
||||
<target>Členové skupiny mohou nevratně mazat odeslané zprávy. (24 hodin)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
|
||||
<source>Group members can send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send direct messages." xml:space="preserve">
|
||||
<source>Group members can send direct messages.</source>
|
||||
<target>Členové skupiny mohou posílat přímé zprávy.</target>
|
||||
@@ -2790,6 +2950,10 @@ This cannot be undone!</source>
|
||||
<target>Jak používat servery</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Hungarian interface" xml:space="preserve">
|
||||
<source>Hungarian interface</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
|
||||
<source>ICE servers (one per line)</source>
|
||||
<target>Servery ICE (jeden na řádek)</target>
|
||||
@@ -2855,6 +3019,14 @@ This cannot be undone!</source>
|
||||
<target>Import databáze</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import failed" xml:space="preserve">
|
||||
<source>Import failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Importing archive" xml:space="preserve">
|
||||
<source>Importing archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved message delivery" xml:space="preserve">
|
||||
<source>Improved message delivery</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2869,6 +3041,10 @@ This cannot be undone!</source>
|
||||
<target>Vylepšená konfigurace serveru</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
|
||||
<source>In order to continue, chat should be stopped.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In reply to" xml:space="preserve">
|
||||
<source>In reply to</source>
|
||||
<target>V odpovědi na</target>
|
||||
@@ -2976,6 +3152,10 @@ This cannot be undone!</source>
|
||||
<source>Invalid link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
|
||||
<source>Invalid migration confirmation</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid name!" xml:space="preserve">
|
||||
<source>Invalid name!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -3331,6 +3511,10 @@ This is your link for group %@!</source>
|
||||
<target>Text zprávy</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Message too large" xml:space="preserve">
|
||||
<source>Message too large</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages" xml:space="preserve">
|
||||
<source>Messages</source>
|
||||
<target>Zprávy</target>
|
||||
@@ -3345,11 +3529,47 @@ This is your link for group %@!</source>
|
||||
<source>Messages from %@ will be shown!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate device" xml:space="preserve">
|
||||
<source>Migrate device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate from another device" xml:space="preserve">
|
||||
<source>Migrate from another device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate here" xml:space="preserve">
|
||||
<source>Migrate here</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device" xml:space="preserve">
|
||||
<source>Migrate to another device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
|
||||
<source>Migrate to another device via QR code.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating" xml:space="preserve">
|
||||
<source>Migrating</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating database archive…" xml:space="preserve">
|
||||
<source>Migrating database archive…</source>
|
||||
<target>Přenášení archivu databáze…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration complete" xml:space="preserve">
|
||||
<source>Migration complete</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration error:" xml:space="preserve">
|
||||
<source>Migration error:</source>
|
||||
<target>Chyba přenášení:</target>
|
||||
@@ -3425,6 +3645,10 @@ This is your link for group %@!</source>
|
||||
<target>Síť a servery</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network connection" xml:space="preserve">
|
||||
<source>Network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network settings" xml:space="preserve">
|
||||
<source>Network settings</source>
|
||||
<target>Nastavení sítě</target>
|
||||
@@ -3534,6 +3758,10 @@ This is your link for group %@!</source>
|
||||
<target>Žádná historie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No network connection" xml:space="preserve">
|
||||
<source>No network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No permission to record voice message" xml:space="preserve">
|
||||
<source>No permission to record voice message</source>
|
||||
<target>Nemáte oprávnění nahrávat hlasové zprávy</target>
|
||||
@@ -3705,6 +3933,10 @@ This is your link for group %@!</source>
|
||||
<source>Open group</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open migration to another device" xml:space="preserve">
|
||||
<source>Open migration to another device</source>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open user profiles" xml:space="preserve">
|
||||
<source>Open user profiles</source>
|
||||
<target>Otevřít uživatelské profily</target>
|
||||
@@ -3719,14 +3951,26 @@ This is your link for group %@!</source>
|
||||
<source>Opening app…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or paste archive link" xml:space="preserve">
|
||||
<source>Or paste archive link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or scan QR code" xml:space="preserve">
|
||||
<source>Or scan QR code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or securely share this file link" xml:space="preserve">
|
||||
<source>Or securely share this file link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or show this code" xml:space="preserve">
|
||||
<source>Or show this code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Other" xml:space="preserve">
|
||||
<source>Other</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PING count" xml:space="preserve">
|
||||
<source>PING count</source>
|
||||
<target>Počet PING</target>
|
||||
@@ -3803,6 +4047,10 @@ This is your link for group %@!</source>
|
||||
<target>Chyba dešifrování</target>
|
||||
<note>message decrypt error item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
|
||||
<source>Picture-in-picture calls</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
|
||||
<source>Please ask your contact to enable sending voice messages.</source>
|
||||
<target>Prosím, požádejte kontaktní osobu, aby umožnila odesílání hlasových zpráv.</target>
|
||||
@@ -3823,6 +4071,10 @@ This is your link for group %@!</source>
|
||||
<target>Zkontrolujte prosím nastavení své i svého kontaktu.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
|
||||
<source>Please confirm that network settings are correct for this device.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please contact developers. Error: %@" xml:space="preserve">
|
||||
<source>Please contact developers.
|
||||
Error: %@</source>
|
||||
@@ -3878,6 +4130,10 @@ Error: %@</source>
|
||||
<target>Je možné, že otisk certifikátu v adrese serveru je nesprávný</target>
|
||||
<note>server test error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Post-quantum E2EE" xml:space="preserve">
|
||||
<source>Post-quantum E2EE</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
|
||||
<source>Preserve the last message draft, with attachments.</source>
|
||||
<target>Zachování posledního návrhu zprávy s přílohami.</target>
|
||||
@@ -3965,6 +4221,10 @@ Error: %@</source>
|
||||
<target>Zakázat reakce na zprávy.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
|
||||
<source>Prohibit sending SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
|
||||
<source>Prohibit sending direct messages to members.</source>
|
||||
<target>Zakázat odesílání přímých zpráv členům.</target>
|
||||
@@ -4010,6 +4270,14 @@ Error: %@</source>
|
||||
<target>Nabízená oznámení</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Push server" xml:space="preserve">
|
||||
<source>Push server</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
|
||||
<source>Quantum resistant encryption</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Rate the app" xml:space="preserve">
|
||||
<source>Rate the app</source>
|
||||
<target>Ohodnoťte aplikaci</target>
|
||||
@@ -4084,6 +4352,10 @@ Error: %@</source>
|
||||
<target>Přijímací adresa bude změněna na jiný server. Změna adresy bude dokončena po připojení odesílatele.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving concurrency" xml:space="preserve">
|
||||
<source>Receiving concurrency</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
|
||||
<source>Receiving file will be stopped.</source>
|
||||
<target>Příjem souboru bude zastaven.</target>
|
||||
@@ -4098,6 +4370,10 @@ Error: %@</source>
|
||||
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
|
||||
<source>Recipient(s) can't see who this message is from.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipients see updates as you type them." xml:space="preserve">
|
||||
<source>Recipients see updates as you type them.</source>
|
||||
<target>Příjemci uvidí aktualizace během jejich psaní.</target>
|
||||
@@ -4192,10 +4468,22 @@ Error: %@</source>
|
||||
<source>Repeat connection request?</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat download" xml:space="preserve">
|
||||
<source>Repeat download</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat import" xml:space="preserve">
|
||||
<source>Repeat import</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat join request?" xml:space="preserve">
|
||||
<source>Repeat join request?</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat upload" xml:space="preserve">
|
||||
<source>Repeat upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply" xml:space="preserve">
|
||||
<source>Reply</source>
|
||||
<target>Odpověď</target>
|
||||
@@ -4295,6 +4583,10 @@ Error: %@</source>
|
||||
<target>SMP servery</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Safer groups" xml:space="preserve">
|
||||
<source>Safer groups</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Save" xml:space="preserve">
|
||||
<source>Save</source>
|
||||
<target>Uložit</target>
|
||||
@@ -4375,11 +4667,19 @@ Error: %@</source>
|
||||
<target>Uložit uvítací zprávu?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved" xml:space="preserve">
|
||||
<source>Saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
|
||||
<source>Saved WebRTC ICE servers will be removed</source>
|
||||
<target>Uložené servery WebRTC ICE budou odstraněny</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved from" xml:space="preserve">
|
||||
<source>Saved from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved message" xml:space="preserve">
|
||||
<source>Saved message</source>
|
||||
<note>message info title</note>
|
||||
@@ -4654,6 +4954,10 @@ Error: %@</source>
|
||||
<target>Nastavit heslo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase" xml:space="preserve">
|
||||
<source>Set passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase to export" xml:space="preserve">
|
||||
<source>Set passphrase to export</source>
|
||||
<target>Nastavení přístupové fráze pro export</target>
|
||||
@@ -4708,6 +5012,10 @@ Error: %@</source>
|
||||
<target>Sdílet s kontakty</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
<source>Show QR code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show calls in phone history" xml:space="preserve">
|
||||
<source>Show calls in phone history</source>
|
||||
<target>Ukaž hovory v historii telefonu</target>
|
||||
@@ -4786,6 +5094,14 @@ Error: %@</source>
|
||||
<trans-unit id="SimpleX links" xml:space="preserve">
|
||||
<source>SimpleX links</source>
|
||||
<target>Odkazy na SimpleX</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
|
||||
<source>SimpleX links are prohibited in this group.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
|
||||
<source>SimpleX links not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX one-time invitation" xml:space="preserve">
|
||||
@@ -4847,6 +5163,10 @@ Error: %@</source>
|
||||
<target>Zastavit SimpleX</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat" xml:space="preserve">
|
||||
<source>Stop chat</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat to enable database actions" xml:space="preserve">
|
||||
<source>Stop chat to enable database actions</source>
|
||||
<target>Zastavte chat pro povolení akcí databáze</target>
|
||||
@@ -4887,6 +5207,10 @@ Error: %@</source>
|
||||
<target>Přestat sdílet adresu?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stopping chat" xml:space="preserve">
|
||||
<source>Stopping chat</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Submit" xml:space="preserve">
|
||||
<source>Submit</source>
|
||||
<target>Odeslat</target>
|
||||
@@ -5129,6 +5453,14 @@ Může se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitován
|
||||
<target>Tuto akci nelze vzít zpět - váš profil, kontakty, zprávy a soubory budou nenávratně ztraceny.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by end-to-end encryption.</source>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This device name" xml:space="preserve">
|
||||
<source>This device name</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -5409,11 +5741,19 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<target>Zvýšit a otevřít chat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload failed" xml:space="preserve">
|
||||
<source>Upload failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload file" xml:space="preserve">
|
||||
<source>Upload file</source>
|
||||
<target>Nahrát soubor</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uploading archive" xml:space="preserve">
|
||||
<source>Uploading archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use .onion hosts" xml:space="preserve">
|
||||
<source>Use .onion hosts</source>
|
||||
<target>Použít hostitele .onion</target>
|
||||
@@ -5462,6 +5802,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<target>Použít server</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
<source>Use the app while in the call.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="User profile" xml:space="preserve">
|
||||
<source>User profile</source>
|
||||
<target>Profil uživatele</target>
|
||||
@@ -5494,6 +5838,14 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<source>Verify connections</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify database passphrase" xml:space="preserve">
|
||||
<source>Verify database passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify passphrase" xml:space="preserve">
|
||||
<source>Verify passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify security code" xml:space="preserve">
|
||||
<source>Verify security code</source>
|
||||
<target>Ověření bezpečnostního kódu</target>
|
||||
@@ -5552,6 +5904,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<target>Hlasové zprávy jsou v této skupině zakázány.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages not allowed" xml:space="preserve">
|
||||
<source>Voice messages not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages prohibited!" xml:space="preserve">
|
||||
<source>Voice messages prohibited!</source>
|
||||
<target>Hlasové zprávy jsou zakázány!</target>
|
||||
@@ -5581,6 +5937,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<target>Čekám na video</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
|
||||
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: you may lose some data!" xml:space="preserve">
|
||||
<source>Warning: you may lose some data!</source>
|
||||
<target>Upozornění: můžete ztratit nějaká data!</target>
|
||||
@@ -5601,6 +5961,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<target>Uvítací zpráva</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Welcome message is too long" xml:space="preserve">
|
||||
<source>Welcome message is too long</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="What's new" xml:space="preserve">
|
||||
<source>What's new</source>
|
||||
<target>Co je nového</target>
|
||||
@@ -5621,6 +5985,14 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<target>Pokud s někým sdílíte inkognito profil, bude tento profil použit pro skupiny, do kterých vás pozve.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WiFi" xml:space="preserve">
|
||||
<source>WiFi</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wired ethernet" xml:space="preserve">
|
||||
<source>Wired ethernet</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="With encrypted files and media." xml:space="preserve">
|
||||
<source>With encrypted files and media.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -5654,6 +6026,10 @@ Chcete-li se připojit, požádejte svůj kontakt o vytvoření dalšího odkazu
|
||||
<target>Vy</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
|
||||
<source>You **must not** use the same database on two devices.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You accepted connection" xml:space="preserve">
|
||||
<source>You accepted connection</source>
|
||||
<target>Přijali jste spojení</target>
|
||||
@@ -5733,6 +6109,10 @@ Repeat join request?</source>
|
||||
<target>Můžete je povolit později v nastavení Soukromí & Bezpečnosti aplikace</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can give another try." xml:space="preserve">
|
||||
<source>You can give another try.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
|
||||
<source>You can hide or mute a user profile - swipe it to the right.</source>
|
||||
<target>Profil uživatele můžete skrýt nebo ztlumit - přejeďte prstem doprava.</target>
|
||||
@@ -6076,6 +6456,10 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
<target>správce</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="admins" xml:space="preserve">
|
||||
<source>admins</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="agreeing encryption for %@…" xml:space="preserve">
|
||||
<source>agreeing encryption for %@…</source>
|
||||
<target>povoluji šifrování pro %@…</target>
|
||||
@@ -6086,6 +6470,10 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
<target>povoluji šifrování…</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="all members" xml:space="preserve">
|
||||
<source>all members</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="always" xml:space="preserve">
|
||||
<source>always</source>
|
||||
<target>vždy</target>
|
||||
@@ -6116,7 +6504,7 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked" xml:space="preserve">
|
||||
<source>blocked</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked %@" xml:space="preserve">
|
||||
<source>blocked %@</source>
|
||||
@@ -6124,7 +6512,7 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked by admin" xml:space="preserve">
|
||||
<source>blocked by admin</source>
|
||||
<note>blocked chat item</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bold" xml:space="preserve">
|
||||
<source>bold</source>
|
||||
@@ -6408,6 +6796,10 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
<source>event happened</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="forwarded" xml:space="preserve">
|
||||
<source>forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="group deleted" xml:space="preserve">
|
||||
<source>group deleted</source>
|
||||
<target>skupina smazána</target>
|
||||
@@ -6550,7 +6942,7 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
<trans-unit id="moderated by %@" xml:space="preserve">
|
||||
<source>moderated by %@</source>
|
||||
<target>moderovaný %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="months" xml:space="preserve">
|
||||
<source>months</source>
|
||||
@@ -6614,11 +7006,19 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
<target>vlastník</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="owners" xml:space="preserve">
|
||||
<source>owners</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="peer-to-peer" xml:space="preserve">
|
||||
<source>peer-to-peer</source>
|
||||
<target>peer-to-peer</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
|
||||
<source>quantum resistant e2e encryption</source>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="received answer…" xml:space="preserve">
|
||||
<source>received answer…</source>
|
||||
<target>obdržel odpověď…</target>
|
||||
@@ -6657,6 +7057,14 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
<target>odstranil vás</target>
|
||||
<note>rcv group event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved" xml:space="preserve">
|
||||
<source>saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved from %@" xml:space="preserve">
|
||||
<source>saved from %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sec" xml:space="preserve">
|
||||
<source>sec</source>
|
||||
<target>sek</target>
|
||||
@@ -6690,6 +7098,10 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
<source>set new profile picture</source>
|
||||
<note>profile update event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
|
||||
<source>standard end-to-end encryption</source>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="starting…" xml:space="preserve">
|
||||
<source>starting…</source>
|
||||
<target>začíná…</target>
|
||||
@@ -6786,6 +7198,10 @@ Servery SimpleX nevidí váš profil.</target>
|
||||
<target>ano</target>
|
||||
<note>pref value</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you" xml:space="preserve">
|
||||
<source>you</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you are invited to group" xml:space="preserve">
|
||||
<source>you are invited to group</source>
|
||||
<target>jste pozváni do skupiny</target>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -105,6 +105,10 @@
|
||||
<source>%@ connected</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ downloaded" xml:space="preserve">
|
||||
<source>%@ downloaded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve">
|
||||
<source>%@ is connected!</source>
|
||||
<target>%@ on yhdistetty!</target>
|
||||
@@ -125,6 +129,10 @@
|
||||
<target>%@ palvelimet</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ uploaded" xml:space="preserve">
|
||||
<source>%@ uploaded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve">
|
||||
<source>%@ wants to connect!</source>
|
||||
<target>%@ haluaa muodostaa yhteyden!</target>
|
||||
@@ -330,6 +338,10 @@
|
||||
<target>**Yksityisin**: älä käytä SimpleX Chat -ilmoituspalvelinta, tarkista viestit ajoittain taustalla (riippuu siitä, kuinka usein käytät sovellusta).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
|
||||
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
|
||||
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
|
||||
<target>**Huomaa**: et voi palauttaa tai muuttaa tunnuslausetta, jos kadotat sen.</target>
|
||||
@@ -345,6 +357,10 @@
|
||||
<target>**Varoitus**: Välittömät push-ilmoitukset vaativat tunnuslauseen, joka on tallennettu Keychainiin.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
|
||||
<source>**Warning**: the archive will be removed.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
|
||||
<source>**e2e encrypted** audio call</source>
|
||||
<target>**e2e-salattu** äänipuhelu</target>
|
||||
@@ -593,6 +609,10 @@
|
||||
<target>Osoitteenmuutos keskeytetään. Käytetään vanhaa vastaanotto-osoitetta.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can block a member for all." xml:space="preserve">
|
||||
<source>Admins can block a member for all.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
|
||||
<source>Admins can create the links to join groups.</source>
|
||||
<target>Ylläpitäjät voivat luoda linkkejä ryhmiin liittymiseen.</target>
|
||||
@@ -646,6 +666,10 @@
|
||||
<target>Kaikki kontaktisi pysyvät yhteydessä. Profiilipäivitys lähetetään kontakteillesi.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
|
||||
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow" xml:space="preserve">
|
||||
<source>Allow</source>
|
||||
<target>Salli</target>
|
||||
@@ -691,6 +715,10 @@
|
||||
<target>Salli lähetettyjen viestien peruuttamaton poistaminen. (24 tuntia)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
|
||||
<source>Allow to send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send files and media." xml:space="preserve">
|
||||
<source>Allow to send files and media.</source>
|
||||
<target>Salli tiedostojen ja median lähettäminen.</target>
|
||||
@@ -769,6 +797,10 @@
|
||||
<target>Sovellusversio: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App data migration" xml:space="preserve">
|
||||
<source>App data migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
|
||||
<source>App encrypts new local files (except videos).</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -803,6 +835,18 @@
|
||||
<target>Ulkonäkö</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Apply" xml:space="preserve">
|
||||
<source>Apply</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archive and upload" xml:space="preserve">
|
||||
<source>Archive and upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archiving database" xml:space="preserve">
|
||||
<source>Archiving database</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<source>Attach</source>
|
||||
<target>Liitä</target>
|
||||
@@ -982,6 +1026,10 @@
|
||||
<target>Peruuta</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cancel migration" xml:space="preserve">
|
||||
<source>Cancel migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
|
||||
<source>Cannot access keychain to save database password</source>
|
||||
<target>Ei pääsyä avainnippuun tietokannan salasanan tallentamiseksi</target>
|
||||
@@ -992,6 +1040,10 @@
|
||||
<target>Tiedostoa ei voi vastaanottaa</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cellular" xml:space="preserve">
|
||||
<source>Cellular</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Change" xml:space="preserve">
|
||||
<source>Change</source>
|
||||
<target>Muuta</target>
|
||||
@@ -1082,6 +1134,10 @@
|
||||
<source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat migrated!" xml:space="preserve">
|
||||
<source>Chat migrated!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat preferences" xml:space="preserve">
|
||||
<source>Chat preferences</source>
|
||||
<target>Chat-asetukset</target>
|
||||
@@ -1102,6 +1158,10 @@
|
||||
<target>Kiinalainen ja espanjalainen käyttöliittymä</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
|
||||
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose file" xml:space="preserve">
|
||||
<source>Choose file</source>
|
||||
<target>Valitse tiedosto</target>
|
||||
@@ -1171,6 +1231,10 @@
|
||||
<target>Vahvista tietokannan päivitykset</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm network settings" xml:space="preserve">
|
||||
<source>Confirm network settings</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm new passphrase…" xml:space="preserve">
|
||||
<source>Confirm new passphrase…</source>
|
||||
<target>Vahvista uusi tunnuslause…</target>
|
||||
@@ -1181,6 +1245,14 @@
|
||||
<target>Vahvista salasana</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
|
||||
<source>Confirm that you remember database passphrase to migrate it.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm upload" xml:space="preserve">
|
||||
<source>Confirm upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Connect" xml:space="preserve">
|
||||
<source>Connect</source>
|
||||
<target>Yhdistä</target>
|
||||
@@ -1421,6 +1493,10 @@ This is your own one-time link!</source>
|
||||
<target>Luotu %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating archive link" xml:space="preserve">
|
||||
<source>Creating archive link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating link…" xml:space="preserve">
|
||||
<source>Creating link…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -1636,6 +1712,10 @@ This cannot be undone!</source>
|
||||
<target>Poista tietokanta</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete database from this device" xml:space="preserve">
|
||||
<source>Delete database from this device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete file" xml:space="preserve">
|
||||
<source>Delete file</source>
|
||||
<target>Poista tiedosto</target>
|
||||
@@ -1920,11 +2000,27 @@ This cannot be undone!</source>
|
||||
<target>Alenna ja avaa keskustelu</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download" xml:space="preserve">
|
||||
<source>Download</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download failed" xml:space="preserve">
|
||||
<source>Download failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download file" xml:space="preserve">
|
||||
<source>Download file</source>
|
||||
<target>Lataa tiedosto</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading archive" xml:space="preserve">
|
||||
<source>Downloading archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading link details" xml:space="preserve">
|
||||
<source>Downloading link details</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duplicate display name!" xml:space="preserve">
|
||||
<source>Duplicate display name!</source>
|
||||
<target>Päällekkäinen näyttönimi!</target>
|
||||
@@ -1979,6 +2075,10 @@ This cannot be undone!</source>
|
||||
<target>Salli kaikille</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
|
||||
<source>Enable in direct chats (BETA)!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable instant notifications?" xml:space="preserve">
|
||||
<source>Enable instant notifications?</source>
|
||||
<target>Salli välittömät ilmoitukset?</target>
|
||||
@@ -2009,6 +2109,10 @@ This cannot be undone!</source>
|
||||
<target>Ota itsetuhoava pääsykoodi käyttöön</target>
|
||||
<note>set passcode view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled for" xml:space="preserve">
|
||||
<source>Enabled for</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt" xml:space="preserve">
|
||||
<source>Encrypt</source>
|
||||
<target>Salaa</target>
|
||||
@@ -2089,6 +2193,10 @@ This cannot be undone!</source>
|
||||
<source>Enter group name…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase" xml:space="preserve">
|
||||
<source>Enter passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve">
|
||||
<source>Enter passphrase…</source>
|
||||
<target>Syötä tunnuslause…</target>
|
||||
@@ -2147,6 +2255,10 @@ This cannot be undone!</source>
|
||||
<target>Virhe lisättäessä jäseniä</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error allowing contact PQ encryption" xml:space="preserve">
|
||||
<source>Error allowing contact PQ encryption</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing address" xml:space="preserve">
|
||||
<source>Error changing address</source>
|
||||
<target>Virhe osoitteenvaihdossa</target>
|
||||
@@ -2235,6 +2347,10 @@ This cannot be undone!</source>
|
||||
<target>Virhe käyttäjäprofiilin poistamisessa</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error downloading the archive" xml:space="preserve">
|
||||
<source>Error downloading the archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
|
||||
<source>Error enabling delivery receipts!</source>
|
||||
<target>Virhe toimituskuittauksien sallimisessa!</target>
|
||||
@@ -2309,6 +2425,10 @@ This cannot be undone!</source>
|
||||
<target>Virhe tunnuslauseen tallentamisessa avainnippuun</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving settings" xml:space="preserve">
|
||||
<source>Error saving settings</source>
|
||||
<note>when migrating</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving user password" xml:space="preserve">
|
||||
<source>Error saving user password</source>
|
||||
<target>Virhe käyttäjän salasanan tallentamisessa</target>
|
||||
@@ -2377,6 +2497,14 @@ This cannot be undone!</source>
|
||||
<target>Virhe päivitettäessä käyttäjän tietosuojaa</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error uploading the archive" xml:space="preserve">
|
||||
<source>Error uploading the archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
|
||||
<source>Error verifying passphrase:</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error: " xml:space="preserve">
|
||||
<source>Error: </source>
|
||||
<target>Virhe: </target>
|
||||
@@ -2426,6 +2554,10 @@ This cannot be undone!</source>
|
||||
<target>Viety tietokanta-arkisto.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
|
||||
<source>Exported file doesn't exist</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exporting database archive…" xml:space="preserve">
|
||||
<source>Exporting database archive…</source>
|
||||
<target>Tietokanta-arkiston vienti…</target>
|
||||
@@ -2485,6 +2617,10 @@ This cannot be undone!</source>
|
||||
<target>Tiedostot ja media ovat tässä ryhmässä kiellettyjä.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media not allowed" xml:space="preserve">
|
||||
<source>Files and media not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media prohibited!" xml:space="preserve">
|
||||
<source>Files and media prohibited!</source>
|
||||
<target>Tiedostot ja media kielletty!</target>
|
||||
@@ -2495,6 +2631,14 @@ This cannot be undone!</source>
|
||||
<target>Suodata lukemattomia- ja suosikkikeskusteluja.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration" xml:space="preserve">
|
||||
<source>Finalize migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration on another device." xml:space="preserve">
|
||||
<source>Finalize migration on another device.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
|
||||
<source>Finally, we have them! 🚀</source>
|
||||
<target>Vihdoinkin meillä! 🚀</target>
|
||||
@@ -2540,6 +2684,18 @@ This cannot be undone!</source>
|
||||
<target>Konsoliin</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forward" xml:space="preserve">
|
||||
<source>Forward</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded" xml:space="preserve">
|
||||
<source>Forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded from" xml:space="preserve">
|
||||
<source>Forwarded from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Found desktop" xml:space="preserve">
|
||||
<source>Found desktop</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2646,6 +2802,10 @@ This cannot be undone!</source>
|
||||
<target>Ryhmän jäsenet voivat poistaa lähetetyt viestit peruuttamattomasti. (24 tuntia)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
|
||||
<source>Group members can send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send direct messages." xml:space="preserve">
|
||||
<source>Group members can send direct messages.</source>
|
||||
<target>Ryhmän jäsenet voivat lähettää suoraviestejä.</target>
|
||||
@@ -2780,6 +2940,10 @@ This cannot be undone!</source>
|
||||
<target>Miten käytät palvelimiasi</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Hungarian interface" xml:space="preserve">
|
||||
<source>Hungarian interface</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
|
||||
<source>ICE servers (one per line)</source>
|
||||
<target>ICE-palvelimet (yksi per rivi)</target>
|
||||
@@ -2845,6 +3009,14 @@ This cannot be undone!</source>
|
||||
<target>Tuo tietokanta</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import failed" xml:space="preserve">
|
||||
<source>Import failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Importing archive" xml:space="preserve">
|
||||
<source>Importing archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved message delivery" xml:space="preserve">
|
||||
<source>Improved message delivery</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2859,6 +3031,10 @@ This cannot be undone!</source>
|
||||
<target>Parannettu palvelimen kokoonpano</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
|
||||
<source>In order to continue, chat should be stopped.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In reply to" xml:space="preserve">
|
||||
<source>In reply to</source>
|
||||
<target>Vastauksena</target>
|
||||
@@ -2966,6 +3142,10 @@ This cannot be undone!</source>
|
||||
<source>Invalid link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
|
||||
<source>Invalid migration confirmation</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid name!" xml:space="preserve">
|
||||
<source>Invalid name!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -3321,6 +3501,10 @@ This is your link for group %@!</source>
|
||||
<target>Viestin teksti</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Message too large" xml:space="preserve">
|
||||
<source>Message too large</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages" xml:space="preserve">
|
||||
<source>Messages</source>
|
||||
<target>Viestit</target>
|
||||
@@ -3335,11 +3519,47 @@ This is your link for group %@!</source>
|
||||
<source>Messages from %@ will be shown!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate device" xml:space="preserve">
|
||||
<source>Migrate device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate from another device" xml:space="preserve">
|
||||
<source>Migrate from another device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate here" xml:space="preserve">
|
||||
<source>Migrate here</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device" xml:space="preserve">
|
||||
<source>Migrate to another device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
|
||||
<source>Migrate to another device via QR code.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating" xml:space="preserve">
|
||||
<source>Migrating</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating database archive…" xml:space="preserve">
|
||||
<source>Migrating database archive…</source>
|
||||
<target>Siirretään tietokannan arkistoa…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration complete" xml:space="preserve">
|
||||
<source>Migration complete</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration error:" xml:space="preserve">
|
||||
<source>Migration error:</source>
|
||||
<target>Siirtovirhe:</target>
|
||||
@@ -3415,6 +3635,10 @@ This is your link for group %@!</source>
|
||||
<target>Verkko ja palvelimet</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network connection" xml:space="preserve">
|
||||
<source>Network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network settings" xml:space="preserve">
|
||||
<source>Network settings</source>
|
||||
<target>Verkkoasetukset</target>
|
||||
@@ -3523,6 +3747,10 @@ This is your link for group %@!</source>
|
||||
<target>Ei historiaa</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No network connection" xml:space="preserve">
|
||||
<source>No network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No permission to record voice message" xml:space="preserve">
|
||||
<source>No permission to record voice message</source>
|
||||
<target>Ei lupaa ääniviestin tallentamiseen</target>
|
||||
@@ -3693,6 +3921,10 @@ This is your link for group %@!</source>
|
||||
<source>Open group</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open migration to another device" xml:space="preserve">
|
||||
<source>Open migration to another device</source>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open user profiles" xml:space="preserve">
|
||||
<source>Open user profiles</source>
|
||||
<target>Avaa käyttäjäprofiilit</target>
|
||||
@@ -3707,14 +3939,26 @@ This is your link for group %@!</source>
|
||||
<source>Opening app…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or paste archive link" xml:space="preserve">
|
||||
<source>Or paste archive link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or scan QR code" xml:space="preserve">
|
||||
<source>Or scan QR code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or securely share this file link" xml:space="preserve">
|
||||
<source>Or securely share this file link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or show this code" xml:space="preserve">
|
||||
<source>Or show this code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Other" xml:space="preserve">
|
||||
<source>Other</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PING count" xml:space="preserve">
|
||||
<source>PING count</source>
|
||||
<target>PING-määrä</target>
|
||||
@@ -3791,6 +4035,10 @@ This is your link for group %@!</source>
|
||||
<target>Pysyvä salauksen purkuvirhe</target>
|
||||
<note>message decrypt error item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
|
||||
<source>Picture-in-picture calls</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
|
||||
<source>Please ask your contact to enable sending voice messages.</source>
|
||||
<target>Pyydä kontaktiasi sallimaan ääniviestien lähettäminen.</target>
|
||||
@@ -3811,6 +4059,10 @@ This is your link for group %@!</source>
|
||||
<target>Tarkista omasi ja kontaktin asetukset.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
|
||||
<source>Please confirm that network settings are correct for this device.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please contact developers. Error: %@" xml:space="preserve">
|
||||
<source>Please contact developers.
|
||||
Error: %@</source>
|
||||
@@ -3866,6 +4118,10 @@ Error: %@</source>
|
||||
<target>Palvelimen osoitteen varmenteen sormenjälki on mahdollisesti virheellinen</target>
|
||||
<note>server test error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Post-quantum E2EE" xml:space="preserve">
|
||||
<source>Post-quantum E2EE</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
|
||||
<source>Preserve the last message draft, with attachments.</source>
|
||||
<target>Säilytä viimeinen viestiluonnos liitteineen.</target>
|
||||
@@ -3953,6 +4209,10 @@ Error: %@</source>
|
||||
<target>Estä viestireaktiot.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
|
||||
<source>Prohibit sending SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
|
||||
<source>Prohibit sending direct messages to members.</source>
|
||||
<target>Estä suorien viestien lähettäminen jäsenille.</target>
|
||||
@@ -3998,6 +4258,14 @@ Error: %@</source>
|
||||
<target>Push-ilmoitukset</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Push server" xml:space="preserve">
|
||||
<source>Push server</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
|
||||
<source>Quantum resistant encryption</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Rate the app" xml:space="preserve">
|
||||
<source>Rate the app</source>
|
||||
<target>Arvioi sovellus</target>
|
||||
@@ -4072,6 +4340,10 @@ Error: %@</source>
|
||||
<target>Vastaanotto-osoite vaihdetaan toiseen palvelimeen. Osoitteenmuutos tehdään sen jälkeen, kun lähettäjä tulee verkkoon.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving concurrency" xml:space="preserve">
|
||||
<source>Receiving concurrency</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
|
||||
<source>Receiving file will be stopped.</source>
|
||||
<target>Tiedoston vastaanotto pysäytetään.</target>
|
||||
@@ -4086,6 +4358,10 @@ Error: %@</source>
|
||||
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
|
||||
<source>Recipient(s) can't see who this message is from.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipients see updates as you type them." xml:space="preserve">
|
||||
<source>Recipients see updates as you type them.</source>
|
||||
<target>Vastaanottajat näkevät päivitykset, kun kirjoitat niitä.</target>
|
||||
@@ -4180,10 +4456,22 @@ Error: %@</source>
|
||||
<source>Repeat connection request?</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat download" xml:space="preserve">
|
||||
<source>Repeat download</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat import" xml:space="preserve">
|
||||
<source>Repeat import</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat join request?" xml:space="preserve">
|
||||
<source>Repeat join request?</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat upload" xml:space="preserve">
|
||||
<source>Repeat upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply" xml:space="preserve">
|
||||
<source>Reply</source>
|
||||
<target>Vastaa</target>
|
||||
@@ -4283,6 +4571,10 @@ Error: %@</source>
|
||||
<target>SMP-palvelimet</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Safer groups" xml:space="preserve">
|
||||
<source>Safer groups</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Save" xml:space="preserve">
|
||||
<source>Save</source>
|
||||
<target>Tallenna</target>
|
||||
@@ -4363,11 +4655,19 @@ Error: %@</source>
|
||||
<target>Tallenna tervetuloviesti?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved" xml:space="preserve">
|
||||
<source>Saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
|
||||
<source>Saved WebRTC ICE servers will be removed</source>
|
||||
<target>Tallennetut WebRTC ICE -palvelimet poistetaan</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved from" xml:space="preserve">
|
||||
<source>Saved from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved message" xml:space="preserve">
|
||||
<source>Saved message</source>
|
||||
<note>message info title</note>
|
||||
@@ -4641,6 +4941,10 @@ Error: %@</source>
|
||||
<target>Aseta pääsykoodi</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase" xml:space="preserve">
|
||||
<source>Set passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase to export" xml:space="preserve">
|
||||
<source>Set passphrase to export</source>
|
||||
<target>Aseta tunnuslause vientiä varten</target>
|
||||
@@ -4695,6 +4999,10 @@ Error: %@</source>
|
||||
<target>Jaa kontaktien kanssa</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
<source>Show QR code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show calls in phone history" xml:space="preserve">
|
||||
<source>Show calls in phone history</source>
|
||||
<target>Näytä puhelut puhelinhistoriassa</target>
|
||||
@@ -4773,6 +5081,14 @@ Error: %@</source>
|
||||
<trans-unit id="SimpleX links" xml:space="preserve">
|
||||
<source>SimpleX links</source>
|
||||
<target>SimpleX-linkit</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
|
||||
<source>SimpleX links are prohibited in this group.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
|
||||
<source>SimpleX links not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX one-time invitation" xml:space="preserve">
|
||||
@@ -4833,6 +5149,10 @@ Error: %@</source>
|
||||
<target>Lopeta SimpleX</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat" xml:space="preserve">
|
||||
<source>Stop chat</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat to enable database actions" xml:space="preserve">
|
||||
<source>Stop chat to enable database actions</source>
|
||||
<target>Pysäytä keskustelu tietokantatoimien mahdollistamiseksi</target>
|
||||
@@ -4873,6 +5193,10 @@ Error: %@</source>
|
||||
<target>Lopeta osoitteen jakaminen?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stopping chat" xml:space="preserve">
|
||||
<source>Stopping chat</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Submit" xml:space="preserve">
|
||||
<source>Submit</source>
|
||||
<target>Lähetä</target>
|
||||
@@ -5115,6 +5439,14 @@ Tämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut.</t
|
||||
<target>Tätä toimintoa ei voi kumota - profiilisi, kontaktisi, viestisi ja tiedostosi poistuvat peruuttamattomasti.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by end-to-end encryption.</source>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This device name" xml:space="preserve">
|
||||
<source>This device name</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -5394,11 +5726,19 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<target>Päivitä ja avaa keskustelu</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload failed" xml:space="preserve">
|
||||
<source>Upload failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload file" xml:space="preserve">
|
||||
<source>Upload file</source>
|
||||
<target>Lataa tiedosto</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uploading archive" xml:space="preserve">
|
||||
<source>Uploading archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use .onion hosts" xml:space="preserve">
|
||||
<source>Use .onion hosts</source>
|
||||
<target>Käytä .onion-isäntiä</target>
|
||||
@@ -5447,6 +5787,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<target>Käytä palvelinta</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
<source>Use the app while in the call.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="User profile" xml:space="preserve">
|
||||
<source>User profile</source>
|
||||
<target>Käyttäjäprofiili</target>
|
||||
@@ -5479,6 +5823,14 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<source>Verify connections</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify database passphrase" xml:space="preserve">
|
||||
<source>Verify database passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify passphrase" xml:space="preserve">
|
||||
<source>Verify passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify security code" xml:space="preserve">
|
||||
<source>Verify security code</source>
|
||||
<target>Tarkista turvakoodi</target>
|
||||
@@ -5537,6 +5889,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<target>Ääniviestit ovat kiellettyjä tässä ryhmässä.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages not allowed" xml:space="preserve">
|
||||
<source>Voice messages not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages prohibited!" xml:space="preserve">
|
||||
<source>Voice messages prohibited!</source>
|
||||
<target>Ääniviestit kielletty!</target>
|
||||
@@ -5566,6 +5922,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<target>Odottaa videota</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
|
||||
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: you may lose some data!" xml:space="preserve">
|
||||
<source>Warning: you may lose some data!</source>
|
||||
<target>Varoitus: saatat menettää joitain tietoja!</target>
|
||||
@@ -5586,6 +5946,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<target>Tervetuloviesti</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Welcome message is too long" xml:space="preserve">
|
||||
<source>Welcome message is too long</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="What's new" xml:space="preserve">
|
||||
<source>What's new</source>
|
||||
<target>Uusimmat</target>
|
||||
@@ -5606,6 +5970,14 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<target>Kun jaat inkognitoprofiilin jonkun kanssa, tätä profiilia käytetään ryhmissä, joihin tämä sinut kutsuu.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WiFi" xml:space="preserve">
|
||||
<source>WiFi</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wired ethernet" xml:space="preserve">
|
||||
<source>Wired ethernet</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="With encrypted files and media." xml:space="preserve">
|
||||
<source>With encrypted files and media.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -5639,6 +6011,10 @@ Jos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja
|
||||
<target>Sinä</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
|
||||
<source>You **must not** use the same database on two devices.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You accepted connection" xml:space="preserve">
|
||||
<source>You accepted connection</source>
|
||||
<target>Hyväksyit yhteyden</target>
|
||||
@@ -5718,6 +6094,10 @@ Repeat join request?</source>
|
||||
<target>Voit ottaa ne käyttöön myöhemmin sovelluksen Yksityisyys & Turvallisuus -asetuksista.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can give another try." xml:space="preserve">
|
||||
<source>You can give another try.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
|
||||
<source>You can hide or mute a user profile - swipe it to the right.</source>
|
||||
<target>Voit piilottaa tai mykistää käyttäjäprofiilin pyyhkäisemällä sitä oikealle.</target>
|
||||
@@ -6061,6 +6441,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
<target>ylläpitäjä</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="admins" xml:space="preserve">
|
||||
<source>admins</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="agreeing encryption for %@…" xml:space="preserve">
|
||||
<source>agreeing encryption for %@…</source>
|
||||
<target>salauksesta sovitaan %@:lle…</target>
|
||||
@@ -6071,6 +6455,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
<target>hyväksyy salausta…</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="all members" xml:space="preserve">
|
||||
<source>all members</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="always" xml:space="preserve">
|
||||
<source>always</source>
|
||||
<target>aina</target>
|
||||
@@ -6101,7 +6489,7 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked" xml:space="preserve">
|
||||
<source>blocked</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked %@" xml:space="preserve">
|
||||
<source>blocked %@</source>
|
||||
@@ -6109,7 +6497,7 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked by admin" xml:space="preserve">
|
||||
<source>blocked by admin</source>
|
||||
<note>blocked chat item</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bold" xml:space="preserve">
|
||||
<source>bold</source>
|
||||
@@ -6393,6 +6781,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
<target>tapahtuma tapahtui</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="forwarded" xml:space="preserve">
|
||||
<source>forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="group deleted" xml:space="preserve">
|
||||
<source>group deleted</source>
|
||||
<target>ryhmä poistettu</target>
|
||||
@@ -6535,7 +6927,7 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
<trans-unit id="moderated by %@" xml:space="preserve">
|
||||
<source>moderated by %@</source>
|
||||
<target>%@ moderoi</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="months" xml:space="preserve">
|
||||
<source>months</source>
|
||||
@@ -6599,11 +6991,19 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
<target>omistaja</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="owners" xml:space="preserve">
|
||||
<source>owners</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="peer-to-peer" xml:space="preserve">
|
||||
<source>peer-to-peer</source>
|
||||
<target>vertais</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
|
||||
<source>quantum resistant e2e encryption</source>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="received answer…" xml:space="preserve">
|
||||
<source>received answer…</source>
|
||||
<target>vastaus saatu…</target>
|
||||
@@ -6642,6 +7042,14 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
<target>poisti sinut</target>
|
||||
<note>rcv group event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved" xml:space="preserve">
|
||||
<source>saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved from %@" xml:space="preserve">
|
||||
<source>saved from %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sec" xml:space="preserve">
|
||||
<source>sec</source>
|
||||
<target>sek</target>
|
||||
@@ -6674,6 +7082,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
<source>set new profile picture</source>
|
||||
<note>profile update event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
|
||||
<source>standard end-to-end encryption</source>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="starting…" xml:space="preserve">
|
||||
<source>starting…</source>
|
||||
<target>alkaa…</target>
|
||||
@@ -6770,6 +7182,10 @@ SimpleX-palvelimet eivät näe profiiliasi.</target>
|
||||
<target>kyllä</target>
|
||||
<note>pref value</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you" xml:space="preserve">
|
||||
<source>you</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you are invited to group" xml:space="preserve">
|
||||
<source>you are invited to group</source>
|
||||
<target>sinut on kutsuttu ryhmään</target>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5311,6 +5311,11 @@ SimpleX servers cannot see your profile.</source>
|
||||
<target state="translated">ללא היסטוריה</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ and %@" xml:space="preserve" approved="no">
|
||||
<source>%@ and %@</source>
|
||||
<target state="translated">%@ ו-%@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="he" datatype="plaintext">
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"locale" : "hu"
|
||||
}
|
||||
],
|
||||
"properties" : {
|
||||
"localizable" : true
|
||||
},
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"red" : "0.000",
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "0.533"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"properties" : {
|
||||
"localizable" : true
|
||||
},
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
/* Bundle display name */
|
||||
"CFBundleDisplayName" = "SimpleX NSE";
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "SimpleX NSE";
|
||||
/* Copyright (human-readable) */
|
||||
"NSHumanReadableCopyright" = "Copyright © 2022 SimpleX Chat. All rights reserved.";
|
||||
@@ -0,0 +1,30 @@
|
||||
/* No comment provided by engineer. */
|
||||
"_italic_" = "\\_italic_";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Add new contact**: to create your one-time QR Code for your contact." = "**Add new contact**: to create your one-time QR Code or link for your contact.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"*bold*" = "\\*bold*";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"`a + b`" = "\\`a + b`";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"~strike~" = "\\~strike~";
|
||||
|
||||
/* call status */
|
||||
"connecting call" = "connecting call…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Connecting server…" = "Connecting to server…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Connecting server… (error: %@)" = "Connecting to server… (error: %@)";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"member connected" = "connected";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"No group!" = "Group not found!";
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "SimpleX";
|
||||
/* Privacy - Camera Usage Description */
|
||||
"NSCameraUsageDescription" = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
|
||||
/* Privacy - Face ID Usage Description */
|
||||
"NSFaceIDUsageDescription" = "SimpleX uses Face ID for local authentication";
|
||||
/* Privacy - Local Network Usage Description */
|
||||
"NSLocalNetworkUsageDescription" = "SimpleX uses local network access to allow using user chat profile via desktop app on the same network.";
|
||||
/* Privacy - Microphone Usage Description */
|
||||
"NSMicrophoneUsageDescription" = "SimpleX needs microphone access for audio and video calls, and to record voice messages.";
|
||||
/* Privacy - Photo Library Additions Usage Description */
|
||||
"NSPhotoLibraryAddUsageDescription" = "SimpleX needs access to Photo Library for saving captured and received media";
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"developmentRegion" : "en",
|
||||
"project" : "SimpleX.xcodeproj",
|
||||
"targetLocale" : "hu",
|
||||
"toolInfo" : {
|
||||
"toolBuildNumber" : "15A240d",
|
||||
"toolID" : "com.apple.dt.xcode",
|
||||
"toolName" : "Xcode",
|
||||
"toolVersion" : "15.0"
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
@@ -107,6 +107,11 @@
|
||||
<target>%@ si è connesso/a</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ downloaded" xml:space="preserve">
|
||||
<source>%@ downloaded</source>
|
||||
<target>%@ scaricati</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve">
|
||||
<source>%@ is connected!</source>
|
||||
<target>%@ è connesso/a!</target>
|
||||
@@ -127,6 +132,11 @@
|
||||
<target>Server %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ uploaded" xml:space="preserve">
|
||||
<source>%@ uploaded</source>
|
||||
<target>%@ caricati</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve">
|
||||
<source>%@ wants to connect!</source>
|
||||
<target>%@ si vuole connettere!</target>
|
||||
@@ -342,6 +352,11 @@
|
||||
<target>**Il più privato**: non usare il server di notifica di SimpleX Chat, controlla i messaggi periodicamente in secondo piano (dipende da quanto spesso usi l'app).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
|
||||
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
|
||||
<target>**Nota bene**: usare lo stesso database su due dispositivi bloccherà la decifrazione dei messaggi dalle tue connessioni, come misura di sicurezza.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
|
||||
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
|
||||
<target>**Nota bene**: NON potrai recuperare o cambiare la password se la perdi.</target>
|
||||
@@ -357,6 +372,11 @@
|
||||
<target>**Attenzione**: le notifiche push istantanee richiedono una password salvata nel portachiavi.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
|
||||
<source>**Warning**: the archive will be removed.</source>
|
||||
<target>**Attenzione**: l'archivio verrà rimosso.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
|
||||
<source>**e2e encrypted** audio call</source>
|
||||
<target>Chiamata **crittografata e2e**</target>
|
||||
@@ -613,6 +633,11 @@
|
||||
<target>Il cambio di indirizzo verrà interrotto. Verrà usato il vecchio indirizzo di ricezione.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can block a member for all." xml:space="preserve">
|
||||
<source>Admins can block a member for all.</source>
|
||||
<target>Gli amministratori possono bloccare un membro per tutti.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
|
||||
<source>Admins can create the links to join groups.</source>
|
||||
<target>Gli amministratori possono creare i link per entrare nei gruppi.</target>
|
||||
@@ -668,6 +693,11 @@
|
||||
<target>Tutti i tuoi contatti resteranno connessi. L'aggiornamento del profilo verrà inviato ai tuoi contatti.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
|
||||
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
|
||||
<target>Tutti i tuoi contatti, le conversazioni e i file verranno criptati in modo sicuro e caricati in blocchi sui relay XFTP configurati.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow" xml:space="preserve">
|
||||
<source>Allow</source>
|
||||
<target>Consenti</target>
|
||||
@@ -713,6 +743,10 @@
|
||||
<target>Permetti di eliminare irreversibilmente i messaggi inviati. (24 ore)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
|
||||
<source>Allow to send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send files and media." xml:space="preserve">
|
||||
<source>Allow to send files and media.</source>
|
||||
<target>Consenti l'invio di file e contenuti multimediali.</target>
|
||||
@@ -793,6 +827,11 @@
|
||||
<target>Build dell'app: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App data migration" xml:space="preserve">
|
||||
<source>App data migration</source>
|
||||
<target>Migrazione dati dell'app</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
|
||||
<source>App encrypts new local files (except videos).</source>
|
||||
<target>L'app cripta i nuovi file locali (eccetto i video).</target>
|
||||
@@ -828,6 +867,21 @@
|
||||
<target>Aspetto</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Apply" xml:space="preserve">
|
||||
<source>Apply</source>
|
||||
<target>Applica</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archive and upload" xml:space="preserve">
|
||||
<source>Archive and upload</source>
|
||||
<target>Archivia e carica</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archiving database" xml:space="preserve">
|
||||
<source>Archiving database</source>
|
||||
<target>Archiviazione del database</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<source>Attach</source>
|
||||
<target>Allega</target>
|
||||
@@ -1018,6 +1072,11 @@
|
||||
<target>Annulla</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cancel migration" xml:space="preserve">
|
||||
<source>Cancel migration</source>
|
||||
<target>Annulla migrazione</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
|
||||
<source>Cannot access keychain to save database password</source>
|
||||
<target>Impossibile accedere al portachiavi per salvare la password del database</target>
|
||||
@@ -1028,6 +1087,10 @@
|
||||
<target>Impossibile ricevere il file</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cellular" xml:space="preserve">
|
||||
<source>Cellular</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Change" xml:space="preserve">
|
||||
<source>Change</source>
|
||||
<target>Cambia</target>
|
||||
@@ -1119,6 +1182,11 @@
|
||||
<target>La chat è ferma. Se hai già usato questo database su un altro dispositivo, dovresti trasferirlo prima di avviare la chat.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat migrated!" xml:space="preserve">
|
||||
<source>Chat migrated!</source>
|
||||
<target>Chat migrata!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat preferences" xml:space="preserve">
|
||||
<source>Chat preferences</source>
|
||||
<target>Preferenze della chat</target>
|
||||
@@ -1139,6 +1207,11 @@
|
||||
<target>Interfaccia cinese e spagnola</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
|
||||
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
|
||||
<target>Scegli _Migra da un altro dispositivo_ sul nuovo dispositivo e scansione il codice QR.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose file" xml:space="preserve">
|
||||
<source>Choose file</source>
|
||||
<target>Scegli file</target>
|
||||
@@ -1209,6 +1282,11 @@
|
||||
<target>Conferma aggiornamenti database</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm network settings" xml:space="preserve">
|
||||
<source>Confirm network settings</source>
|
||||
<target>Conferma le impostazioni di rete</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm new passphrase…" xml:space="preserve">
|
||||
<source>Confirm new passphrase…</source>
|
||||
<target>Conferma nuova password…</target>
|
||||
@@ -1219,6 +1297,16 @@
|
||||
<target>Conferma password</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
|
||||
<source>Confirm that you remember database passphrase to migrate it.</source>
|
||||
<target>Conferma che ricordi la password del database da migrare.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm upload" xml:space="preserve">
|
||||
<source>Confirm upload</source>
|
||||
<target>Conferma caricamento</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Connect" xml:space="preserve">
|
||||
<source>Connect</source>
|
||||
<target>Connetti</target>
|
||||
@@ -1478,6 +1566,11 @@ Questo è il tuo link una tantum!</target>
|
||||
<target>Creato il %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating archive link" xml:space="preserve">
|
||||
<source>Creating archive link</source>
|
||||
<target>Creazione link dell'archivio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating link…" xml:space="preserve">
|
||||
<source>Creating link…</source>
|
||||
<target>Creazione link…</target>
|
||||
@@ -1698,6 +1791,11 @@ Non è reversibile!</target>
|
||||
<target>Elimina database</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete database from this device" xml:space="preserve">
|
||||
<source>Delete database from this device</source>
|
||||
<target>Elimina il database da questo dispositivo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete file" xml:space="preserve">
|
||||
<source>Delete file</source>
|
||||
<target>Elimina file</target>
|
||||
@@ -1988,11 +2086,30 @@ Non è reversibile!</target>
|
||||
<target>Esegui downgrade e apri chat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download" xml:space="preserve">
|
||||
<source>Download</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download failed" xml:space="preserve">
|
||||
<source>Download failed</source>
|
||||
<target>Scaricamento fallito</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download file" xml:space="preserve">
|
||||
<source>Download file</source>
|
||||
<target>Scarica file</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading archive" xml:space="preserve">
|
||||
<source>Downloading archive</source>
|
||||
<target>Scaricamento archivio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading link details" xml:space="preserve">
|
||||
<source>Downloading link details</source>
|
||||
<target>Scaricamento dettagli del link</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duplicate display name!" xml:space="preserve">
|
||||
<source>Duplicate display name!</source>
|
||||
<target>Nome da mostrare doppio!</target>
|
||||
@@ -2048,6 +2165,11 @@ Non è reversibile!</target>
|
||||
<target>Attiva per tutti</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
|
||||
<source>Enable in direct chats (BETA)!</source>
|
||||
<target>Attivala nelle chat dirette (BETA)!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable instant notifications?" xml:space="preserve">
|
||||
<source>Enable instant notifications?</source>
|
||||
<target>Attivare le notifiche istantanee?</target>
|
||||
@@ -2078,6 +2200,10 @@ Non è reversibile!</target>
|
||||
<target>Attiva il codice di autodistruzione</target>
|
||||
<note>set passcode view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled for" xml:space="preserve">
|
||||
<source>Enabled for</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt" xml:space="preserve">
|
||||
<source>Encrypt</source>
|
||||
<target>Crittografare</target>
|
||||
@@ -2163,6 +2289,11 @@ Non è reversibile!</target>
|
||||
<target>Inserisci il nome del gruppo…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase" xml:space="preserve">
|
||||
<source>Enter passphrase</source>
|
||||
<target>Inserisci password</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve">
|
||||
<source>Enter passphrase…</source>
|
||||
<target>Inserisci la password…</target>
|
||||
@@ -2223,6 +2354,11 @@ Non è reversibile!</target>
|
||||
<target>Errore di aggiunta membro/i</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error allowing contact PQ encryption" xml:space="preserve">
|
||||
<source>Error allowing contact PQ encryption</source>
|
||||
<target>Errore nel consentire la crittografia PQ al contatto</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing address" xml:space="preserve">
|
||||
<source>Error changing address</source>
|
||||
<target>Errore nella modifica dell'indirizzo</target>
|
||||
@@ -2313,6 +2449,11 @@ Non è reversibile!</target>
|
||||
<target>Errore nell'eliminazione del profilo utente</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error downloading the archive" xml:space="preserve">
|
||||
<source>Error downloading the archive</source>
|
||||
<target>Errore di scaricamento dell'archivio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
|
||||
<source>Error enabling delivery receipts!</source>
|
||||
<target>Errore nell'attivazione delle ricevute di consegna!</target>
|
||||
@@ -2388,6 +2529,11 @@ Non è reversibile!</target>
|
||||
<target>Errore nel salvataggio della password nel portachiavi</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving settings" xml:space="preserve">
|
||||
<source>Error saving settings</source>
|
||||
<target>Errore di salvataggio delle impostazioni</target>
|
||||
<note>when migrating</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving user password" xml:space="preserve">
|
||||
<source>Error saving user password</source>
|
||||
<target>Errore nel salvataggio della password utente</target>
|
||||
@@ -2458,6 +2604,16 @@ Non è reversibile!</target>
|
||||
<target>Errore nell'aggiornamento della privacy dell'utente</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error uploading the archive" xml:space="preserve">
|
||||
<source>Error uploading the archive</source>
|
||||
<target>Errore di invio dell'archivio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
|
||||
<source>Error verifying passphrase:</source>
|
||||
<target>Errore di verifica della password:</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error: " xml:space="preserve">
|
||||
<source>Error: </source>
|
||||
<target>Errore: </target>
|
||||
@@ -2508,6 +2664,11 @@ Non è reversibile!</target>
|
||||
<target>Archivio database esportato.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
|
||||
<source>Exported file doesn't exist</source>
|
||||
<target>Il file esportato non esiste</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exporting database archive…" xml:space="preserve">
|
||||
<source>Exporting database archive…</source>
|
||||
<target>Esportazione archivio database…</target>
|
||||
@@ -2568,6 +2729,10 @@ Non è reversibile!</target>
|
||||
<target>File e contenuti multimediali sono vietati in questo gruppo.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media not allowed" xml:space="preserve">
|
||||
<source>Files and media not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media prohibited!" xml:space="preserve">
|
||||
<source>Files and media prohibited!</source>
|
||||
<target>File e contenuti multimediali vietati!</target>
|
||||
@@ -2578,6 +2743,16 @@ Non è reversibile!</target>
|
||||
<target>Filtra le chat non lette e preferite.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration" xml:space="preserve">
|
||||
<source>Finalize migration</source>
|
||||
<target>Finalizza la migrazione</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration on another device." xml:space="preserve">
|
||||
<source>Finalize migration on another device.</source>
|
||||
<target>Finalizza la migrazione su un altro dispositivo.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
|
||||
<source>Finally, we have them! 🚀</source>
|
||||
<target>Finalmente le abbiamo! 🚀</target>
|
||||
@@ -2623,6 +2798,18 @@ Non è reversibile!</target>
|
||||
<target>Per console</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forward" xml:space="preserve">
|
||||
<source>Forward</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded" xml:space="preserve">
|
||||
<source>Forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded from" xml:space="preserve">
|
||||
<source>Forwarded from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Found desktop" xml:space="preserve">
|
||||
<source>Found desktop</source>
|
||||
<target>Desktop trovato</target>
|
||||
@@ -2733,6 +2920,10 @@ Non è reversibile!</target>
|
||||
<target>I membri del gruppo possono eliminare irreversibilmente i messaggi inviati. (24 ore)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
|
||||
<source>Group members can send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send direct messages." xml:space="preserve">
|
||||
<source>Group members can send direct messages.</source>
|
||||
<target>I membri del gruppo possono inviare messaggi diretti.</target>
|
||||
@@ -2868,6 +3059,11 @@ Non è reversibile!</target>
|
||||
<target>Come usare i tuoi server</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Hungarian interface" xml:space="preserve">
|
||||
<source>Hungarian interface</source>
|
||||
<target>Interfaccia in ungherese</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
|
||||
<source>ICE servers (one per line)</source>
|
||||
<target>Server ICE (uno per riga)</target>
|
||||
@@ -2933,6 +3129,16 @@ Non è reversibile!</target>
|
||||
<target>Importa database</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import failed" xml:space="preserve">
|
||||
<source>Import failed</source>
|
||||
<target>Importazione fallita</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Importing archive" xml:space="preserve">
|
||||
<source>Importing archive</source>
|
||||
<target>Importazione archivio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved message delivery" xml:space="preserve">
|
||||
<source>Improved message delivery</source>
|
||||
<target>Consegna dei messaggi migliorata</target>
|
||||
@@ -2948,6 +3154,11 @@ Non è reversibile!</target>
|
||||
<target>Configurazione del server migliorata</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
|
||||
<source>In order to continue, chat should be stopped.</source>
|
||||
<target>Per continuare, la chat deve essere fermata.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In reply to" xml:space="preserve">
|
||||
<source>In reply to</source>
|
||||
<target>In risposta a</target>
|
||||
@@ -3060,6 +3271,11 @@ Non è reversibile!</target>
|
||||
<target>Link non valido</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
|
||||
<source>Invalid migration confirmation</source>
|
||||
<target>Conferma di migrazione non valida</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid name!" xml:space="preserve">
|
||||
<source>Invalid name!</source>
|
||||
<target>Nome non valido!</target>
|
||||
@@ -3428,6 +3644,11 @@ Questo è il tuo link per il gruppo %@!</target>
|
||||
<target>Testo del messaggio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Message too large" xml:space="preserve">
|
||||
<source>Message too large</source>
|
||||
<target>Messaggio troppo grande</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages" xml:space="preserve">
|
||||
<source>Messages</source>
|
||||
<target>Messaggi</target>
|
||||
@@ -3443,11 +3664,56 @@ Questo è il tuo link per il gruppo %@!</target>
|
||||
<target>I messaggi da %@ verranno mostrati!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<target>I messaggi, i file e le chiamate sono protetti da **crittografia end-to-end** con perfect forward secrecy, ripudio e recupero da intrusione.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<target>I messaggi, i file e le chiamate sono protetti da **crittografia e2e resistente alla quantistica** con perfect forward secrecy, ripudio e recupero da intrusione.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate device" xml:space="preserve">
|
||||
<source>Migrate device</source>
|
||||
<target>Migra dispositivo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate from another device" xml:space="preserve">
|
||||
<source>Migrate from another device</source>
|
||||
<target>Migra da un altro dispositivo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate here" xml:space="preserve">
|
||||
<source>Migrate here</source>
|
||||
<target>Migra qui</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device" xml:space="preserve">
|
||||
<source>Migrate to another device</source>
|
||||
<target>Migra ad un altro dispositivo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
|
||||
<source>Migrate to another device via QR code.</source>
|
||||
<target>Migra ad un altro dispositivo via codice QR.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating" xml:space="preserve">
|
||||
<source>Migrating</source>
|
||||
<target>Migrazione</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating database archive…" xml:space="preserve">
|
||||
<source>Migrating database archive…</source>
|
||||
<target>Migrazione archivio del database…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration complete" xml:space="preserve">
|
||||
<source>Migration complete</source>
|
||||
<target>Migrazione completata</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration error:" xml:space="preserve">
|
||||
<source>Migration error:</source>
|
||||
<target>Errore di migrazione:</target>
|
||||
@@ -3523,6 +3789,10 @@ Questo è il tuo link per il gruppo %@!</target>
|
||||
<target>Rete e server</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network connection" xml:space="preserve">
|
||||
<source>Network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network settings" xml:space="preserve">
|
||||
<source>Network settings</source>
|
||||
<target>Impostazioni di rete</target>
|
||||
@@ -3633,6 +3903,10 @@ Questo è il tuo link per il gruppo %@!</target>
|
||||
<target>Nessuna cronologia</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No network connection" xml:space="preserve">
|
||||
<source>No network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No permission to record voice message" xml:space="preserve">
|
||||
<source>No permission to record voice message</source>
|
||||
<target>Nessuna autorizzazione per registrare messaggi vocali</target>
|
||||
@@ -3807,6 +4081,11 @@ Questo è il tuo link per il gruppo %@!</target>
|
||||
<target>Apri gruppo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open migration to another device" xml:space="preserve">
|
||||
<source>Open migration to another device</source>
|
||||
<target>Apri migrazione ad un altro dispositivo</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open user profiles" xml:space="preserve">
|
||||
<source>Open user profiles</source>
|
||||
<target>Apri i profili utente</target>
|
||||
@@ -3822,16 +4101,30 @@ Questo è il tuo link per il gruppo %@!</target>
|
||||
<target>Apertura dell'app…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or paste archive link" xml:space="preserve">
|
||||
<source>Or paste archive link</source>
|
||||
<target>O incolla il link dell'archivio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or scan QR code" xml:space="preserve">
|
||||
<source>Or scan QR code</source>
|
||||
<target>O scansiona il codice QR</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or securely share this file link" xml:space="preserve">
|
||||
<source>Or securely share this file link</source>
|
||||
<target>O condividi in modo sicuro questo link del file</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or show this code" xml:space="preserve">
|
||||
<source>Or show this code</source>
|
||||
<target>O mostra questo codice</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Other" xml:space="preserve">
|
||||
<source>Other</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PING count" xml:space="preserve">
|
||||
<source>PING count</source>
|
||||
<target>Conteggio PING</target>
|
||||
@@ -3912,6 +4205,11 @@ Questo è il tuo link per il gruppo %@!</target>
|
||||
<target>Errore di decifrazione</target>
|
||||
<note>message decrypt error item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
|
||||
<source>Picture-in-picture calls</source>
|
||||
<target>Chiamate picture-in-picture</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
|
||||
<source>Please ask your contact to enable sending voice messages.</source>
|
||||
<target>Chiedi al tuo contatto di attivare l'invio dei messaggi vocali.</target>
|
||||
@@ -3932,6 +4230,11 @@ Questo è il tuo link per il gruppo %@!</target>
|
||||
<target>Controlla le preferenze tue e del tuo contatto.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
|
||||
<source>Please confirm that network settings are correct for this device.</source>
|
||||
<target>Conferma che le impostazioni di rete sono corrette per questo dispositivo.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please contact developers. Error: %@" xml:space="preserve">
|
||||
<source>Please contact developers.
|
||||
Error: %@</source>
|
||||
@@ -3989,6 +4292,11 @@ Errore: %@</target>
|
||||
<target>Probabilmente l'impronta del certificato nell'indirizzo del server è sbagliata</target>
|
||||
<note>server test error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Post-quantum E2EE" xml:space="preserve">
|
||||
<source>Post-quantum E2EE</source>
|
||||
<target>E2EE post-quantistica</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
|
||||
<source>Preserve the last message draft, with attachments.</source>
|
||||
<target>Conserva la bozza dell'ultimo messaggio, con gli allegati.</target>
|
||||
@@ -4079,6 +4387,10 @@ Errore: %@</target>
|
||||
<target>Proibisci le reazioni ai messaggi.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
|
||||
<source>Prohibit sending SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
|
||||
<source>Prohibit sending direct messages to members.</source>
|
||||
<target>Proibisci l'invio di messaggi diretti ai membri.</target>
|
||||
@@ -4124,6 +4436,16 @@ Errore: %@</target>
|
||||
<target>Notifiche push</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Push server" xml:space="preserve">
|
||||
<source>Push server</source>
|
||||
<target>Server push</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
|
||||
<source>Quantum resistant encryption</source>
|
||||
<target>Crittografia resistente alla quantistica</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Rate the app" xml:space="preserve">
|
||||
<source>Rate the app</source>
|
||||
<target>Valuta l'app</target>
|
||||
@@ -4199,6 +4521,10 @@ Errore: %@</target>
|
||||
<target>L'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell'indirizzo verrà completata dopo che il mittente sarà in linea.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving concurrency" xml:space="preserve">
|
||||
<source>Receiving concurrency</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
|
||||
<source>Receiving file will be stopped.</source>
|
||||
<target>La ricezione del file verrà interrotta.</target>
|
||||
@@ -4214,6 +4540,10 @@ Errore: %@</target>
|
||||
<target>Cronologia recente e [bot della directory](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) migliorato.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
|
||||
<source>Recipient(s) can't see who this message is from.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipients see updates as you type them." xml:space="preserve">
|
||||
<source>Recipients see updates as you type them.</source>
|
||||
<target>I destinatari vedono gli aggiornamenti mentre li digiti.</target>
|
||||
@@ -4309,11 +4639,26 @@ Errore: %@</target>
|
||||
<target>Ripetere la richiesta di connessione?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat download" xml:space="preserve">
|
||||
<source>Repeat download</source>
|
||||
<target>Ripeti scaricamento</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat import" xml:space="preserve">
|
||||
<source>Repeat import</source>
|
||||
<target>Ripeti importazione</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat join request?" xml:space="preserve">
|
||||
<source>Repeat join request?</source>
|
||||
<target>Ripetere la richiesta di ingresso?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat upload" xml:space="preserve">
|
||||
<source>Repeat upload</source>
|
||||
<target>Ripeti caricamento</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply" xml:space="preserve">
|
||||
<source>Reply</source>
|
||||
<target>Rispondi</target>
|
||||
@@ -4414,6 +4759,11 @@ Errore: %@</target>
|
||||
<target>Server SMP</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Safer groups" xml:space="preserve">
|
||||
<source>Safer groups</source>
|
||||
<target>Gruppi più sicuri</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Save" xml:space="preserve">
|
||||
<source>Save</source>
|
||||
<target>Salva</target>
|
||||
@@ -4494,11 +4844,19 @@ Errore: %@</target>
|
||||
<target>Salvare il messaggio di benvenuto?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved" xml:space="preserve">
|
||||
<source>Saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
|
||||
<source>Saved WebRTC ICE servers will be removed</source>
|
||||
<target>I server WebRTC ICE salvati verranno rimossi</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved from" xml:space="preserve">
|
||||
<source>Saved from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved message" xml:space="preserve">
|
||||
<source>Saved message</source>
|
||||
<target>Messaggio salvato</target>
|
||||
@@ -4779,6 +5137,11 @@ Errore: %@</target>
|
||||
<target>Imposta codice</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase" xml:space="preserve">
|
||||
<source>Set passphrase</source>
|
||||
<target>Imposta password</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase to export" xml:space="preserve">
|
||||
<source>Set passphrase to export</source>
|
||||
<target>Imposta la password per esportare</target>
|
||||
@@ -4834,6 +5197,11 @@ Errore: %@</target>
|
||||
<target>Condividi con i contatti</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
<source>Show QR code</source>
|
||||
<target>Mostra codice QR</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show calls in phone history" xml:space="preserve">
|
||||
<source>Show calls in phone history</source>
|
||||
<target>Mostra le chiamate nella cronologia del telefono</target>
|
||||
@@ -4912,6 +5280,14 @@ Errore: %@</target>
|
||||
<trans-unit id="SimpleX links" xml:space="preserve">
|
||||
<source>SimpleX links</source>
|
||||
<target>Link di SimpleX</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
|
||||
<source>SimpleX links are prohibited in this group.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
|
||||
<source>SimpleX links not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX one-time invitation" xml:space="preserve">
|
||||
@@ -4974,6 +5350,11 @@ Errore: %@</target>
|
||||
<target>Ferma SimpleX</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat" xml:space="preserve">
|
||||
<source>Stop chat</source>
|
||||
<target>Ferma la chat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat to enable database actions" xml:space="preserve">
|
||||
<source>Stop chat to enable database actions</source>
|
||||
<target>Ferma la chat per attivare le azioni del database</target>
|
||||
@@ -5014,6 +5395,11 @@ Errore: %@</target>
|
||||
<target>Smettere di condividere l'indirizzo?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stopping chat" xml:space="preserve">
|
||||
<source>Stopping chat</source>
|
||||
<target>Arresto della chat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Submit" xml:space="preserve">
|
||||
<source>Submit</source>
|
||||
<target>Invia</target>
|
||||
@@ -5261,6 +5647,16 @@ Può accadere a causa di qualche bug o quando la connessione è compromessa.</ta
|
||||
<target>Questa azione non può essere annullata: il tuo profilo, i contatti, i messaggi e i file andranno persi in modo irreversibile.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by end-to-end encryption.</source>
|
||||
<target>Questa chat è protetta da crittografia end-to-end.</target>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
|
||||
<target>Questa chat è protetta da crittografia end-to-end resistente alla quantistica.</target>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This device name" xml:space="preserve">
|
||||
<source>This device name</source>
|
||||
<target>Il nome di questo dispositivo</target>
|
||||
@@ -5555,11 +5951,21 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>Aggiorna e apri chat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload failed" xml:space="preserve">
|
||||
<source>Upload failed</source>
|
||||
<target>Invio fallito</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload file" xml:space="preserve">
|
||||
<source>Upload file</source>
|
||||
<target>Invia file</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uploading archive" xml:space="preserve">
|
||||
<source>Uploading archive</source>
|
||||
<target>Invio dell'archivio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use .onion hosts" xml:space="preserve">
|
||||
<source>Use .onion hosts</source>
|
||||
<target>Usa gli host .onion</target>
|
||||
@@ -5610,6 +6016,11 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>Usa il server</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
<source>Use the app while in the call.</source>
|
||||
<target>Usa l'app mentre sei in chiamata.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="User profile" xml:space="preserve">
|
||||
<source>User profile</source>
|
||||
<target>Profilo utente</target>
|
||||
@@ -5645,6 +6056,16 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>Verifica le connessioni</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify database passphrase" xml:space="preserve">
|
||||
<source>Verify database passphrase</source>
|
||||
<target>Verifica password del database</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify passphrase" xml:space="preserve">
|
||||
<source>Verify passphrase</source>
|
||||
<target>Verifica password</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify security code" xml:space="preserve">
|
||||
<source>Verify security code</source>
|
||||
<target>Verifica codice di sicurezza</target>
|
||||
@@ -5705,6 +6126,10 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>I messaggi vocali sono vietati in questo gruppo.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages not allowed" xml:space="preserve">
|
||||
<source>Voice messages not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages prohibited!" xml:space="preserve">
|
||||
<source>Voice messages prohibited!</source>
|
||||
<target>Messaggi vocali vietati!</target>
|
||||
@@ -5735,6 +6160,11 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>In attesa del video</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
|
||||
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
|
||||
<target>Attenzione: avviare la chat su più dispositivi non è supportato e provocherà problemi di recapito dei messaggi</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: you may lose some data!" xml:space="preserve">
|
||||
<source>Warning: you may lose some data!</source>
|
||||
<target>Attenzione: potresti perdere alcuni dati!</target>
|
||||
@@ -5755,6 +6185,11 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>Messaggio di benvenuto</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Welcome message is too long" xml:space="preserve">
|
||||
<source>Welcome message is too long</source>
|
||||
<target>Il messaggio di benvenuto è troppo lungo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="What's new" xml:space="preserve">
|
||||
<source>What's new</source>
|
||||
<target>Novità</target>
|
||||
@@ -5775,6 +6210,14 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>Quando condividi un profilo in incognito con qualcuno, questo profilo verrà utilizzato per i gruppi a cui ti invitano.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WiFi" xml:space="preserve">
|
||||
<source>WiFi</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wired ethernet" xml:space="preserve">
|
||||
<source>Wired ethernet</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="With encrypted files and media." xml:space="preserve">
|
||||
<source>With encrypted files and media.</source>
|
||||
<target>Con file e multimediali criptati.</target>
|
||||
@@ -5810,6 +6253,11 @@ Per connetterti, chiedi al tuo contatto di creare un altro link di connessione e
|
||||
<target>Tu</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
|
||||
<source>You **must not** use the same database on two devices.</source>
|
||||
<target>**Non devi** usare lo stesso database su due dispositivi.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You accepted connection" xml:space="preserve">
|
||||
<source>You accepted connection</source>
|
||||
<target>Hai accettato la connessione</target>
|
||||
@@ -5897,6 +6345,11 @@ Ripetere la richiesta di ingresso?</target>
|
||||
<target>Puoi attivarle più tardi nelle impostazioni di privacy e sicurezza dell'app.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can give another try." xml:space="preserve">
|
||||
<source>You can give another try.</source>
|
||||
<target>Puoi fare un altro tentativo.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
|
||||
<source>You can hide or mute a user profile - swipe it to the right.</source>
|
||||
<target>Puoi nascondere o silenziare un profilo utente - scorrilo verso destra.</target>
|
||||
@@ -6173,7 +6626,7 @@ Puoi annullare questa connessione e rimuovere il contatto (e riprovare più tard
|
||||
</trans-unit>
|
||||
<trans-unit id="Your profile **%@** will be shared." xml:space="preserve">
|
||||
<source>Your profile **%@** will be shared.</source>
|
||||
<target>Il tuo profilo **%@** verrà condiviso.</target>
|
||||
<target>Verrà condiviso il tuo profilo **%@**.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile." xml:space="preserve">
|
||||
@@ -6248,6 +6701,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<target>amministratore</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="admins" xml:space="preserve">
|
||||
<source>admins</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="agreeing encryption for %@…" xml:space="preserve">
|
||||
<source>agreeing encryption for %@…</source>
|
||||
<target>concordando la crittografia per %@…</target>
|
||||
@@ -6258,6 +6715,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<target>concordando la crittografia…</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="all members" xml:space="preserve">
|
||||
<source>all members</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="always" xml:space="preserve">
|
||||
<source>always</source>
|
||||
<target>sempre</target>
|
||||
@@ -6291,7 +6752,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<trans-unit id="blocked" xml:space="preserve">
|
||||
<source>blocked</source>
|
||||
<target>bloccato</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked %@" xml:space="preserve">
|
||||
<source>blocked %@</source>
|
||||
@@ -6301,7 +6762,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<trans-unit id="blocked by admin" xml:space="preserve">
|
||||
<source>blocked by admin</source>
|
||||
<target>bloccato dall'amministratore</target>
|
||||
<note>blocked chat item</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bold" xml:space="preserve">
|
||||
<source>bold</source>
|
||||
@@ -6588,6 +7049,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<target>evento accaduto</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="forwarded" xml:space="preserve">
|
||||
<source>forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="group deleted" xml:space="preserve">
|
||||
<source>group deleted</source>
|
||||
<target>gruppo eliminato</target>
|
||||
@@ -6731,7 +7196,7 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<trans-unit id="moderated by %@" xml:space="preserve">
|
||||
<source>moderated by %@</source>
|
||||
<target>moderato da %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="months" xml:space="preserve">
|
||||
<source>months</source>
|
||||
@@ -6795,11 +7260,20 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<target>proprietario</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="owners" xml:space="preserve">
|
||||
<source>owners</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="peer-to-peer" xml:space="preserve">
|
||||
<source>peer-to-peer</source>
|
||||
<target>peer-to-peer</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
|
||||
<source>quantum resistant e2e encryption</source>
|
||||
<target>crittografia e2e resistente alla quantistica</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="received answer…" xml:space="preserve">
|
||||
<source>received answer…</source>
|
||||
<target>risposta ricevuta…</target>
|
||||
@@ -6840,6 +7314,14 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<target>ti ha rimosso/a</target>
|
||||
<note>rcv group event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved" xml:space="preserve">
|
||||
<source>saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved from %@" xml:space="preserve">
|
||||
<source>saved from %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sec" xml:space="preserve">
|
||||
<source>sec</source>
|
||||
<target>sec</target>
|
||||
@@ -6875,6 +7357,11 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<target>impostata nuova immagine del profilo</target>
|
||||
<note>profile update event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
|
||||
<source>standard end-to-end encryption</source>
|
||||
<target>crittografia end-to-end standard</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="starting…" xml:space="preserve">
|
||||
<source>starting…</source>
|
||||
<target>avvio…</target>
|
||||
@@ -6975,6 +7462,10 @@ I server di SimpleX non possono vedere il tuo profilo.</target>
|
||||
<target>sì</target>
|
||||
<note>pref value</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you" xml:space="preserve">
|
||||
<source>you</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you are invited to group" xml:space="preserve">
|
||||
<source>you are invited to group</source>
|
||||
<target>sei stato/a invitato/a al gruppo</target>
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ and %@" xml:space="preserve">
|
||||
<source>%@ and %@</source>
|
||||
<target>%@ と %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ and %@ connected" xml:space="preserve">
|
||||
@@ -106,6 +107,10 @@
|
||||
<target>%@ 接続中</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ downloaded" xml:space="preserve">
|
||||
<source>%@ downloaded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve">
|
||||
<source>%@ is connected!</source>
|
||||
<target>%@ 接続中!</target>
|
||||
@@ -126,6 +131,10 @@
|
||||
<target>%@ サーバー</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ uploaded" xml:space="preserve">
|
||||
<source>%@ uploaded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve">
|
||||
<source>%@ wants to connect!</source>
|
||||
<target>%@ が接続を希望しています!</target>
|
||||
@@ -333,6 +342,10 @@
|
||||
<target>**最もプライベート**: SimpleX Chat 通知サーバーを使用せず、バックグラウンドで定期的にメッセージをチェックします (アプリの使用頻度によって異なります)。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
|
||||
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
|
||||
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
|
||||
<target>**注意**: パスフレーズを紛失すると、パスフレーズを復元または変更できなくなります。</target>
|
||||
@@ -348,6 +361,10 @@
|
||||
<target>**警告**: 即時の プッシュ通知には、キーチェーンに保存されたパスフレーズが必要です。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
|
||||
<source>**Warning**: the archive will be removed.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
|
||||
<source>**e2e encrypted** audio call</source>
|
||||
<target>**e2e 暗号化**音声通話</target>
|
||||
@@ -596,6 +613,10 @@
|
||||
<target>アドレス変更は中止されます。古い受信アドレスが使用されます。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can block a member for all." xml:space="preserve">
|
||||
<source>Admins can block a member for all.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
|
||||
<source>Admins can create the links to join groups.</source>
|
||||
<target>管理者はグループの参加リンクを生成できます。</target>
|
||||
@@ -649,6 +670,10 @@
|
||||
<target>すべての連絡先は維持されます。連絡先に更新されたプロフィールを送信します。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
|
||||
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow" xml:space="preserve">
|
||||
<source>Allow</source>
|
||||
<target>許可</target>
|
||||
@@ -694,6 +719,10 @@
|
||||
<target>送信済みメッセージの永久削除を許可する。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
|
||||
<source>Allow to send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send files and media." xml:space="preserve">
|
||||
<source>Allow to send files and media.</source>
|
||||
<target>ファイルやメディアの送信を許可する。</target>
|
||||
@@ -772,6 +801,10 @@
|
||||
<target>アプリのビルド: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App data migration" xml:space="preserve">
|
||||
<source>App data migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
|
||||
<source>App encrypts new local files (except videos).</source>
|
||||
<target>アプリは新しいローカルファイル(ビデオを除く)を暗号化します。</target>
|
||||
@@ -807,6 +840,18 @@
|
||||
<target>見た目</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Apply" xml:space="preserve">
|
||||
<source>Apply</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archive and upload" xml:space="preserve">
|
||||
<source>Archive and upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archiving database" xml:space="preserve">
|
||||
<source>Archiving database</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<source>Attach</source>
|
||||
<target>添付する</target>
|
||||
@@ -987,6 +1032,10 @@
|
||||
<target>中止</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cancel migration" xml:space="preserve">
|
||||
<source>Cancel migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
|
||||
<source>Cannot access keychain to save database password</source>
|
||||
<target>データベースのパスワードを保存するためのキーチェーンにアクセスできません</target>
|
||||
@@ -997,6 +1046,10 @@
|
||||
<target>ファイル受信ができません</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cellular" xml:space="preserve">
|
||||
<source>Cellular</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Change" xml:space="preserve">
|
||||
<source>Change</source>
|
||||
<target>変更</target>
|
||||
@@ -1087,6 +1140,10 @@
|
||||
<source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat migrated!" xml:space="preserve">
|
||||
<source>Chat migrated!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat preferences" xml:space="preserve">
|
||||
<source>Chat preferences</source>
|
||||
<target>チャット設定</target>
|
||||
@@ -1107,6 +1164,10 @@
|
||||
<target>中国語とスペイン語UI</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
|
||||
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose file" xml:space="preserve">
|
||||
<source>Choose file</source>
|
||||
<target>ファイルを選択</target>
|
||||
@@ -1176,6 +1237,10 @@
|
||||
<target>データベースのアップグレードを確認</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm network settings" xml:space="preserve">
|
||||
<source>Confirm network settings</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm new passphrase…" xml:space="preserve">
|
||||
<source>Confirm new passphrase…</source>
|
||||
<target>新しいパスフレーズを確認…</target>
|
||||
@@ -1186,6 +1251,14 @@
|
||||
<target>パスワードを確認</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
|
||||
<source>Confirm that you remember database passphrase to migrate it.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm upload" xml:space="preserve">
|
||||
<source>Confirm upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Connect" xml:space="preserve">
|
||||
<source>Connect</source>
|
||||
<target>接続</target>
|
||||
@@ -1426,6 +1499,10 @@ This is your own one-time link!</source>
|
||||
<target>%@ によって作成されました</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating archive link" xml:space="preserve">
|
||||
<source>Creating archive link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating link…" xml:space="preserve">
|
||||
<source>Creating link…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -1641,6 +1718,10 @@ This cannot be undone!</source>
|
||||
<target>データベースを削除</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete database from this device" xml:space="preserve">
|
||||
<source>Delete database from this device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete file" xml:space="preserve">
|
||||
<source>Delete file</source>
|
||||
<target>ファイルの削除</target>
|
||||
@@ -1925,11 +2006,27 @@ This cannot be undone!</source>
|
||||
<target>ダウングレードしてチャットを開く</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download" xml:space="preserve">
|
||||
<source>Download</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download failed" xml:space="preserve">
|
||||
<source>Download failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download file" xml:space="preserve">
|
||||
<source>Download file</source>
|
||||
<target>ファイルをダウンロード</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading archive" xml:space="preserve">
|
||||
<source>Downloading archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading link details" xml:space="preserve">
|
||||
<source>Downloading link details</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duplicate display name!" xml:space="preserve">
|
||||
<source>Duplicate display name!</source>
|
||||
<target>表示の名前が重複してます!</target>
|
||||
@@ -1984,6 +2081,10 @@ This cannot be undone!</source>
|
||||
<target>すべて有効</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
|
||||
<source>Enable in direct chats (BETA)!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable instant notifications?" xml:space="preserve">
|
||||
<source>Enable instant notifications?</source>
|
||||
<target>即時通知を有効にしますか?</target>
|
||||
@@ -2014,6 +2115,10 @@ This cannot be undone!</source>
|
||||
<target>自己破壊パスコードを有効にする</target>
|
||||
<note>set passcode view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled for" xml:space="preserve">
|
||||
<source>Enabled for</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt" xml:space="preserve">
|
||||
<source>Encrypt</source>
|
||||
<target>暗号化する</target>
|
||||
@@ -2095,6 +2200,10 @@ This cannot be undone!</source>
|
||||
<source>Enter group name…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase" xml:space="preserve">
|
||||
<source>Enter passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve">
|
||||
<source>Enter passphrase…</source>
|
||||
<target>暗証フレーズを入力…</target>
|
||||
@@ -2153,6 +2262,10 @@ This cannot be undone!</source>
|
||||
<target>メンバー追加にエラー発生</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error allowing contact PQ encryption" xml:space="preserve">
|
||||
<source>Error allowing contact PQ encryption</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing address" xml:space="preserve">
|
||||
<source>Error changing address</source>
|
||||
<target>アドレス変更にエラー発生</target>
|
||||
@@ -2242,6 +2355,10 @@ This cannot be undone!</source>
|
||||
<target>ユーザのプロフィール削除にエラー発生</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error downloading the archive" xml:space="preserve">
|
||||
<source>Error downloading the archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
|
||||
<source>Error enabling delivery receipts!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2315,6 +2432,10 @@ This cannot be undone!</source>
|
||||
<target>キーチェーンにパスフレーズを保存にエラー発生</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving settings" xml:space="preserve">
|
||||
<source>Error saving settings</source>
|
||||
<note>when migrating</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving user password" xml:space="preserve">
|
||||
<source>Error saving user password</source>
|
||||
<target>ユーザーパスワード保存エラー</target>
|
||||
@@ -2383,6 +2504,14 @@ This cannot be undone!</source>
|
||||
<target>ユーザープライバシーの更新のエラー</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error uploading the archive" xml:space="preserve">
|
||||
<source>Error uploading the archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
|
||||
<source>Error verifying passphrase:</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error: " xml:space="preserve">
|
||||
<source>Error: </source>
|
||||
<target>エラー : </target>
|
||||
@@ -2432,6 +2561,10 @@ This cannot be undone!</source>
|
||||
<target>データベースのアーカイブをエクスポートします。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
|
||||
<source>Exported file doesn't exist</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exporting database archive…" xml:space="preserve">
|
||||
<source>Exporting database archive…</source>
|
||||
<target>データベース アーカイブをエクスポートしています…</target>
|
||||
@@ -2491,6 +2624,10 @@ This cannot be undone!</source>
|
||||
<target>このグループでは、ファイルとメディアは禁止されています。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media not allowed" xml:space="preserve">
|
||||
<source>Files and media not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media prohibited!" xml:space="preserve">
|
||||
<source>Files and media prohibited!</source>
|
||||
<target>ファイルとメディアは禁止されています!</target>
|
||||
@@ -2501,6 +2638,14 @@ This cannot be undone!</source>
|
||||
<target>未読とお気に入りをフィルターします。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration" xml:space="preserve">
|
||||
<source>Finalize migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration on another device." xml:space="preserve">
|
||||
<source>Finalize migration on another device.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
|
||||
<source>Finally, we have them! 🚀</source>
|
||||
<target>ついに、私たちはそれらを手に入れました! 🚀</target>
|
||||
@@ -2546,6 +2691,18 @@ This cannot be undone!</source>
|
||||
<target>コンソール</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forward" xml:space="preserve">
|
||||
<source>Forward</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded" xml:space="preserve">
|
||||
<source>Forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded from" xml:space="preserve">
|
||||
<source>Forwarded from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Found desktop" xml:space="preserve">
|
||||
<source>Found desktop</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2652,6 +2809,10 @@ This cannot be undone!</source>
|
||||
<target>グループのメンバーがメッセージを完全削除することができます。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
|
||||
<source>Group members can send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send direct messages." xml:space="preserve">
|
||||
<source>Group members can send direct messages.</source>
|
||||
<target>グループのメンバーがダイレクトメッセージを送信できます。</target>
|
||||
@@ -2786,6 +2947,10 @@ This cannot be undone!</source>
|
||||
<target>自分のサーバの使い方</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Hungarian interface" xml:space="preserve">
|
||||
<source>Hungarian interface</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
|
||||
<source>ICE servers (one per line)</source>
|
||||
<target>ICEサーバ (1行に1サーバ)</target>
|
||||
@@ -2851,6 +3016,14 @@ This cannot be undone!</source>
|
||||
<target>データベースを読み込む</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import failed" xml:space="preserve">
|
||||
<source>Import failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Importing archive" xml:space="preserve">
|
||||
<source>Importing archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved message delivery" xml:space="preserve">
|
||||
<source>Improved message delivery</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2865,6 +3038,10 @@ This cannot be undone!</source>
|
||||
<target>サーバ設定の向上</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
|
||||
<source>In order to continue, chat should be stopped.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In reply to" xml:space="preserve">
|
||||
<source>In reply to</source>
|
||||
<target>返信先</target>
|
||||
@@ -2972,6 +3149,10 @@ This cannot be undone!</source>
|
||||
<source>Invalid link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
|
||||
<source>Invalid migration confirmation</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid name!" xml:space="preserve">
|
||||
<source>Invalid name!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -3326,6 +3507,10 @@ This is your link for group %@!</source>
|
||||
<target>メッセージ内容</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Message too large" xml:space="preserve">
|
||||
<source>Message too large</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages" xml:space="preserve">
|
||||
<source>Messages</source>
|
||||
<target>メッセージ</target>
|
||||
@@ -3340,11 +3525,47 @@ This is your link for group %@!</source>
|
||||
<source>Messages from %@ will be shown!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate device" xml:space="preserve">
|
||||
<source>Migrate device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate from another device" xml:space="preserve">
|
||||
<source>Migrate from another device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate here" xml:space="preserve">
|
||||
<source>Migrate here</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device" xml:space="preserve">
|
||||
<source>Migrate to another device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
|
||||
<source>Migrate to another device via QR code.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating" xml:space="preserve">
|
||||
<source>Migrating</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating database archive…" xml:space="preserve">
|
||||
<source>Migrating database archive…</source>
|
||||
<target>データベースのアーカイブを移行しています…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration complete" xml:space="preserve">
|
||||
<source>Migration complete</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration error:" xml:space="preserve">
|
||||
<source>Migration error:</source>
|
||||
<target>移行エラー:</target>
|
||||
@@ -3420,6 +3641,10 @@ This is your link for group %@!</source>
|
||||
<target>ネットワークとサーバ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network connection" xml:space="preserve">
|
||||
<source>Network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network settings" xml:space="preserve">
|
||||
<source>Network settings</source>
|
||||
<target>ネットワーク設定</target>
|
||||
@@ -3529,6 +3754,10 @@ This is your link for group %@!</source>
|
||||
<target>履歴はありません</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No network connection" xml:space="preserve">
|
||||
<source>No network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No permission to record voice message" xml:space="preserve">
|
||||
<source>No permission to record voice message</source>
|
||||
<target>音声メッセージを録音する権限がありません</target>
|
||||
@@ -3700,6 +3929,10 @@ This is your link for group %@!</source>
|
||||
<source>Open group</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open migration to another device" xml:space="preserve">
|
||||
<source>Open migration to another device</source>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open user profiles" xml:space="preserve">
|
||||
<source>Open user profiles</source>
|
||||
<target>ユーザープロフィールを開く</target>
|
||||
@@ -3714,14 +3947,26 @@ This is your link for group %@!</source>
|
||||
<source>Opening app…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or paste archive link" xml:space="preserve">
|
||||
<source>Or paste archive link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or scan QR code" xml:space="preserve">
|
||||
<source>Or scan QR code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or securely share this file link" xml:space="preserve">
|
||||
<source>Or securely share this file link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or show this code" xml:space="preserve">
|
||||
<source>Or show this code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Other" xml:space="preserve">
|
||||
<source>Other</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PING count" xml:space="preserve">
|
||||
<source>PING count</source>
|
||||
<target>PING回数</target>
|
||||
@@ -3798,6 +4043,10 @@ This is your link for group %@!</source>
|
||||
<target>永続的な復号化エラー</target>
|
||||
<note>message decrypt error item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
|
||||
<source>Picture-in-picture calls</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
|
||||
<source>Please ask your contact to enable sending voice messages.</source>
|
||||
<target>音声メッセージを有効にするように連絡相手に要求してください。</target>
|
||||
@@ -3818,6 +4067,10 @@ This is your link for group %@!</source>
|
||||
<target>あなたと連絡先の設定を確認してください。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
|
||||
<source>Please confirm that network settings are correct for this device.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please contact developers. Error: %@" xml:space="preserve">
|
||||
<source>Please contact developers.
|
||||
Error: %@</source>
|
||||
@@ -3873,6 +4126,10 @@ Error: %@</source>
|
||||
<target>サーバアドレスの証明証IDが正しくないかもしれません</target>
|
||||
<note>server test error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Post-quantum E2EE" xml:space="preserve">
|
||||
<source>Post-quantum E2EE</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
|
||||
<source>Preserve the last message draft, with attachments.</source>
|
||||
<target>添付を含めて、下書きを保存する。</target>
|
||||
@@ -3960,6 +4217,10 @@ Error: %@</source>
|
||||
<target>メッセージへのリアクションは禁止されています。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
|
||||
<source>Prohibit sending SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
|
||||
<source>Prohibit sending direct messages to members.</source>
|
||||
<target>メンバー間のダイレクトメッセージを使用禁止にする。</target>
|
||||
@@ -4005,6 +4266,14 @@ Error: %@</source>
|
||||
<target>プッシュ通知</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Push server" xml:space="preserve">
|
||||
<source>Push server</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
|
||||
<source>Quantum resistant encryption</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Rate the app" xml:space="preserve">
|
||||
<source>Rate the app</source>
|
||||
<target>アプリを評価</target>
|
||||
@@ -4078,6 +4347,10 @@ Error: %@</source>
|
||||
<target>開発中の機能です!相手のクライアントが4.2でなければ機能しません。アドレス変更が完了すると、会話にメッセージが出ます。連絡相手 (またはグループのメンバー) からメッセージを受信できないかをご確認ください。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving concurrency" xml:space="preserve">
|
||||
<source>Receiving concurrency</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
|
||||
<source>Receiving file will be stopped.</source>
|
||||
<target>ファイルの受信を停止します。</target>
|
||||
@@ -4092,6 +4365,10 @@ Error: %@</source>
|
||||
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
|
||||
<source>Recipient(s) can't see who this message is from.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipients see updates as you type them." xml:space="preserve">
|
||||
<source>Recipients see updates as you type them.</source>
|
||||
<target>受信者には、入力時に更新内容が表示されます。</target>
|
||||
@@ -4186,10 +4463,22 @@ Error: %@</source>
|
||||
<source>Repeat connection request?</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat download" xml:space="preserve">
|
||||
<source>Repeat download</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat import" xml:space="preserve">
|
||||
<source>Repeat import</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat join request?" xml:space="preserve">
|
||||
<source>Repeat join request?</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat upload" xml:space="preserve">
|
||||
<source>Repeat upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply" xml:space="preserve">
|
||||
<source>Reply</source>
|
||||
<target>返信</target>
|
||||
@@ -4289,6 +4578,10 @@ Error: %@</source>
|
||||
<target>SMPサーバ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Safer groups" xml:space="preserve">
|
||||
<source>Safer groups</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Save" xml:space="preserve">
|
||||
<source>Save</source>
|
||||
<target>保存</target>
|
||||
@@ -4369,11 +4662,19 @@ Error: %@</source>
|
||||
<target>ウェルカムメッセージを保存しますか?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved" xml:space="preserve">
|
||||
<source>Saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
|
||||
<source>Saved WebRTC ICE servers will be removed</source>
|
||||
<target>保存されたWebRTC ICEサーバは削除されます</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved from" xml:space="preserve">
|
||||
<source>Saved from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved message" xml:space="preserve">
|
||||
<source>Saved message</source>
|
||||
<note>message info title</note>
|
||||
@@ -4640,6 +4941,10 @@ Error: %@</source>
|
||||
<target>パスコードを設定する</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase" xml:space="preserve">
|
||||
<source>Set passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase to export" xml:space="preserve">
|
||||
<source>Set passphrase to export</source>
|
||||
<target>暗証フレーズを設定してからエクスポート</target>
|
||||
@@ -4694,6 +4999,10 @@ Error: %@</source>
|
||||
<target>連絡先と共有する</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
<source>Show QR code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show calls in phone history" xml:space="preserve">
|
||||
<source>Show calls in phone history</source>
|
||||
<target>通話履歴を表示</target>
|
||||
@@ -4772,6 +5081,14 @@ Error: %@</source>
|
||||
<trans-unit id="SimpleX links" xml:space="preserve">
|
||||
<source>SimpleX links</source>
|
||||
<target>SimpleXリンク</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
|
||||
<source>SimpleX links are prohibited in this group.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
|
||||
<source>SimpleX links not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX one-time invitation" xml:space="preserve">
|
||||
@@ -4833,6 +5150,10 @@ Error: %@</source>
|
||||
<target>SimpleX を停止</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat" xml:space="preserve">
|
||||
<source>Stop chat</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat to enable database actions" xml:space="preserve">
|
||||
<source>Stop chat to enable database actions</source>
|
||||
<target>チャットを停止してデータベースアクションを有効にします</target>
|
||||
@@ -4873,6 +5194,10 @@ Error: %@</source>
|
||||
<target>アドレスの共有を停止しますか?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stopping chat" xml:space="preserve">
|
||||
<source>Stopping chat</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Submit" xml:space="preserve">
|
||||
<source>Submit</source>
|
||||
<target>送信</target>
|
||||
@@ -5115,6 +5440,14 @@ It can happen because of some bug or when the connection is compromised.</source
|
||||
<target>あなたのプロフィール、連絡先、メッセージ、ファイルが完全削除されます (※元に戻せません※)。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by end-to-end encryption.</source>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This device name" xml:space="preserve">
|
||||
<source>This device name</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -5393,11 +5726,19 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>アップグレードしてチャットを開く</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload failed" xml:space="preserve">
|
||||
<source>Upload failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload file" xml:space="preserve">
|
||||
<source>Upload file</source>
|
||||
<target>ファイルをアップロードする</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uploading archive" xml:space="preserve">
|
||||
<source>Uploading archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use .onion hosts" xml:space="preserve">
|
||||
<source>Use .onion hosts</source>
|
||||
<target>.onionホストを使う</target>
|
||||
@@ -5446,6 +5787,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>サーバを使う</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
<source>Use the app while in the call.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="User profile" xml:space="preserve">
|
||||
<source>User profile</source>
|
||||
<target>ユーザープロフィール</target>
|
||||
@@ -5478,6 +5823,14 @@ To connect, please ask your contact to create another connection link and check
|
||||
<source>Verify connections</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify database passphrase" xml:space="preserve">
|
||||
<source>Verify database passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify passphrase" xml:space="preserve">
|
||||
<source>Verify passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify security code" xml:space="preserve">
|
||||
<source>Verify security code</source>
|
||||
<target>セキュリティコードを確認</target>
|
||||
@@ -5536,6 +5889,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>このグループでは音声メッセージが使用禁止です。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages not allowed" xml:space="preserve">
|
||||
<source>Voice messages not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages prohibited!" xml:space="preserve">
|
||||
<source>Voice messages prohibited!</source>
|
||||
<target>音声メッセージは使用禁止です!</target>
|
||||
@@ -5565,6 +5922,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>ビデオ待機中</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
|
||||
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: you may lose some data!" xml:space="preserve">
|
||||
<source>Warning: you may lose some data!</source>
|
||||
<target>警告: 一部のデータが失われる可能性があります!</target>
|
||||
@@ -5585,6 +5946,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>ウェルカムメッセージ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Welcome message is too long" xml:space="preserve">
|
||||
<source>Welcome message is too long</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="What's new" xml:space="preserve">
|
||||
<source>What's new</source>
|
||||
<target>新着情報</target>
|
||||
@@ -5605,6 +5970,14 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>連絡相手にシークレットモードのプロフィールを共有すると、その連絡相手に招待されたグループでも同じプロフィールが使われます。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WiFi" xml:space="preserve">
|
||||
<source>WiFi</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wired ethernet" xml:space="preserve">
|
||||
<source>Wired ethernet</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="With encrypted files and media." xml:space="preserve">
|
||||
<source>With encrypted files and media.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -5638,6 +6011,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>あなた</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
|
||||
<source>You **must not** use the same database on two devices.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You accepted connection" xml:space="preserve">
|
||||
<source>You accepted connection</source>
|
||||
<target>接続を承認しました</target>
|
||||
@@ -5717,6 +6094,10 @@ Repeat join request?</source>
|
||||
<target>あとでアプリのプライバシーとセキュリティの設定から有効にすることができます。</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can give another try." xml:space="preserve">
|
||||
<source>You can give another try.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
|
||||
<source>You can hide or mute a user profile - swipe it to the right.</source>
|
||||
<target>ユーザープロファイルを右にスワイプすると、非表示またはミュートにすることができます。</target>
|
||||
@@ -6060,6 +6441,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
<target>管理者</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="admins" xml:space="preserve">
|
||||
<source>admins</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="agreeing encryption for %@…" xml:space="preserve">
|
||||
<source>agreeing encryption for %@…</source>
|
||||
<target>%@の暗号化に同意しています…</target>
|
||||
@@ -6070,6 +6455,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
<target>暗号化に同意しています…</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="all members" xml:space="preserve">
|
||||
<source>all members</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="always" xml:space="preserve">
|
||||
<source>always</source>
|
||||
<target>常に</target>
|
||||
@@ -6100,7 +6489,7 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked" xml:space="preserve">
|
||||
<source>blocked</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked %@" xml:space="preserve">
|
||||
<source>blocked %@</source>
|
||||
@@ -6108,7 +6497,7 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked by admin" xml:space="preserve">
|
||||
<source>blocked by admin</source>
|
||||
<note>blocked chat item</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bold" xml:space="preserve">
|
||||
<source>bold</source>
|
||||
@@ -6392,6 +6781,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
<target>イベント発生</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="forwarded" xml:space="preserve">
|
||||
<source>forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="group deleted" xml:space="preserve">
|
||||
<source>group deleted</source>
|
||||
<target>グループ削除済み</target>
|
||||
@@ -6534,7 +6927,7 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
<trans-unit id="moderated by %@" xml:space="preserve">
|
||||
<source>moderated by %@</source>
|
||||
<target>%@ によってモデレートされた</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="months" xml:space="preserve">
|
||||
<source>months</source>
|
||||
@@ -6598,11 +6991,19 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
<target>オーナー</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="owners" xml:space="preserve">
|
||||
<source>owners</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="peer-to-peer" xml:space="preserve">
|
||||
<source>peer-to-peer</source>
|
||||
<target>P2P</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
|
||||
<source>quantum resistant e2e encryption</source>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="received answer…" xml:space="preserve">
|
||||
<source>received answer…</source>
|
||||
<target>回答を受け取りました…</target>
|
||||
@@ -6641,6 +7042,14 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
<target>あなたを除名しました</target>
|
||||
<note>rcv group event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved" xml:space="preserve">
|
||||
<source>saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved from %@" xml:space="preserve">
|
||||
<source>saved from %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sec" xml:space="preserve">
|
||||
<source>sec</source>
|
||||
<target>秒</target>
|
||||
@@ -6673,6 +7082,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
<source>set new profile picture</source>
|
||||
<note>profile update event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
|
||||
<source>standard end-to-end encryption</source>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="starting…" xml:space="preserve">
|
||||
<source>starting…</source>
|
||||
<target>接続中…</target>
|
||||
@@ -6769,6 +7182,10 @@ SimpleX サーバーはあなたのプロファイルを参照できません。
|
||||
<target>はい</target>
|
||||
<note>pref value</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you" xml:space="preserve">
|
||||
<source>you</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you are invited to group" xml:space="preserve">
|
||||
<source>you are invited to group</source>
|
||||
<target>グループ招待が届きました</target>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -107,6 +107,11 @@
|
||||
<target>%@ połączony</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ downloaded" xml:space="preserve">
|
||||
<source>%@ downloaded</source>
|
||||
<target>%@ pobrane</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve">
|
||||
<source>%@ is connected!</source>
|
||||
<target>%@ jest połączony!</target>
|
||||
@@ -127,6 +132,11 @@
|
||||
<target>%@ serwery</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ uploaded" xml:space="preserve">
|
||||
<source>%@ uploaded</source>
|
||||
<target>%@ wgrane</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve">
|
||||
<source>%@ wants to connect!</source>
|
||||
<target>%@ chce się połączyć!</target>
|
||||
@@ -342,6 +352,11 @@
|
||||
<target>**Najbardziej prywatny**: nie korzystaj z serwera powiadomień SimpleX Chat, sprawdzaj wiadomości okresowo w tle (zależy jak często korzystasz z aplikacji).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
|
||||
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
|
||||
<target>*Uwaga*: używanie tej samej bazy danych na dwóch urządzeniach zepsuje odszyfrowywanie wiadomości twoich połączeń, jako zabezpieczenie.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
|
||||
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
|
||||
<target>**Uwaga**: NIE będziesz w stanie odzyskać lub zmienić hasła, jeśli je stracisz.</target>
|
||||
@@ -357,6 +372,11 @@
|
||||
<target>**Uwaga**: Natychmiastowe powiadomienia push wymagają hasła zapisanego w Keychain.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
|
||||
<source>**Warning**: the archive will be removed.</source>
|
||||
<target>**Ostrzeżenie**: archiwum zostanie usunięte.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
|
||||
<source>**e2e encrypted** audio call</source>
|
||||
<target>**szyfrowane e2e** połączenie audio</target>
|
||||
@@ -613,6 +633,11 @@
|
||||
<target>Zmiana adresu zostanie przerwana. Użyty zostanie stary adres odbiorczy.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can block a member for all." xml:space="preserve">
|
||||
<source>Admins can block a member for all.</source>
|
||||
<target>Administratorzy mogą blokować członka dla wszystkich.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
|
||||
<source>Admins can create the links to join groups.</source>
|
||||
<target>Administratorzy mogą tworzyć linki do dołączania do grup.</target>
|
||||
@@ -668,6 +693,11 @@
|
||||
<target>Wszystkie Twoje kontakty pozostaną połączone. Aktualizacja profilu zostanie wysłana do Twoich kontaktów.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
|
||||
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
|
||||
<target>Wszystkie twoje kontakty, konwersacje i pliki będą bezpiecznie szyfrowane i wgrywane w kawałkach do skonfigurowanych przekaźników XFTP.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow" xml:space="preserve">
|
||||
<source>Allow</source>
|
||||
<target>Pozwól</target>
|
||||
@@ -713,6 +743,10 @@
|
||||
<target>Zezwól na nieodwracalne usunięcie wysłanych wiadomości. (24 godziny)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
|
||||
<source>Allow to send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send files and media." xml:space="preserve">
|
||||
<source>Allow to send files and media.</source>
|
||||
<target>Pozwól na wysyłanie plików i mediów.</target>
|
||||
@@ -793,6 +827,11 @@
|
||||
<target>Kompilacja aplikacji: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App data migration" xml:space="preserve">
|
||||
<source>App data migration</source>
|
||||
<target>Migracja danych aplikacji</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
|
||||
<source>App encrypts new local files (except videos).</source>
|
||||
<target>Aplikacja szyfruje nowe lokalne pliki (bez filmów).</target>
|
||||
@@ -828,6 +867,21 @@
|
||||
<target>Wygląd</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Apply" xml:space="preserve">
|
||||
<source>Apply</source>
|
||||
<target>Zastosuj</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archive and upload" xml:space="preserve">
|
||||
<source>Archive and upload</source>
|
||||
<target>Archiwizuj i prześlij</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archiving database" xml:space="preserve">
|
||||
<source>Archiving database</source>
|
||||
<target>Archiwizowanie bazy danych</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<source>Attach</source>
|
||||
<target>Dołącz</target>
|
||||
@@ -1018,6 +1072,11 @@
|
||||
<target>Anuluj</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cancel migration" xml:space="preserve">
|
||||
<source>Cancel migration</source>
|
||||
<target>Anuluj migrację</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
|
||||
<source>Cannot access keychain to save database password</source>
|
||||
<target>Nie można uzyskać dostępu do pęku kluczy, aby zapisać hasło do bazy danych</target>
|
||||
@@ -1028,6 +1087,10 @@
|
||||
<target>Nie można odebrać pliku</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cellular" xml:space="preserve">
|
||||
<source>Cellular</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Change" xml:space="preserve">
|
||||
<source>Change</source>
|
||||
<target>Zmień</target>
|
||||
@@ -1119,6 +1182,11 @@
|
||||
<target>Czat został zatrzymany. Jeśli korzystałeś już z tej bazy danych na innym urządzeniu, powinieneś przenieść ją z powrotem przed rozpoczęciem czatu.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat migrated!" xml:space="preserve">
|
||||
<source>Chat migrated!</source>
|
||||
<target>Czat zmigrowany!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat preferences" xml:space="preserve">
|
||||
<source>Chat preferences</source>
|
||||
<target>Preferencje czatu</target>
|
||||
@@ -1139,6 +1207,11 @@
|
||||
<target>Chiński i hiszpański interfejs</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
|
||||
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
|
||||
<target>Wybierz _Zmigruj z innego urządzenia_ na nowym urządzeniu i zeskanuj kod QR.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose file" xml:space="preserve">
|
||||
<source>Choose file</source>
|
||||
<target>Wybierz plik</target>
|
||||
@@ -1209,6 +1282,11 @@
|
||||
<target>Potwierdź aktualizacje bazy danych</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm network settings" xml:space="preserve">
|
||||
<source>Confirm network settings</source>
|
||||
<target>Potwierdź ustawienia sieciowe</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm new passphrase…" xml:space="preserve">
|
||||
<source>Confirm new passphrase…</source>
|
||||
<target>Potwierdź nowe hasło…</target>
|
||||
@@ -1219,6 +1297,16 @@
|
||||
<target>Potwierdź hasło</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
|
||||
<source>Confirm that you remember database passphrase to migrate it.</source>
|
||||
<target>Potwierdź, że pamiętasz hasło do bazy danych, aby ją zmigrować.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm upload" xml:space="preserve">
|
||||
<source>Confirm upload</source>
|
||||
<target>Potwierdź wgranie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Connect" xml:space="preserve">
|
||||
<source>Connect</source>
|
||||
<target>Połącz</target>
|
||||
@@ -1478,6 +1566,11 @@ To jest twój jednorazowy link!</target>
|
||||
<target>Utworzony w dniu %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating archive link" xml:space="preserve">
|
||||
<source>Creating archive link</source>
|
||||
<target>Tworzenie linku archiwum</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating link…" xml:space="preserve">
|
||||
<source>Creating link…</source>
|
||||
<target>Tworzenie linku…</target>
|
||||
@@ -1698,6 +1791,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Usuń bazę danych</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete database from this device" xml:space="preserve">
|
||||
<source>Delete database from this device</source>
|
||||
<target>Usuń bazę danych z tego urządzenia</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete file" xml:space="preserve">
|
||||
<source>Delete file</source>
|
||||
<target>Usuń plik</target>
|
||||
@@ -1988,11 +2086,30 @@ To nie może być cofnięte!</target>
|
||||
<target>Obniż wersję i otwórz czat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download" xml:space="preserve">
|
||||
<source>Download</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download failed" xml:space="preserve">
|
||||
<source>Download failed</source>
|
||||
<target>Pobieranie nie udane</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download file" xml:space="preserve">
|
||||
<source>Download file</source>
|
||||
<target>Pobierz plik</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading archive" xml:space="preserve">
|
||||
<source>Downloading archive</source>
|
||||
<target>Pobieranie archiwum</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading link details" xml:space="preserve">
|
||||
<source>Downloading link details</source>
|
||||
<target>Pobieranie szczegółów linku</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duplicate display name!" xml:space="preserve">
|
||||
<source>Duplicate display name!</source>
|
||||
<target>Zduplikowana wyświetlana nazwa!</target>
|
||||
@@ -2048,6 +2165,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Włącz dla wszystkich</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
|
||||
<source>Enable in direct chats (BETA)!</source>
|
||||
<target>Włącz w czatach bezpośrednich (BETA)!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable instant notifications?" xml:space="preserve">
|
||||
<source>Enable instant notifications?</source>
|
||||
<target>Włączyć natychmiastowe powiadomienia?</target>
|
||||
@@ -2078,6 +2200,10 @@ To nie może być cofnięte!</target>
|
||||
<target>Włącz pin samodestrukcji</target>
|
||||
<note>set passcode view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled for" xml:space="preserve">
|
||||
<source>Enabled for</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt" xml:space="preserve">
|
||||
<source>Encrypt</source>
|
||||
<target>Szyfruj</target>
|
||||
@@ -2163,6 +2289,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Wpisz nazwę grupy…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase" xml:space="preserve">
|
||||
<source>Enter passphrase</source>
|
||||
<target>Wprowadź hasło</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve">
|
||||
<source>Enter passphrase…</source>
|
||||
<target>Wprowadź hasło…</target>
|
||||
@@ -2223,6 +2354,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Błąd dodawania członka(ów)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error allowing contact PQ encryption" xml:space="preserve">
|
||||
<source>Error allowing contact PQ encryption</source>
|
||||
<target>Błąd pozwalania kontaktowi na szyfrowanie PQ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing address" xml:space="preserve">
|
||||
<source>Error changing address</source>
|
||||
<target>Błąd zmiany adresu</target>
|
||||
@@ -2313,6 +2449,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Błąd usuwania profilu użytkownika</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error downloading the archive" xml:space="preserve">
|
||||
<source>Error downloading the archive</source>
|
||||
<target>Błąd pobierania archiwum</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
|
||||
<source>Error enabling delivery receipts!</source>
|
||||
<target>Błąd włączania potwierdzeń dostawy!</target>
|
||||
@@ -2388,6 +2529,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Błąd zapisu hasła do pęku kluczy</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving settings" xml:space="preserve">
|
||||
<source>Error saving settings</source>
|
||||
<target>Błąd zapisywania ustawień</target>
|
||||
<note>when migrating</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving user password" xml:space="preserve">
|
||||
<source>Error saving user password</source>
|
||||
<target>Błąd zapisu hasła użytkownika</target>
|
||||
@@ -2458,6 +2604,16 @@ To nie może być cofnięte!</target>
|
||||
<target>Błąd aktualizacji prywatności użytkownika</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error uploading the archive" xml:space="preserve">
|
||||
<source>Error uploading the archive</source>
|
||||
<target>Błąd wgrywania archiwum</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
|
||||
<source>Error verifying passphrase:</source>
|
||||
<target>Błąd weryfikowania hasła:</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error: " xml:space="preserve">
|
||||
<source>Error: </source>
|
||||
<target>Błąd: </target>
|
||||
@@ -2508,6 +2664,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Wyeksportowane archiwum bazy danych.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
|
||||
<source>Exported file doesn't exist</source>
|
||||
<target>Wyeksportowany plik nie istnieje</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exporting database archive…" xml:space="preserve">
|
||||
<source>Exporting database archive…</source>
|
||||
<target>Eksportowanie archiwum bazy danych…</target>
|
||||
@@ -2568,6 +2729,10 @@ To nie może być cofnięte!</target>
|
||||
<target>Pliki i media są zabronione w tej grupie.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media not allowed" xml:space="preserve">
|
||||
<source>Files and media not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media prohibited!" xml:space="preserve">
|
||||
<source>Files and media prohibited!</source>
|
||||
<target>Pliki i media zabronione!</target>
|
||||
@@ -2578,6 +2743,16 @@ To nie może być cofnięte!</target>
|
||||
<target>Filtruj nieprzeczytane i ulubione czaty.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration" xml:space="preserve">
|
||||
<source>Finalize migration</source>
|
||||
<target>Dokończ migrację</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration on another device." xml:space="preserve">
|
||||
<source>Finalize migration on another device.</source>
|
||||
<target>Dokończ migrację na innym urządzeniu.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
|
||||
<source>Finally, we have them! 🚀</source>
|
||||
<target>W końcu je mamy! 🚀</target>
|
||||
@@ -2623,6 +2798,18 @@ To nie może być cofnięte!</target>
|
||||
<target>Dla konsoli</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forward" xml:space="preserve">
|
||||
<source>Forward</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded" xml:space="preserve">
|
||||
<source>Forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded from" xml:space="preserve">
|
||||
<source>Forwarded from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Found desktop" xml:space="preserve">
|
||||
<source>Found desktop</source>
|
||||
<target>Znaleziono komputer</target>
|
||||
@@ -2733,6 +2920,10 @@ To nie może być cofnięte!</target>
|
||||
<target>Członkowie grupy mogą nieodwracalnie usuwać wysłane wiadomości. (24 godziny)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
|
||||
<source>Group members can send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send direct messages." xml:space="preserve">
|
||||
<source>Group members can send direct messages.</source>
|
||||
<target>Członkowie grupy mogą wysyłać bezpośrednie wiadomości.</target>
|
||||
@@ -2868,6 +3059,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Jak korzystać z Twoich serwerów</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Hungarian interface" xml:space="preserve">
|
||||
<source>Hungarian interface</source>
|
||||
<target>Węgierski interfejs</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
|
||||
<source>ICE servers (one per line)</source>
|
||||
<target>Serwery ICE (po jednym na linię)</target>
|
||||
@@ -2933,6 +3129,16 @@ To nie może być cofnięte!</target>
|
||||
<target>Importuj bazę danych</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import failed" xml:space="preserve">
|
||||
<source>Import failed</source>
|
||||
<target>Import nie udał się</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Importing archive" xml:space="preserve">
|
||||
<source>Importing archive</source>
|
||||
<target>Importowanie archiwum</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved message delivery" xml:space="preserve">
|
||||
<source>Improved message delivery</source>
|
||||
<target>Ulepszona dostawa wiadomości</target>
|
||||
@@ -2948,6 +3154,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Ulepszona konfiguracja serwera</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
|
||||
<source>In order to continue, chat should be stopped.</source>
|
||||
<target>Aby konturować, czat musi zostać zatrzymany.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In reply to" xml:space="preserve">
|
||||
<source>In reply to</source>
|
||||
<target>W odpowiedzi na</target>
|
||||
@@ -3060,6 +3271,11 @@ To nie może być cofnięte!</target>
|
||||
<target>Nieprawidłowy link</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
|
||||
<source>Invalid migration confirmation</source>
|
||||
<target>Nieprawidłowe potwierdzenie migracji</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid name!" xml:space="preserve">
|
||||
<source>Invalid name!</source>
|
||||
<target>Nieprawidłowa nazwa!</target>
|
||||
@@ -3428,6 +3644,11 @@ To jest twój link do grupy %@!</target>
|
||||
<target>Tekst wiadomości</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Message too large" xml:space="preserve">
|
||||
<source>Message too large</source>
|
||||
<target>Wiadomość jest zbyt duża</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages" xml:space="preserve">
|
||||
<source>Messages</source>
|
||||
<target>Wiadomości</target>
|
||||
@@ -3443,11 +3664,56 @@ To jest twój link do grupy %@!</target>
|
||||
<target>Wiadomości od %@ zostaną pokazane!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<target>Wiadomości, pliki i połączenia są chronione przez **szyfrowanie end-to-end** z doskonałym utajnianiem z wyprzedzeniem i odzyskiem po złamaniu.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<target>Wiadomości, pliki i połączenia są chronione przez **kwantowo odporne szyfrowanie end-to-end** z doskonałym utajnianiem z wyprzedzeniem i odzyskiem po złamaniu.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate device" xml:space="preserve">
|
||||
<source>Migrate device</source>
|
||||
<target>Zmigruj urządzenie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate from another device" xml:space="preserve">
|
||||
<source>Migrate from another device</source>
|
||||
<target>Zmigruj z innego urządzenia</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate here" xml:space="preserve">
|
||||
<source>Migrate here</source>
|
||||
<target>Zmigruj tutaj</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device" xml:space="preserve">
|
||||
<source>Migrate to another device</source>
|
||||
<target>Zmigruj do innego urządzenia</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
|
||||
<source>Migrate to another device via QR code.</source>
|
||||
<target>Zmigruj do innego urządzenia przez kod QR.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating" xml:space="preserve">
|
||||
<source>Migrating</source>
|
||||
<target>Migrowanie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating database archive…" xml:space="preserve">
|
||||
<source>Migrating database archive…</source>
|
||||
<target>Migrowanie archiwum bazy danych…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration complete" xml:space="preserve">
|
||||
<source>Migration complete</source>
|
||||
<target>Migracja zakończona</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration error:" xml:space="preserve">
|
||||
<source>Migration error:</source>
|
||||
<target>Błąd migracji:</target>
|
||||
@@ -3523,6 +3789,10 @@ To jest twój link do grupy %@!</target>
|
||||
<target>Sieć i serwery</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network connection" xml:space="preserve">
|
||||
<source>Network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network settings" xml:space="preserve">
|
||||
<source>Network settings</source>
|
||||
<target>Ustawienia sieci</target>
|
||||
@@ -3633,6 +3903,10 @@ To jest twój link do grupy %@!</target>
|
||||
<target>Brak historii</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No network connection" xml:space="preserve">
|
||||
<source>No network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No permission to record voice message" xml:space="preserve">
|
||||
<source>No permission to record voice message</source>
|
||||
<target>Brak uprawnień do nagrywania wiadomości głosowej</target>
|
||||
@@ -3807,6 +4081,11 @@ To jest twój link do grupy %@!</target>
|
||||
<target>Grupa otwarta</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open migration to another device" xml:space="preserve">
|
||||
<source>Open migration to another device</source>
|
||||
<target>Otwórz migrację na innym urządzeniu</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open user profiles" xml:space="preserve">
|
||||
<source>Open user profiles</source>
|
||||
<target>Otwórz profile użytkownika</target>
|
||||
@@ -3822,16 +4101,30 @@ To jest twój link do grupy %@!</target>
|
||||
<target>Otwieranie aplikacji…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or paste archive link" xml:space="preserve">
|
||||
<source>Or paste archive link</source>
|
||||
<target>Lub wklej link archiwum</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or scan QR code" xml:space="preserve">
|
||||
<source>Or scan QR code</source>
|
||||
<target>Lub zeskanuj kod QR</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or securely share this file link" xml:space="preserve">
|
||||
<source>Or securely share this file link</source>
|
||||
<target>Lub bezpiecznie udostępnij ten link pliku</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or show this code" xml:space="preserve">
|
||||
<source>Or show this code</source>
|
||||
<target>Lub pokaż ten kod</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Other" xml:space="preserve">
|
||||
<source>Other</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PING count" xml:space="preserve">
|
||||
<source>PING count</source>
|
||||
<target>Liczba PINGÓW</target>
|
||||
@@ -3912,6 +4205,11 @@ To jest twój link do grupy %@!</target>
|
||||
<target>Stały błąd odszyfrowania</target>
|
||||
<note>message decrypt error item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
|
||||
<source>Picture-in-picture calls</source>
|
||||
<target>Połączenia obraz-w-obrazie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
|
||||
<source>Please ask your contact to enable sending voice messages.</source>
|
||||
<target>Poproś Twój kontakt o włączenie wysyłania wiadomości głosowych.</target>
|
||||
@@ -3932,6 +4230,11 @@ To jest twój link do grupy %@!</target>
|
||||
<target>Proszę sprawdzić preferencje Twoje i Twojego kontaktu.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
|
||||
<source>Please confirm that network settings are correct for this device.</source>
|
||||
<target>Proszę potwierdzić, że ustawienia sieciowe są prawidłowe dla tego urządzenia.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please contact developers. Error: %@" xml:space="preserve">
|
||||
<source>Please contact developers.
|
||||
Error: %@</source>
|
||||
@@ -3989,6 +4292,11 @@ Błąd: %@</target>
|
||||
<target>Możliwe, że odcisk palca certyfikatu w adresie serwera jest nieprawidłowy</target>
|
||||
<note>server test error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Post-quantum E2EE" xml:space="preserve">
|
||||
<source>Post-quantum E2EE</source>
|
||||
<target>Postkwantowe E2EE</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
|
||||
<source>Preserve the last message draft, with attachments.</source>
|
||||
<target>Zachowaj ostatnią wersję roboczą wiadomości wraz z załącznikami.</target>
|
||||
@@ -4079,6 +4387,10 @@ Błąd: %@</target>
|
||||
<target>Zabroń reakcje wiadomości.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
|
||||
<source>Prohibit sending SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
|
||||
<source>Prohibit sending direct messages to members.</source>
|
||||
<target>Zabroń wysyłania bezpośrednich wiadomości do członków.</target>
|
||||
@@ -4124,6 +4436,16 @@ Błąd: %@</target>
|
||||
<target>Powiadomienia push</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Push server" xml:space="preserve">
|
||||
<source>Push server</source>
|
||||
<target>Serwer Push</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
|
||||
<source>Quantum resistant encryption</source>
|
||||
<target>Kwantowo odporne szyfrowanie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Rate the app" xml:space="preserve">
|
||||
<source>Rate the app</source>
|
||||
<target>Oceń aplikację</target>
|
||||
@@ -4199,6 +4521,10 @@ Błąd: %@</target>
|
||||
<target>Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving concurrency" xml:space="preserve">
|
||||
<source>Receiving concurrency</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
|
||||
<source>Receiving file will be stopped.</source>
|
||||
<target>Odbieranie pliku zostanie przerwane.</target>
|
||||
@@ -4214,6 +4540,10 @@ Błąd: %@</target>
|
||||
<target>Ostania historia i ulepszony [bot adresowy](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
|
||||
<source>Recipient(s) can't see who this message is from.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipients see updates as you type them." xml:space="preserve">
|
||||
<source>Recipients see updates as you type them.</source>
|
||||
<target>Odbiorcy widzą aktualizacje podczas ich wpisywania.</target>
|
||||
@@ -4309,11 +4639,26 @@ Błąd: %@</target>
|
||||
<target>Powtórzyć prośbę połączenia?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat download" xml:space="preserve">
|
||||
<source>Repeat download</source>
|
||||
<target>Powtórz pobieranie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat import" xml:space="preserve">
|
||||
<source>Repeat import</source>
|
||||
<target>Powtórz importowanie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat join request?" xml:space="preserve">
|
||||
<source>Repeat join request?</source>
|
||||
<target>Powtórzyć prośbę dołączenia?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat upload" xml:space="preserve">
|
||||
<source>Repeat upload</source>
|
||||
<target>Powtórz wgrywanie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply" xml:space="preserve">
|
||||
<source>Reply</source>
|
||||
<target>Odpowiedz</target>
|
||||
@@ -4414,6 +4759,11 @@ Błąd: %@</target>
|
||||
<target>Serwery SMP</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Safer groups" xml:space="preserve">
|
||||
<source>Safer groups</source>
|
||||
<target>Bezpieczniejsze grupy</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Save" xml:space="preserve">
|
||||
<source>Save</source>
|
||||
<target>Zapisz</target>
|
||||
@@ -4494,11 +4844,19 @@ Błąd: %@</target>
|
||||
<target>Zapisać wiadomość powitalną?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved" xml:space="preserve">
|
||||
<source>Saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
|
||||
<source>Saved WebRTC ICE servers will be removed</source>
|
||||
<target>Zapisane serwery WebRTC ICE zostaną usunięte</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved from" xml:space="preserve">
|
||||
<source>Saved from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved message" xml:space="preserve">
|
||||
<source>Saved message</source>
|
||||
<target>Zachowano wiadomość</target>
|
||||
@@ -4779,6 +5137,11 @@ Błąd: %@</target>
|
||||
<target>Ustaw pin</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase" xml:space="preserve">
|
||||
<source>Set passphrase</source>
|
||||
<target>Ustaw hasło</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase to export" xml:space="preserve">
|
||||
<source>Set passphrase to export</source>
|
||||
<target>Ustaw hasło do eksportu</target>
|
||||
@@ -4834,6 +5197,11 @@ Błąd: %@</target>
|
||||
<target>Udostępnij kontaktom</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
<source>Show QR code</source>
|
||||
<target>Pokaż kod QR</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show calls in phone history" xml:space="preserve">
|
||||
<source>Show calls in phone history</source>
|
||||
<target>Pokaż połączenia w historii telefonu</target>
|
||||
@@ -4912,6 +5280,14 @@ Błąd: %@</target>
|
||||
<trans-unit id="SimpleX links" xml:space="preserve">
|
||||
<source>SimpleX links</source>
|
||||
<target>Linki SimpleX</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
|
||||
<source>SimpleX links are prohibited in this group.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
|
||||
<source>SimpleX links not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX one-time invitation" xml:space="preserve">
|
||||
@@ -4974,6 +5350,11 @@ Błąd: %@</target>
|
||||
<target>Zatrzymaj SimpleX</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat" xml:space="preserve">
|
||||
<source>Stop chat</source>
|
||||
<target>Zatrzymaj czat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat to enable database actions" xml:space="preserve">
|
||||
<source>Stop chat to enable database actions</source>
|
||||
<target>Zatrzymaj czat, aby umożliwić działania na bazie danych</target>
|
||||
@@ -5014,6 +5395,11 @@ Błąd: %@</target>
|
||||
<target>Przestać udostępniać adres?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stopping chat" xml:space="preserve">
|
||||
<source>Stopping chat</source>
|
||||
<target>Zatrzymywanie czatu</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Submit" xml:space="preserve">
|
||||
<source>Submit</source>
|
||||
<target>Zatwierdź</target>
|
||||
@@ -5261,6 +5647,16 @@ Może się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skom
|
||||
<target>Tego działania nie można cofnąć - Twój profil, kontakty, wiadomości i pliki zostaną nieodwracalnie utracone.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by end-to-end encryption.</source>
|
||||
<target>Ten czat jest chroniony przez szyfrowanie end-to-end.</target>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
|
||||
<target>Ten czat jest chroniony przez kwantowo odporne szyfrowanie end-to-end.</target>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This device name" xml:space="preserve">
|
||||
<source>This device name</source>
|
||||
<target>Nazwa tego urządzenia</target>
|
||||
@@ -5555,11 +5951,21 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<target>Zaktualizuj i otwórz czat</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload failed" xml:space="preserve">
|
||||
<source>Upload failed</source>
|
||||
<target>Wgrywanie nie udane</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload file" xml:space="preserve">
|
||||
<source>Upload file</source>
|
||||
<target>Prześlij plik</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uploading archive" xml:space="preserve">
|
||||
<source>Uploading archive</source>
|
||||
<target>Wgrywanie archiwum</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use .onion hosts" xml:space="preserve">
|
||||
<source>Use .onion hosts</source>
|
||||
<target>Użyj hostów .onion</target>
|
||||
@@ -5610,6 +6016,11 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<target>Użyj serwera</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
<source>Use the app while in the call.</source>
|
||||
<target>Używaj aplikacji podczas połączenia.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="User profile" xml:space="preserve">
|
||||
<source>User profile</source>
|
||||
<target>Profil użytkownika</target>
|
||||
@@ -5645,6 +6056,16 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<target>Zweryfikuj połączenia</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify database passphrase" xml:space="preserve">
|
||||
<source>Verify database passphrase</source>
|
||||
<target>Zweryfikuj hasło bazy danych</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify passphrase" xml:space="preserve">
|
||||
<source>Verify passphrase</source>
|
||||
<target>Zweryfikuj hasło</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify security code" xml:space="preserve">
|
||||
<source>Verify security code</source>
|
||||
<target>Weryfikuj kod bezpieczeństwa</target>
|
||||
@@ -5705,6 +6126,10 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<target>Wiadomości głosowe są zabronione w tej grupie.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages not allowed" xml:space="preserve">
|
||||
<source>Voice messages not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages prohibited!" xml:space="preserve">
|
||||
<source>Voice messages prohibited!</source>
|
||||
<target>Wiadomości głosowe zabronione!</target>
|
||||
@@ -5735,6 +6160,11 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<target>Oczekiwanie na film</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
|
||||
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
|
||||
<target>Ostrzeżenie: rozpoczęcie czatu na wielu urządzeniach nie jest wspierane i spowoduje niepowodzenia dostarczania wiadomości</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: you may lose some data!" xml:space="preserve">
|
||||
<source>Warning: you may lose some data!</source>
|
||||
<target>Uwaga: możesz stracić niektóre dane!</target>
|
||||
@@ -5755,6 +6185,11 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<target>Wiadomość powitalna</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Welcome message is too long" xml:space="preserve">
|
||||
<source>Welcome message is too long</source>
|
||||
<target>Wiadomość powitalna jest zbyt długa</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="What's new" xml:space="preserve">
|
||||
<source>What's new</source>
|
||||
<target>Co nowego</target>
|
||||
@@ -5775,6 +6210,14 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<target>Gdy udostępnisz komuś profil incognito, będzie on używany w grupach, do których Cię zaprosi.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WiFi" xml:space="preserve">
|
||||
<source>WiFi</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wired ethernet" xml:space="preserve">
|
||||
<source>Wired ethernet</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="With encrypted files and media." xml:space="preserve">
|
||||
<source>With encrypted files and media.</source>
|
||||
<target>Z zaszyfrowanymi plikami i multimediami.</target>
|
||||
@@ -5810,6 +6253,11 @@ Aby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połąc
|
||||
<target>Ty</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
|
||||
<source>You **must not** use the same database on two devices.</source>
|
||||
<target>**Nie możesz** używać tej samej bazy na dwóch urządzeniach.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You accepted connection" xml:space="preserve">
|
||||
<source>You accepted connection</source>
|
||||
<target>Zaakceptowałeś połączenie</target>
|
||||
@@ -5897,6 +6345,11 @@ Powtórzyć prośbę dołączenia?</target>
|
||||
<target>Możesz je włączyć później w ustawieniach Prywatności i Bezpieczeństwa aplikacji.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can give another try." xml:space="preserve">
|
||||
<source>You can give another try.</source>
|
||||
<target>Możesz spróbować ponownie.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
|
||||
<source>You can hide or mute a user profile - swipe it to the right.</source>
|
||||
<target>Możesz ukryć lub wyciszyć profil użytkownika - przesuń palcem w prawo.</target>
|
||||
@@ -6248,6 +6701,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<target>administrator</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="admins" xml:space="preserve">
|
||||
<source>admins</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="agreeing encryption for %@…" xml:space="preserve">
|
||||
<source>agreeing encryption for %@…</source>
|
||||
<target>uzgadnianie szyfrowania dla %@…</target>
|
||||
@@ -6258,6 +6715,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<target>uzgadnianie szyfrowania…</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="all members" xml:space="preserve">
|
||||
<source>all members</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="always" xml:space="preserve">
|
||||
<source>always</source>
|
||||
<target>zawsze</target>
|
||||
@@ -6291,7 +6752,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<trans-unit id="blocked" xml:space="preserve">
|
||||
<source>blocked</source>
|
||||
<target>zablokowany</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked %@" xml:space="preserve">
|
||||
<source>blocked %@</source>
|
||||
@@ -6301,7 +6762,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<trans-unit id="blocked by admin" xml:space="preserve">
|
||||
<source>blocked by admin</source>
|
||||
<target>zablokowany przez admina</target>
|
||||
<note>blocked chat item</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bold" xml:space="preserve">
|
||||
<source>bold</source>
|
||||
@@ -6588,6 +7049,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<target>nowe wydarzenie</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="forwarded" xml:space="preserve">
|
||||
<source>forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="group deleted" xml:space="preserve">
|
||||
<source>group deleted</source>
|
||||
<target>grupa usunięta</target>
|
||||
@@ -6731,7 +7196,7 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<trans-unit id="moderated by %@" xml:space="preserve">
|
||||
<source>moderated by %@</source>
|
||||
<target>moderowany przez %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="months" xml:space="preserve">
|
||||
<source>months</source>
|
||||
@@ -6795,11 +7260,20 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<target>właściciel</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="owners" xml:space="preserve">
|
||||
<source>owners</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="peer-to-peer" xml:space="preserve">
|
||||
<source>peer-to-peer</source>
|
||||
<target>peer-to-peer</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
|
||||
<source>quantum resistant e2e encryption</source>
|
||||
<target>kwantowo odporne szyfrowanie e2e</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="received answer…" xml:space="preserve">
|
||||
<source>received answer…</source>
|
||||
<target>otrzymano odpowiedź…</target>
|
||||
@@ -6840,6 +7314,14 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<target>usunął cię</target>
|
||||
<note>rcv group event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved" xml:space="preserve">
|
||||
<source>saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved from %@" xml:space="preserve">
|
||||
<source>saved from %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sec" xml:space="preserve">
|
||||
<source>sec</source>
|
||||
<target>sek</target>
|
||||
@@ -6875,6 +7357,11 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<target>ustaw nowe zdjęcie profilu</target>
|
||||
<note>profile update event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
|
||||
<source>standard end-to-end encryption</source>
|
||||
<target>standardowe szyfrowanie end-to-end</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="starting…" xml:space="preserve">
|
||||
<source>starting…</source>
|
||||
<target>uruchamianie…</target>
|
||||
@@ -6975,6 +7462,10 @@ Serwery SimpleX nie mogą zobaczyć Twojego profilu.</target>
|
||||
<target>tak</target>
|
||||
<note>pref value</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you" xml:space="preserve">
|
||||
<source>you</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you are invited to group" xml:space="preserve">
|
||||
<source>you are invited to group</source>
|
||||
<target>jesteś zaproszony do grupy</target>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is not verified" xml:space="preserve" approved="no">
|
||||
<source>%@ is not verified</source>
|
||||
<target state="translated">%@ não foi verificado</target>
|
||||
<target state="translated">%@ não foi verificado(a)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is verified" xml:space="preserve" approved="no">
|
||||
@@ -84,12 +84,12 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%d days" xml:space="preserve" approved="no">
|
||||
<source>%d days</source>
|
||||
<target state="translated">%d dia(s)</target>
|
||||
<target state="translated">%d dias</target>
|
||||
<note>message ttl</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d hours" xml:space="preserve" approved="no">
|
||||
<source>%d hours</source>
|
||||
<target state="translated">%d hora(s)</target>
|
||||
<target state="translated">%d horas</target>
|
||||
<note>message ttl</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d min" xml:space="preserve" approved="no">
|
||||
@@ -99,7 +99,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%d months" xml:space="preserve" approved="no">
|
||||
<source>%d months</source>
|
||||
<target state="translated">%d mês(es)</target>
|
||||
<target state="translated">%d meses</target>
|
||||
<note>message ttl</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d sec" xml:space="preserve" approved="no">
|
||||
@@ -109,7 +109,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="%d skipped message(s)" xml:space="preserve" approved="no">
|
||||
<source>%d skipped message(s)</source>
|
||||
<target state="translated">%d mensagem(ns) ignorada(s)</target>
|
||||
<target state="translated">%d mensagem(ns) omitida(s)</target>
|
||||
<note>integrity error chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld" xml:space="preserve" approved="no">
|
||||
@@ -5189,6 +5189,51 @@ Isso pode acontecer por causa de algum bug ou quando a conexão está comprometi
|
||||
<target state="translated">Desaparecerá: %@</target>
|
||||
<note>copied message info</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="# %@" xml:space="preserve" approved="no">
|
||||
<source># %@</source>
|
||||
<target state="translated"># %@</target>
|
||||
<note>copied message info title, # <title></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="## History" xml:space="preserve" approved="no">
|
||||
<source>## History</source>
|
||||
<target state="translated">## Histórico</target>
|
||||
<note>copied message info</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="## In reply to" xml:space="preserve" approved="no">
|
||||
<source>## In reply to</source>
|
||||
<target state="translated">## Em resposta a</target>
|
||||
<note>copied message info</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ connected" xml:space="preserve" approved="no">
|
||||
<source>%@ connected</source>
|
||||
<target state="translated">%@ conectado(a)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@, %@ and %lld members" xml:space="preserve" approved="no">
|
||||
<source>%@, %@ and %lld members</source>
|
||||
<target state="translated">%@, %@ e %lld membros</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ and %@ connected" xml:space="preserve" approved="no">
|
||||
<source>%@ and %@ connected</source>
|
||||
<target state="translated">%@ e %@ conectados</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve" approved="no">
|
||||
<source>%@, %@ and %lld other members connected</source>
|
||||
<target state="translated">%@, %@ e %lld e outros membros se conectaram</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ and %@" xml:space="preserve" approved="no">
|
||||
<source>%@ and %@</source>
|
||||
<target state="translated">%@ e %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ at %@:" xml:space="preserve" approved="no">
|
||||
<source>%1$@ at %2$@:</source>
|
||||
<target state="translated">%1$@ em %2$@:</target>
|
||||
<note>copied message info, <sender> at <time></note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="pt-BR" datatype="plaintext">
|
||||
|
||||
@@ -15,32 +15,39 @@
|
||||
Available in v5.1</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id=" " xml:space="preserve">
|
||||
<trans-unit id=" " xml:space="preserve" approved="no">
|
||||
<source> </source>
|
||||
<target state="translated"> </target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id=" " xml:space="preserve">
|
||||
<trans-unit id=" " xml:space="preserve" approved="no">
|
||||
<source> </source>
|
||||
<target state="translated"> </target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id=" " xml:space="preserve">
|
||||
<trans-unit id=" " xml:space="preserve" approved="no">
|
||||
<source> </source>
|
||||
<target state="translated"> </target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id=" (" xml:space="preserve">
|
||||
<trans-unit id=" (" xml:space="preserve" approved="no">
|
||||
<source> (</source>
|
||||
<target state="translated"> (</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id=" (can be copied)" xml:space="preserve">
|
||||
<trans-unit id=" (can be copied)" xml:space="preserve" approved="no">
|
||||
<source> (can be copied)</source>
|
||||
<target state="translated"> .(pode ser copiado)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="!1 colored!" xml:space="preserve">
|
||||
<trans-unit id="!1 colored!" xml:space="preserve" approved="no">
|
||||
<source>!1 colored!</source>
|
||||
<target state="translated">!1 colorido!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="#secret#" xml:space="preserve">
|
||||
<trans-unit id="#secret#" xml:space="preserve" approved="no">
|
||||
<source>#secret#</source>
|
||||
<target state="translated">#secreto#</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@" xml:space="preserve">
|
||||
@@ -55,48 +62,59 @@ Available in v5.1</source>
|
||||
<source>%@ / %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve">
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve" approved="no">
|
||||
<source>%@ is connected!</source>
|
||||
<target state="translated">%@ está conectado!</target>
|
||||
<note>notification title</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is not verified" xml:space="preserve">
|
||||
<trans-unit id="%@ is not verified" xml:space="preserve" approved="no">
|
||||
<source>%@ is not verified</source>
|
||||
<target state="translated">%@ não foi verificado</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is verified" xml:space="preserve">
|
||||
<trans-unit id="%@ is verified" xml:space="preserve" approved="no">
|
||||
<source>%@ is verified</source>
|
||||
<target state="translated">%@ foi verificado</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ servers" xml:space="preserve">
|
||||
<trans-unit id="%@ servers" xml:space="preserve" approved="no">
|
||||
<source>%@ servers</source>
|
||||
<target state="translated">%@ servidores</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve">
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve" approved="no">
|
||||
<source>%@ wants to connect!</source>
|
||||
<target state="translated">%@ quer se conectar!</target>
|
||||
<note>notification title</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d days" xml:space="preserve">
|
||||
<trans-unit id="%d days" xml:space="preserve" approved="no">
|
||||
<source>%d days</source>
|
||||
<target state="translated">%d dias</target>
|
||||
<note>message ttl</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d hours" xml:space="preserve">
|
||||
<trans-unit id="%d hours" xml:space="preserve" approved="no">
|
||||
<source>%d hours</source>
|
||||
<target state="translated">%d horas</target>
|
||||
<note>message ttl</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d min" xml:space="preserve">
|
||||
<trans-unit id="%d min" xml:space="preserve" approved="no">
|
||||
<source>%d min</source>
|
||||
<target state="translated">%d minuto</target>
|
||||
<note>message ttl</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d months" xml:space="preserve">
|
||||
<trans-unit id="%d months" xml:space="preserve" approved="no">
|
||||
<source>%d months</source>
|
||||
<target state="translated">%d meses</target>
|
||||
<note>message ttl</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d sec" xml:space="preserve">
|
||||
<trans-unit id="%d sec" xml:space="preserve" approved="no">
|
||||
<source>%d sec</source>
|
||||
<target state="translated">%d segundo</target>
|
||||
<note>message ttl</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d skipped message(s)" xml:space="preserve">
|
||||
<trans-unit id="%d skipped message(s)" xml:space="preserve" approved="no">
|
||||
<source>%d skipped message(s)</source>
|
||||
<target state="translated">%d mensagem(s) ignorada(s)</target>
|
||||
<note>integrity error chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld" xml:space="preserve">
|
||||
@@ -107,28 +125,34 @@ Available in v5.1</source>
|
||||
<source>%lld %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld contact(s) selected" xml:space="preserve">
|
||||
<trans-unit id="%lld contact(s) selected" xml:space="preserve" approved="no">
|
||||
<source>%lld contact(s) selected</source>
|
||||
<target state="translated">%lld contato(s) selecionado(s)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld file(s) with total size of %@" xml:space="preserve">
|
||||
<trans-unit id="%lld file(s) with total size of %@" xml:space="preserve" approved="no">
|
||||
<source>%lld file(s) with total size of %@</source>
|
||||
<target state="translated">%lld arquivo(s) com tamanho total de %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld members" xml:space="preserve">
|
||||
<trans-unit id="%lld members" xml:space="preserve" approved="no">
|
||||
<source>%lld members</source>
|
||||
<target state="translated">%lld membros</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld minutes" xml:space="preserve">
|
||||
<trans-unit id="%lld minutes" xml:space="preserve" approved="no">
|
||||
<source>%lld minutes</source>
|
||||
<target state="translated">%lld minutos</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld second(s)" xml:space="preserve">
|
||||
<trans-unit id="%lld second(s)" xml:space="preserve" approved="no">
|
||||
<source>%lld second(s)</source>
|
||||
<target state="translated">%lld segundo(s)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld seconds" xml:space="preserve">
|
||||
<trans-unit id="%lld seconds" xml:space="preserve" approved="no">
|
||||
<source>%lld seconds</source>
|
||||
<target state="translated">%lld segundos</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lldd" xml:space="preserve">
|
||||
@@ -159,12 +183,14 @@ Available in v5.1</source>
|
||||
<source>%lldw</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%u messages failed to decrypt." xml:space="preserve">
|
||||
<trans-unit id="%u messages failed to decrypt." xml:space="preserve" approved="no">
|
||||
<source>%u messages failed to decrypt.</source>
|
||||
<target state="translated">%u mensagens não foram descriptografadas.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%u messages skipped." xml:space="preserve">
|
||||
<trans-unit id="%u messages skipped." xml:space="preserve" approved="no">
|
||||
<source>%u messages skipped.</source>
|
||||
<target state="translated">%u mensagens ignoradas.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="(" xml:space="preserve">
|
||||
@@ -175,48 +201,56 @@ Available in v5.1</source>
|
||||
<source>)</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Add new contact**: to create your one-time QR Code for your contact." xml:space="preserve">
|
||||
<trans-unit id="**Add new contact**: to create your one-time QR Code for your contact." xml:space="preserve" approved="no">
|
||||
<source>**Add new contact**: to create your one-time QR Code or link for your contact.</source>
|
||||
<target state="translated">**Adicionar novo contato**: para criar seu QR Code único ou link para seu contato.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Create link / QR code** for your contact to use." xml:space="preserve">
|
||||
<source>**Create link / QR code** for your contact to use.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**More private**: check new messages every 20 minutes. Device token is shared with SimpleX Chat server, but not how many contacts or messages you have." xml:space="preserve">
|
||||
<trans-unit id="**More private**: check new messages every 20 minutes. Device token is shared with SimpleX Chat server, but not how many contacts or messages you have." xml:space="preserve" approved="no">
|
||||
<source>**More private**: check new messages every 20 minutes. Device token is shared with SimpleX Chat server, but not how many contacts or messages you have.</source>
|
||||
<target state="translated">**Mais privado**: verifique novas mensagens a cada 20 minutos. O token do dispositivo é compartilhado com o servidor SimpleX Chat, mas não com quantos contatos ou mensagens você possui.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." xml:space="preserve">
|
||||
<trans-unit id="**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." xml:space="preserve" approved="no">
|
||||
<source>**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app).</source>
|
||||
<target state="translated">**Totalmente privado**: não use o servidor de notificações do SimpleX Chat, verifique as mensagens periodicamente em segundo plano (depende da frequência com que você usa o aplicativo).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Paste received link** or open it in the browser and tap **Open in mobile app**." xml:space="preserve">
|
||||
<source>**Paste received link** or open it in the browser and tap **Open in mobile app**.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve" approved="no">
|
||||
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
|
||||
<target state="translated">**Atenção**: Você NÃO poderá recuperar ou alterar a senha caso a perca.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." xml:space="preserve">
|
||||
<trans-unit id="**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." xml:space="preserve" approved="no">
|
||||
<source>**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from.</source>
|
||||
<target state="translated">**Recomendado**: O token do dispositivo e as notificações são enviados ao servidor de notificação do SimpleX Chat, mas não o conteúdo, o tamanho da mensagem ou de quem ela é.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Scan QR code**: to connect to your contact in person or via video call." xml:space="preserve">
|
||||
<source>**Scan QR code**: to connect to your contact in person or via video call.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: Instant push notifications require passphrase saved in Keychain." xml:space="preserve">
|
||||
<trans-unit id="**Warning**: Instant push notifications require passphrase saved in Keychain." xml:space="preserve" approved="no">
|
||||
<source>**Warning**: Instant push notifications require passphrase saved in Keychain.</source>
|
||||
<target state="translated">**Aviso**: As notificações push instantâneas exigem uma senha salva nas Chaves.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve" approved="no">
|
||||
<source>**e2e encrypted** audio call</source>
|
||||
<target state="translated">** Criptografado e2e** chamada de áudio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** video call" xml:space="preserve">
|
||||
<trans-unit id="**e2e encrypted** video call" xml:space="preserve" approved="no">
|
||||
<source>**e2e encrypted** video call</source>
|
||||
<target state="translated">**Criptografado e2e** chamada de vídeo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="*bold*" xml:space="preserve">
|
||||
@@ -353,144 +387,175 @@ Available in v5.1</source>
|
||||
<source>All group members will remain connected.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." xml:space="preserve">
|
||||
<trans-unit id="All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." xml:space="preserve" approved="no">
|
||||
<source>All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you.</source>
|
||||
<target state="translated">Todas as mensagens serão apagadas – isso não pode ser desfeito! As mensagens serão apagadas SOMENTE para você.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected" xml:space="preserve">
|
||||
<source>All your contacts will remain connected</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow" xml:space="preserve">
|
||||
<trans-unit id="Allow" xml:space="preserve" approved="no">
|
||||
<source>Allow</source>
|
||||
<target state="translated">Permitir</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow calls only if your contact allows them." xml:space="preserve">
|
||||
<trans-unit id="Allow calls only if your contact allows them." xml:space="preserve" approved="no">
|
||||
<source>Allow calls only if your contact allows them.</source>
|
||||
<target state="translated">Permita chamadas somente se seu contato permitir.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow disappearing messages only if your contact allows it to you." xml:space="preserve">
|
||||
<trans-unit id="Allow disappearing messages only if your contact allows it to you." xml:space="preserve" approved="no">
|
||||
<source>Allow disappearing messages only if your contact allows it to you.</source>
|
||||
<target state="translated">Permita o desaparecimento de mensagens somente se o seu contato permitir.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow irreversible message deletion only if your contact allows it to you." xml:space="preserve">
|
||||
<source>Allow irreversible message deletion only if your contact allows it to you.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow sending direct messages to members." xml:space="preserve">
|
||||
<trans-unit id="Allow sending direct messages to members." xml:space="preserve" approved="no">
|
||||
<source>Allow sending direct messages to members.</source>
|
||||
<target state="translated">Permitir o envio de mensagens diretas aos membros.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow sending disappearing messages." xml:space="preserve">
|
||||
<trans-unit id="Allow sending disappearing messages." xml:space="preserve" approved="no">
|
||||
<source>Allow sending disappearing messages.</source>
|
||||
<target state="translated">Permitir o envio de mensagens que desaparecem.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to irreversibly delete sent messages." xml:space="preserve">
|
||||
<source>Allow to irreversibly delete sent messages.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send voice messages." xml:space="preserve">
|
||||
<trans-unit id="Allow to send voice messages." xml:space="preserve" approved="no">
|
||||
<source>Allow to send voice messages.</source>
|
||||
<target state="translated">Permitir enviar mensagens de voz.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow voice messages only if your contact allows them." xml:space="preserve">
|
||||
<trans-unit id="Allow voice messages only if your contact allows them." xml:space="preserve" approved="no">
|
||||
<source>Allow voice messages only if your contact allows them.</source>
|
||||
<target state="translated">Permita mensagens de voz apenas se o seu contato permitir.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow voice messages?" xml:space="preserve">
|
||||
<trans-unit id="Allow voice messages?" xml:space="preserve" approved="no">
|
||||
<source>Allow voice messages?</source>
|
||||
<target state="translated">Permitir mensagens de voz?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow your contacts to call you." xml:space="preserve">
|
||||
<trans-unit id="Allow your contacts to call you." xml:space="preserve" approved="no">
|
||||
<source>Allow your contacts to call you.</source>
|
||||
<target state="translated">Permita que seus contatos liguem para você.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow your contacts to irreversibly delete sent messages." xml:space="preserve">
|
||||
<source>Allow your contacts to irreversibly delete sent messages.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow your contacts to send disappearing messages." xml:space="preserve">
|
||||
<trans-unit id="Allow your contacts to send disappearing messages." xml:space="preserve" approved="no">
|
||||
<source>Allow your contacts to send disappearing messages.</source>
|
||||
<target state="translated">Permita que seus contatos enviem mensagens que desaparecem.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow your contacts to send voice messages." xml:space="preserve">
|
||||
<trans-unit id="Allow your contacts to send voice messages." xml:space="preserve" approved="no">
|
||||
<source>Allow your contacts to send voice messages.</source>
|
||||
<target state="translated">Permita que seus contatos enviem mensagens de voz.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Already connected?" xml:space="preserve">
|
||||
<trans-unit id="Already connected?" xml:space="preserve" approved="no">
|
||||
<source>Already connected?</source>
|
||||
<target state="translated">Já conectado?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Always use relay" xml:space="preserve">
|
||||
<trans-unit id="Always use relay" xml:space="preserve" approved="no">
|
||||
<source>Always use relay</source>
|
||||
<target state="translated">Sempre usar retransmissão</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Answer call" xml:space="preserve">
|
||||
<trans-unit id="Answer call" xml:space="preserve" approved="no">
|
||||
<source>Answer call</source>
|
||||
<target state="translated">Atender chamada</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App build: %@" xml:space="preserve">
|
||||
<trans-unit id="App build: %@" xml:space="preserve" approved="no">
|
||||
<source>App build: %@</source>
|
||||
<target state="translated">Versão do Aplicativo: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App icon" xml:space="preserve">
|
||||
<trans-unit id="App icon" xml:space="preserve" approved="no">
|
||||
<source>App icon</source>
|
||||
<target state="translated">Ícone do Aplicativo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App passcode" xml:space="preserve">
|
||||
<trans-unit id="App passcode" xml:space="preserve" approved="no">
|
||||
<source>App passcode</source>
|
||||
<target state="translated">Senha do Aplicativo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App version" xml:space="preserve">
|
||||
<trans-unit id="App version" xml:space="preserve" approved="no">
|
||||
<source>App version</source>
|
||||
<target state="translated">Versão do Aplicativo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App version: v%@" xml:space="preserve">
|
||||
<trans-unit id="App version: v%@" xml:space="preserve" approved="no">
|
||||
<source>App version: v%@</source>
|
||||
<target state="translated">Versão do Aplicativo: v%@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Appearance" xml:space="preserve">
|
||||
<trans-unit id="Appearance" xml:space="preserve" approved="no">
|
||||
<source>Appearance</source>
|
||||
<target state="translated">Aparência</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<trans-unit id="Attach" xml:space="preserve" approved="no">
|
||||
<source>Attach</source>
|
||||
<target state="translated">Anexar</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Audio & video calls" xml:space="preserve">
|
||||
<trans-unit id="Audio & video calls" xml:space="preserve" approved="no">
|
||||
<source>Audio & video calls</source>
|
||||
<target state="translated">Chamadas de áudio e vídeo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Audio and video calls" xml:space="preserve">
|
||||
<trans-unit id="Audio and video calls" xml:space="preserve" approved="no">
|
||||
<source>Audio and video calls</source>
|
||||
<target state="translated">Chamadas de áudio e vídeo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Audio/video calls" xml:space="preserve">
|
||||
<trans-unit id="Audio/video calls" xml:space="preserve" approved="no">
|
||||
<source>Audio/video calls</source>
|
||||
<target state="translated">Chamadas de áudio/vídeo</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Audio/video calls are prohibited." xml:space="preserve">
|
||||
<trans-unit id="Audio/video calls are prohibited." xml:space="preserve" approved="no">
|
||||
<source>Audio/video calls are prohibited.</source>
|
||||
<target state="translated">Chamadas de áudio/vídeo são proibidas.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Authentication cancelled" xml:space="preserve">
|
||||
<trans-unit id="Authentication cancelled" xml:space="preserve" approved="no">
|
||||
<source>Authentication cancelled</source>
|
||||
<target state="translated">Autenticação cancelada</target>
|
||||
<note>PIN entry</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Authentication failed" xml:space="preserve">
|
||||
<trans-unit id="Authentication failed" xml:space="preserve" approved="no">
|
||||
<source>Authentication failed</source>
|
||||
<target state="translated">Falha na autenticação</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Authentication is required before the call is connected, but you may miss calls." xml:space="preserve">
|
||||
<trans-unit id="Authentication is required before the call is connected, but you may miss calls." xml:space="preserve" approved="no">
|
||||
<source>Authentication is required before the call is connected, but you may miss calls.</source>
|
||||
<target state="translated">A autenticação é necessária antes que a chamada seja conectada, mas você pode perder chamadas.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Authentication unavailable" xml:space="preserve">
|
||||
<trans-unit id="Authentication unavailable" xml:space="preserve" approved="no">
|
||||
<source>Authentication unavailable</source>
|
||||
<target state="translated">Autenticação indisponível</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Auto-accept contact requests" xml:space="preserve">
|
||||
<trans-unit id="Auto-accept contact requests" xml:space="preserve" approved="no">
|
||||
<source>Auto-accept contact requests</source>
|
||||
<target state="translated">Aceitar solicitações de contato automaticamente</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Auto-accept images" xml:space="preserve">
|
||||
@@ -4162,6 +4227,226 @@ SimpleX servers cannot see your profile.</source>
|
||||
<source>\~strike~</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="## In reply to" xml:space="preserve" approved="no">
|
||||
<source>## In reply to</source>
|
||||
<target state="translated">## Em resposta a</target>
|
||||
<note>copied message info</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ uploaded" xml:space="preserve" approved="no">
|
||||
<source>%@ uploaded</source>
|
||||
<target state="translated">%@ enviado</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%d weeks" xml:space="preserve" approved="no">
|
||||
<source>%d weeks</source>
|
||||
<target state="translated">%d semanas</target>
|
||||
<note>time interval</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld messages blocked by admin" xml:space="preserve" approved="no">
|
||||
<source>%lld messages blocked by admin</source>
|
||||
<target state="translated">%lld mensagens bloqueadas pelo administrador</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld new interface languages" xml:space="preserve" approved="no">
|
||||
<source>%lld new interface languages</source>
|
||||
<target state="translated">%lld novas interface de idiomas</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Add contact**: to create a new invitation link, or connect via a link you received." xml:space="preserve" approved="no">
|
||||
<source>**Add contact**: to create a new invitation link, or connect via a link you received.</source>
|
||||
<target state="translated">**Adicionar contato**: para criar um novo link de convite ou conectar-se por meio de um link que você recebeu.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Create group**: to create a new group." xml:space="preserve" approved="no">
|
||||
<source>**Create group**: to create a new group.</source>
|
||||
<target state="translated">**Criar grupo**: para criar um novo grupo.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve" approved="no">
|
||||
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
|
||||
<target state="translated">**Observação**: usar o mesmo banco de dados em dois dispositivos interromperá a descriptografia de mensagens de suas conexões, como proteção de segurança.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="## History" xml:space="preserve" approved="no">
|
||||
<source>## History</source>
|
||||
<target state="translated">## Histórico</target>
|
||||
<note>copied message info</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve" approved="no">
|
||||
<source>**Warning**: the archive will be removed.</source>
|
||||
<target state="translated">**Atenção**: O arquivo será removido.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ and %@" xml:space="preserve" approved="no">
|
||||
<source>%@ and %@</source>
|
||||
<target state="translated">%@ e %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ and %@ connected" xml:space="preserve" approved="no">
|
||||
<source>%@ and %@ connected</source>
|
||||
<target state="translated">%@ e %@ conectado</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ at %@:" xml:space="preserve" approved="no">
|
||||
<source>%1$@ at %2$@:</source>
|
||||
<target state="translated">%1$@ em %2$@:</target>
|
||||
<note>copied message info, <sender> at <time></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ connected" xml:space="preserve" approved="no">
|
||||
<source>%@ connected</source>
|
||||
<target state="translated">%@ conectado</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@, %@ and %lld members" xml:space="preserve" approved="no">
|
||||
<source>%@, %@ and %lld members</source>
|
||||
<target state="translated">%@, %@ e %lld membros</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@, %@ and %lld other members connected" xml:space="preserve" approved="no">
|
||||
<source>%@, %@ and %lld other members connected</source>
|
||||
<target state="translated">%@, %@ e %lld outros membros conectados</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld group events" xml:space="preserve" approved="no">
|
||||
<source>%lld group events</source>
|
||||
<target state="translated">%lld eventos de grupo</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld messages marked deleted" xml:space="preserve" approved="no">
|
||||
<source>%lld messages marked deleted</source>
|
||||
<target state="translated">%lld mensagens marcadas como excluídas</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld messages blocked" xml:space="preserve" approved="no">
|
||||
<source>%lld messages blocked</source>
|
||||
<target state="translated">%lld mensagens bloqueadas</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%lld messages moderated by %@" xml:space="preserve" approved="no">
|
||||
<source>%lld messages moderated by %@</source>
|
||||
<target state="translated">%lld mensagens moderadas por %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="(this device v%@)" xml:space="preserve" approved="no">
|
||||
<source>(this device v%@)</source>
|
||||
<target state="translated">(este dispositivo v%@)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All data is erased when it is entered." xml:space="preserve" approved="no">
|
||||
<source>All data is erased when it is entered.</source>
|
||||
<target state="translated">Todos os dados são apagados quando são inseridos.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow irreversible message deletion only if your contact allows it to you. (24 hours)" xml:space="preserve" approved="no">
|
||||
<source>Allow irreversible message deletion only if your contact allows it to you. (24 hours)</source>
|
||||
<target state="translated">Permita a exclusão irreversível de mensagens somente se o seu contato permitir. (24 horas)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Apply" xml:space="preserve" approved="no">
|
||||
<source>Apply</source>
|
||||
<target state="translated">Aplicar</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archive and upload" xml:space="preserve" approved="no">
|
||||
<source>Archive and upload</source>
|
||||
<target state="translated">Arquivar e fazer envio</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All new messages from %@ will be hidden!" xml:space="preserve" approved="no">
|
||||
<source>All new messages from %@ will be hidden!</source>
|
||||
<target state="translated">Todas as novas mensagens de %@ ficarão ocultas!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Already connecting!" xml:space="preserve" approved="no">
|
||||
<source>Already connecting!</source>
|
||||
<target state="translated">Já conectando!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve" approved="no">
|
||||
<source>App encrypts new local files (except videos).</source>
|
||||
<target state="translated">O aplicativo criptografa novos arquivos locais (exceto vídeos).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App passcode is replaced with self-destruct passcode." xml:space="preserve" approved="no">
|
||||
<source>App passcode is replaced with self-destruct passcode.</source>
|
||||
<target state="translated">A senha do Aplicativo é substituída pela senha de autodestruição.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected." xml:space="preserve" approved="no">
|
||||
<source>All your contacts will remain connected.</source>
|
||||
<target state="translated">Todos os seus contatos permanecerão conectados.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts will remain connected. Profile update will be sent to your contacts." xml:space="preserve" approved="no">
|
||||
<source>All your contacts will remain connected. Profile update will be sent to your contacts.</source>
|
||||
<target state="translated">Todos os seus contatos permanecerão conectados. A atualização do perfil será enviada para seus contatos.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send files and media." xml:space="preserve" approved="no">
|
||||
<source>Allow to send files and media.</source>
|
||||
<target state="translated">Permitir o envio de arquivos e mídia.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App data migration" xml:space="preserve" approved="no">
|
||||
<source>App data migration</source>
|
||||
<target state="translated">Migração de dados de aplicativos</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archiving database" xml:space="preserve" approved="no">
|
||||
<source>Archiving database</source>
|
||||
<target state="translated">Arquivando banco de dados</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All messages will be deleted - this cannot be undone!" xml:space="preserve" approved="no">
|
||||
<source>All messages will be deleted - this cannot be undone!</source>
|
||||
<target state="translated">Todas as mensagens serão apagadas – isso não pode ser desfeito!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve" approved="no">
|
||||
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
|
||||
<target state="translated">Todos os seus contatos, conversas e arquivos serão criptografados com segurança e enviados em partes para retransmissões XFTP configuradas.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow message reactions only if your contact allows them." xml:space="preserve" approved="no">
|
||||
<source>Allow message reactions only if your contact allows them.</source>
|
||||
<target state="translated">Permita reações às mensagens somente se o seu contato permitir.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow message reactions." xml:space="preserve" approved="no">
|
||||
<source>Allow message reactions.</source>
|
||||
<target state="translated">Permitir reações às mensagens.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow your contacts to irreversibly delete sent messages. (24 hours)" xml:space="preserve" approved="no">
|
||||
<source>Allow your contacts to irreversibly delete sent messages. (24 hours)</source>
|
||||
<target state="translated">Permita que seus contatos apaguem irreversivelmente as mensagens enviadas. (24 horas)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Already joining the group!" xml:space="preserve" approved="no">
|
||||
<source>Already joining the group!</source>
|
||||
<target state="translated">Entrando no grupo!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="An empty chat profile with the provided name is created, and the app opens as usual." xml:space="preserve" approved="no">
|
||||
<source>An empty chat profile with the provided name is created, and the app opens as usual.</source>
|
||||
<target state="translated">Um perfil de conversa vazio com o nome fornecido é criado e o aplicativo abre normalmente.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Auto-accept" xml:space="preserve" approved="no">
|
||||
<source>Auto-accept</source>
|
||||
<target state="translated">Aceitar automaticamente</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow your contacts adding message reactions." xml:space="preserve" approved="no">
|
||||
<source>Allow your contacts adding message reactions.</source>
|
||||
<target state="translated">Permita que seus contatos adicionem reações às mensagens.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to irreversibly delete sent messages. (24 hours)" xml:space="preserve" approved="no">
|
||||
<source>Allow to irreversibly delete sent messages. (24 hours)</source>
|
||||
<target state="translated">Permitir apagar irreversivelmente as mensagens enviadas. (24 horas)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="pt" datatype="plaintext">
|
||||
|
||||
@@ -107,6 +107,11 @@
|
||||
<target>%@ соединен(а)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ downloaded" xml:space="preserve">
|
||||
<source>%@ downloaded</source>
|
||||
<target>%@ загружено</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve">
|
||||
<source>%@ is connected!</source>
|
||||
<target>Установлено соединение с %@!</target>
|
||||
@@ -127,6 +132,11 @@
|
||||
<target>%@ серверы</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ uploaded" xml:space="preserve">
|
||||
<source>%@ uploaded</source>
|
||||
<target>%@ загружено</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve">
|
||||
<source>%@ wants to connect!</source>
|
||||
<target>%@ хочет соединиться!</target>
|
||||
@@ -342,6 +352,11 @@
|
||||
<target>**Самый конфиденциальный**: не использовать сервер уведомлений SimpleX Chat, проверять сообщения периодически в фоновом режиме (зависит от того насколько часто Вы используете приложение).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
|
||||
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
|
||||
<target>**Обратите внимание**: использование одной и той же базы данных на двух устройствах нарушит расшифровку сообщений от ваших контактов, как свойство защиты соединений.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
|
||||
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
|
||||
<target>**Внимание**: Вы не сможете восстановить или поменять пароль, если Вы его потеряете.</target>
|
||||
@@ -357,6 +372,11 @@
|
||||
<target>**Внимание**: для работы мгновенных уведомлений пароль должен быть сохранен в Keychain.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
|
||||
<source>**Warning**: the archive will be removed.</source>
|
||||
<target>**Внимание**: архив будет удален.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
|
||||
<source>**e2e encrypted** audio call</source>
|
||||
<target>**e2e зашифрованный** аудиозвонок</target>
|
||||
@@ -613,6 +633,11 @@
|
||||
<target>Изменение адреса будет прекращено. Будет использоваться старый адрес.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can block a member for all." xml:space="preserve">
|
||||
<source>Admins can block a member for all.</source>
|
||||
<target>Админы могут заблокировать члена группы.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
|
||||
<source>Admins can create the links to join groups.</source>
|
||||
<target>Админы могут создать ссылки для вступления в группу.</target>
|
||||
@@ -668,6 +693,11 @@
|
||||
<target>Все Ваши контакты сохранятся. Обновленный профиль будет отправлен Вашим контактам.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
|
||||
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
|
||||
<target>Все ваши контакты, разговоры и файлы будут надежно зашифрованы и загружены на выбранные XFTP серверы.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow" xml:space="preserve">
|
||||
<source>Allow</source>
|
||||
<target>Разрешить</target>
|
||||
@@ -713,6 +743,10 @@
|
||||
<target>Разрешить необратимо удалять отправленные сообщения. (24 часа)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
|
||||
<source>Allow to send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send files and media." xml:space="preserve">
|
||||
<source>Allow to send files and media.</source>
|
||||
<target>Разрешить посылать файлы и медиа.</target>
|
||||
@@ -793,6 +827,11 @@
|
||||
<target>Сборка приложения: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App data migration" xml:space="preserve">
|
||||
<source>App data migration</source>
|
||||
<target>Миграция данных</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
|
||||
<source>App encrypts new local files (except videos).</source>
|
||||
<target>Приложение шифрует новые локальные файлы (кроме видео).</target>
|
||||
@@ -828,6 +867,21 @@
|
||||
<target>Интерфейс</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Apply" xml:space="preserve">
|
||||
<source>Apply</source>
|
||||
<target>Применить</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archive and upload" xml:space="preserve">
|
||||
<source>Archive and upload</source>
|
||||
<target>Архивировать и загрузить</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archiving database" xml:space="preserve">
|
||||
<source>Archiving database</source>
|
||||
<target>Подготовка архива</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<source>Attach</source>
|
||||
<target>Прикрепить</target>
|
||||
@@ -1018,6 +1072,11 @@
|
||||
<target>Отменить</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cancel migration" xml:space="preserve">
|
||||
<source>Cancel migration</source>
|
||||
<target>Отменить миграцию</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
|
||||
<source>Cannot access keychain to save database password</source>
|
||||
<target>Ошибка доступа к Keychain при сохранении пароля</target>
|
||||
@@ -1028,6 +1087,10 @@
|
||||
<target>Невозможно получить файл</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cellular" xml:space="preserve">
|
||||
<source>Cellular</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Change" xml:space="preserve">
|
||||
<source>Change</source>
|
||||
<target>Поменять</target>
|
||||
@@ -1119,6 +1182,11 @@
|
||||
<target>Чат остановлен. Если вы уже использовали эту базу данных на другом устройстве, перенесите ее обратно до запуска чата.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat migrated!" xml:space="preserve">
|
||||
<source>Chat migrated!</source>
|
||||
<target>Чат мигрирован!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat preferences" xml:space="preserve">
|
||||
<source>Chat preferences</source>
|
||||
<target>Предпочтения</target>
|
||||
@@ -1139,6 +1207,11 @@
|
||||
<target>Китайский и Испанский интерфейс</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
|
||||
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
|
||||
<target>Выберите _Мигрировать с другого устройства_ на новом устройстве и сосканируйте QR код.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose file" xml:space="preserve">
|
||||
<source>Choose file</source>
|
||||
<target>Выбрать файл</target>
|
||||
@@ -1209,6 +1282,11 @@
|
||||
<target>Подтвердить обновление базы данных</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm network settings" xml:space="preserve">
|
||||
<source>Confirm network settings</source>
|
||||
<target>Подтвердите настройки сети</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm new passphrase…" xml:space="preserve">
|
||||
<source>Confirm new passphrase…</source>
|
||||
<target>Подтвердите новый пароль…</target>
|
||||
@@ -1219,6 +1297,16 @@
|
||||
<target>Подтвердить пароль</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
|
||||
<source>Confirm that you remember database passphrase to migrate it.</source>
|
||||
<target>Подтвердите, что Вы помните пароль базы данных для ее миграции.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm upload" xml:space="preserve">
|
||||
<source>Confirm upload</source>
|
||||
<target>Подтвердить загрузку</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Connect" xml:space="preserve">
|
||||
<source>Connect</source>
|
||||
<target>Соединиться</target>
|
||||
@@ -1478,6 +1566,11 @@ This is your own one-time link!</source>
|
||||
<target>Дата создания %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating archive link" xml:space="preserve">
|
||||
<source>Creating archive link</source>
|
||||
<target>Создание ссылки на архив</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating link…" xml:space="preserve">
|
||||
<source>Creating link…</source>
|
||||
<target>Создаётся ссылка…</target>
|
||||
@@ -1698,6 +1791,11 @@ This cannot be undone!</source>
|
||||
<target>Удалить данные чата</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete database from this device" xml:space="preserve">
|
||||
<source>Delete database from this device</source>
|
||||
<target>Удалить базу данных с этого устройства</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete file" xml:space="preserve">
|
||||
<source>Delete file</source>
|
||||
<target>Удалить файл</target>
|
||||
@@ -1988,11 +2086,30 @@ This cannot be undone!</source>
|
||||
<target>Откатить версию и открыть чат</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download" xml:space="preserve">
|
||||
<source>Download</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download failed" xml:space="preserve">
|
||||
<source>Download failed</source>
|
||||
<target>Ошибка загрузки</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download file" xml:space="preserve">
|
||||
<source>Download file</source>
|
||||
<target>Загрузка файла</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading archive" xml:space="preserve">
|
||||
<source>Downloading archive</source>
|
||||
<target>Загрузка архива</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading link details" xml:space="preserve">
|
||||
<source>Downloading link details</source>
|
||||
<target>Загрузка ссылки архива</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duplicate display name!" xml:space="preserve">
|
||||
<source>Duplicate display name!</source>
|
||||
<target>Имя профиля уже используется!</target>
|
||||
@@ -2048,6 +2165,11 @@ This cannot be undone!</source>
|
||||
<target>Включить для всех</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
|
||||
<source>Enable in direct chats (BETA)!</source>
|
||||
<target>Включите для контактов (BETA)!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable instant notifications?" xml:space="preserve">
|
||||
<source>Enable instant notifications?</source>
|
||||
<target>Включить мгновенные уведомления?</target>
|
||||
@@ -2078,6 +2200,10 @@ This cannot be undone!</source>
|
||||
<target>Включить код самоуничтожения</target>
|
||||
<note>set passcode view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled for" xml:space="preserve">
|
||||
<source>Enabled for</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt" xml:space="preserve">
|
||||
<source>Encrypt</source>
|
||||
<target>Зашифровать</target>
|
||||
@@ -2163,6 +2289,11 @@ This cannot be undone!</source>
|
||||
<target>Введите имя группы…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase" xml:space="preserve">
|
||||
<source>Enter passphrase</source>
|
||||
<target>Введите пароль</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve">
|
||||
<source>Enter passphrase…</source>
|
||||
<target>Введите пароль…</target>
|
||||
@@ -2223,6 +2354,11 @@ This cannot be undone!</source>
|
||||
<target>Ошибка при добавлении членов группы</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error allowing contact PQ encryption" xml:space="preserve">
|
||||
<source>Error allowing contact PQ encryption</source>
|
||||
<target>Ошибка разрешения квантово-устойчивого шифрования</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing address" xml:space="preserve">
|
||||
<source>Error changing address</source>
|
||||
<target>Ошибка при изменении адреса</target>
|
||||
@@ -2313,6 +2449,11 @@ This cannot be undone!</source>
|
||||
<target>Ошибка удаления профиля пользователя</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error downloading the archive" xml:space="preserve">
|
||||
<source>Error downloading the archive</source>
|
||||
<target>Ошибка загрузки архива</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
|
||||
<source>Error enabling delivery receipts!</source>
|
||||
<target>Ошибка при включении отчётов о доставке!</target>
|
||||
@@ -2388,6 +2529,11 @@ This cannot be undone!</source>
|
||||
<target>Ошибка сохранения пароля в Keychain</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving settings" xml:space="preserve">
|
||||
<source>Error saving settings</source>
|
||||
<target>Ошибка сохранения настроек</target>
|
||||
<note>when migrating</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving user password" xml:space="preserve">
|
||||
<source>Error saving user password</source>
|
||||
<target>Ошибка при сохранении пароля пользователя</target>
|
||||
@@ -2458,6 +2604,16 @@ This cannot be undone!</source>
|
||||
<target>Ошибка при обновлении конфиденциальности</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error uploading the archive" xml:space="preserve">
|
||||
<source>Error uploading the archive</source>
|
||||
<target>Ошибка загрузки архива</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
|
||||
<source>Error verifying passphrase:</source>
|
||||
<target>Ошибка подтверждения пароля:</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error: " xml:space="preserve">
|
||||
<source>Error: </source>
|
||||
<target>Ошибка: </target>
|
||||
@@ -2508,6 +2664,11 @@ This cannot be undone!</source>
|
||||
<target>Архив чата экспортирован.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
|
||||
<source>Exported file doesn't exist</source>
|
||||
<target>Экспортированный файл не существует</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exporting database archive…" xml:space="preserve">
|
||||
<source>Exporting database archive…</source>
|
||||
<target>Архив чата экспортируется…</target>
|
||||
@@ -2568,6 +2729,10 @@ This cannot be undone!</source>
|
||||
<target>Файлы и медиа запрещены в этой группе.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media not allowed" xml:space="preserve">
|
||||
<source>Files and media not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media prohibited!" xml:space="preserve">
|
||||
<source>Files and media prohibited!</source>
|
||||
<target>Файлы и медиа запрещены!</target>
|
||||
@@ -2578,6 +2743,16 @@ This cannot be undone!</source>
|
||||
<target>Фильтровать непрочитанные и избранные чаты.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration" xml:space="preserve">
|
||||
<source>Finalize migration</source>
|
||||
<target>Завершить миграцию</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration on another device." xml:space="preserve">
|
||||
<source>Finalize migration on another device.</source>
|
||||
<target>Завершите миграцию на другом устройстве.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
|
||||
<source>Finally, we have them! 🚀</source>
|
||||
<target>Наконец-то, мы их добавили! 🚀</target>
|
||||
@@ -2623,6 +2798,18 @@ This cannot be undone!</source>
|
||||
<target>Для консоли</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forward" xml:space="preserve">
|
||||
<source>Forward</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded" xml:space="preserve">
|
||||
<source>Forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded from" xml:space="preserve">
|
||||
<source>Forwarded from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Found desktop" xml:space="preserve">
|
||||
<source>Found desktop</source>
|
||||
<target>Компьютер найден</target>
|
||||
@@ -2733,6 +2920,10 @@ This cannot be undone!</source>
|
||||
<target>Члены группы могут необратимо удалять отправленные сообщения. (24 часа)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
|
||||
<source>Group members can send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send direct messages." xml:space="preserve">
|
||||
<source>Group members can send direct messages.</source>
|
||||
<target>Члены группы могут посылать прямые сообщения.</target>
|
||||
@@ -2868,6 +3059,11 @@ This cannot be undone!</source>
|
||||
<target>Как использовать серверы</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Hungarian interface" xml:space="preserve">
|
||||
<source>Hungarian interface</source>
|
||||
<target>Венгерский интерфейс</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
|
||||
<source>ICE servers (one per line)</source>
|
||||
<target>ICE серверы (один на строке)</target>
|
||||
@@ -2933,6 +3129,16 @@ This cannot be undone!</source>
|
||||
<target>Импорт архива чата</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import failed" xml:space="preserve">
|
||||
<source>Import failed</source>
|
||||
<target>Ошибка импорта</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Importing archive" xml:space="preserve">
|
||||
<source>Importing archive</source>
|
||||
<target>Импорт архива</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved message delivery" xml:space="preserve">
|
||||
<source>Improved message delivery</source>
|
||||
<target>Улучшенная доставка сообщений</target>
|
||||
@@ -2948,6 +3154,11 @@ This cannot be undone!</source>
|
||||
<target>Улучшенная конфигурация серверов</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
|
||||
<source>In order to continue, chat should be stopped.</source>
|
||||
<target>Чтобы продолжить, чат должен быть остановлен.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In reply to" xml:space="preserve">
|
||||
<source>In reply to</source>
|
||||
<target>В ответ на</target>
|
||||
@@ -3060,6 +3271,11 @@ This cannot be undone!</source>
|
||||
<target>Ошибка ссылки</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
|
||||
<source>Invalid migration confirmation</source>
|
||||
<target>Ошибка подтверждения миграции</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid name!" xml:space="preserve">
|
||||
<source>Invalid name!</source>
|
||||
<target>Неверное имя!</target>
|
||||
@@ -3428,6 +3644,11 @@ This is your link for group %@!</source>
|
||||
<target>Текст сообщения</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Message too large" xml:space="preserve">
|
||||
<source>Message too large</source>
|
||||
<target>Сообщение слишком большое</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages" xml:space="preserve">
|
||||
<source>Messages</source>
|
||||
<target>Сообщения</target>
|
||||
@@ -3443,11 +3664,56 @@ This is your link for group %@!</source>
|
||||
<target>Сообщения от %@ будут показаны!</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<target>Сообщения, файлы и звонки защищены **end-to-end шифрованием** с прямой секретностью (PFS), правдоподобным отрицанием и восстановлением от взлома.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<target>Сообщения, файлы и звонки защищены **квантово-устойчивым end-to-end шифрованием** с прямой секретностью (PFS), правдоподобным отрицанием и восстановлением от взлома.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate device" xml:space="preserve">
|
||||
<source>Migrate device</source>
|
||||
<target>Мигрировать устройство</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate from another device" xml:space="preserve">
|
||||
<source>Migrate from another device</source>
|
||||
<target>Миграция с другого устройства</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate here" xml:space="preserve">
|
||||
<source>Migrate here</source>
|
||||
<target>Мигрировать сюда</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device" xml:space="preserve">
|
||||
<source>Migrate to another device</source>
|
||||
<target>Мигрировать на другое устройство</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
|
||||
<source>Migrate to another device via QR code.</source>
|
||||
<target>Мигрируйте на другое устройство через QR код.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating" xml:space="preserve">
|
||||
<source>Migrating</source>
|
||||
<target>Миграция</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating database archive…" xml:space="preserve">
|
||||
<source>Migrating database archive…</source>
|
||||
<target>Данные чата перемещаются…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration complete" xml:space="preserve">
|
||||
<source>Migration complete</source>
|
||||
<target>Миграция завершена</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration error:" xml:space="preserve">
|
||||
<source>Migration error:</source>
|
||||
<target>Ошибка при перемещении данных:</target>
|
||||
@@ -3523,6 +3789,10 @@ This is your link for group %@!</source>
|
||||
<target>Сеть & серверы</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network connection" xml:space="preserve">
|
||||
<source>Network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network settings" xml:space="preserve">
|
||||
<source>Network settings</source>
|
||||
<target>Настройки сети</target>
|
||||
@@ -3633,6 +3903,10 @@ This is your link for group %@!</source>
|
||||
<target>Нет истории</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No network connection" xml:space="preserve">
|
||||
<source>No network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No permission to record voice message" xml:space="preserve">
|
||||
<source>No permission to record voice message</source>
|
||||
<target>Нет разрешения для записи голосового сообщения</target>
|
||||
@@ -3807,6 +4081,11 @@ This is your link for group %@!</source>
|
||||
<target>Открыть группу</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open migration to another device" xml:space="preserve">
|
||||
<source>Open migration to another device</source>
|
||||
<target>Открытие миграции на другое устройство</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open user profiles" xml:space="preserve">
|
||||
<source>Open user profiles</source>
|
||||
<target>Открыть профили пользователя</target>
|
||||
@@ -3822,16 +4101,30 @@ This is your link for group %@!</source>
|
||||
<target>Приложение отрывается…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or paste archive link" xml:space="preserve">
|
||||
<source>Or paste archive link</source>
|
||||
<target>Или вставьте ссылку архива</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or scan QR code" xml:space="preserve">
|
||||
<source>Or scan QR code</source>
|
||||
<target>Или отсканируйте QR код</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or securely share this file link" xml:space="preserve">
|
||||
<source>Or securely share this file link</source>
|
||||
<target>Или передайте эту ссылку</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or show this code" xml:space="preserve">
|
||||
<source>Or show this code</source>
|
||||
<target>Или покажите этот код</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Other" xml:space="preserve">
|
||||
<source>Other</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PING count" xml:space="preserve">
|
||||
<source>PING count</source>
|
||||
<target>Количество PING</target>
|
||||
@@ -3912,6 +4205,11 @@ This is your link for group %@!</source>
|
||||
<target>Ошибка расшифровки</target>
|
||||
<note>message decrypt error item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
|
||||
<source>Picture-in-picture calls</source>
|
||||
<target>Звонки с картинкой-в-картинке</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
|
||||
<source>Please ask your contact to enable sending voice messages.</source>
|
||||
<target>Попросите у Вашего контакта разрешить отправку голосовых сообщений.</target>
|
||||
@@ -3932,6 +4230,11 @@ This is your link for group %@!</source>
|
||||
<target>Проверьте предпочтения Вашего контакта.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
|
||||
<source>Please confirm that network settings are correct for this device.</source>
|
||||
<target>Пожалуйста, подтвердите, что настройки сети верны для этого устройства.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please contact developers. Error: %@" xml:space="preserve">
|
||||
<source>Please contact developers.
|
||||
Error: %@</source>
|
||||
@@ -3989,6 +4292,11 @@ Error: %@</source>
|
||||
<target>Возможно, хэш сертификата в адресе сервера неверный</target>
|
||||
<note>server test error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Post-quantum E2EE" xml:space="preserve">
|
||||
<source>Post-quantum E2EE</source>
|
||||
<target>Квантово-устойчивое E2EE</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
|
||||
<source>Preserve the last message draft, with attachments.</source>
|
||||
<target>Сохранить последний черновик, вместе с вложениями.</target>
|
||||
@@ -4079,6 +4387,10 @@ Error: %@</source>
|
||||
<target>Запретить реакции на сообщения.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
|
||||
<source>Prohibit sending SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
|
||||
<source>Prohibit sending direct messages to members.</source>
|
||||
<target>Запретить посылать прямые сообщения членам группы.</target>
|
||||
@@ -4124,6 +4436,16 @@ Error: %@</source>
|
||||
<target>Доставка уведомлений</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Push server" xml:space="preserve">
|
||||
<source>Push server</source>
|
||||
<target>Сервер уведомлений</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
|
||||
<source>Quantum resistant encryption</source>
|
||||
<target>Квантово-устойчивое шифрование</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Rate the app" xml:space="preserve">
|
||||
<source>Rate the app</source>
|
||||
<target>Оценить приложение</target>
|
||||
@@ -4199,6 +4521,10 @@ Error: %@</source>
|
||||
<target>Адрес получения сообщений будет перемещён на другой сервер. Изменение адреса завершится после того как отправитель будет онлайн.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving concurrency" xml:space="preserve">
|
||||
<source>Receiving concurrency</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
|
||||
<source>Receiving file will be stopped.</source>
|
||||
<target>Приём файла будет прекращён.</target>
|
||||
@@ -4214,6 +4540,10 @@ Error: %@</source>
|
||||
<target>История сообщений и улучшенный [каталог групп](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
|
||||
<source>Recipient(s) can't see who this message is from.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipients see updates as you type them." xml:space="preserve">
|
||||
<source>Recipients see updates as you type them.</source>
|
||||
<target>Получатели видят их в то время как Вы их набираете.</target>
|
||||
@@ -4309,11 +4639,26 @@ Error: %@</source>
|
||||
<target>Повторить запрос на соединение?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat download" xml:space="preserve">
|
||||
<source>Repeat download</source>
|
||||
<target>Повторить загрузку</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat import" xml:space="preserve">
|
||||
<source>Repeat import</source>
|
||||
<target>Повторить импорт</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat join request?" xml:space="preserve">
|
||||
<source>Repeat join request?</source>
|
||||
<target>Повторить запрос на вступление?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat upload" xml:space="preserve">
|
||||
<source>Repeat upload</source>
|
||||
<target>Повторить загрузку</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply" xml:space="preserve">
|
||||
<source>Reply</source>
|
||||
<target>Ответить</target>
|
||||
@@ -4414,6 +4759,11 @@ Error: %@</source>
|
||||
<target>SMP серверы</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Safer groups" xml:space="preserve">
|
||||
<source>Safer groups</source>
|
||||
<target>Более безопасные группы</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Save" xml:space="preserve">
|
||||
<source>Save</source>
|
||||
<target>Сохранить</target>
|
||||
@@ -4494,11 +4844,19 @@ Error: %@</source>
|
||||
<target>Сохранить приветственное сообщение?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved" xml:space="preserve">
|
||||
<source>Saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
|
||||
<source>Saved WebRTC ICE servers will be removed</source>
|
||||
<target>Сохраненные WebRTC ICE серверы будут удалены</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved from" xml:space="preserve">
|
||||
<source>Saved from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved message" xml:space="preserve">
|
||||
<source>Saved message</source>
|
||||
<target>Сохраненное сообщение</target>
|
||||
@@ -4779,6 +5137,11 @@ Error: %@</source>
|
||||
<target>Установить код доступа</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase" xml:space="preserve">
|
||||
<source>Set passphrase</source>
|
||||
<target>Установить пароль</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase to export" xml:space="preserve">
|
||||
<source>Set passphrase to export</source>
|
||||
<target>Установите пароль</target>
|
||||
@@ -4834,6 +5197,11 @@ Error: %@</source>
|
||||
<target>Поделиться с контактами</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
<source>Show QR code</source>
|
||||
<target>Показать QR код</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show calls in phone history" xml:space="preserve">
|
||||
<source>Show calls in phone history</source>
|
||||
<target>Показать звонки в истории телефона</target>
|
||||
@@ -4912,6 +5280,14 @@ Error: %@</source>
|
||||
<trans-unit id="SimpleX links" xml:space="preserve">
|
||||
<source>SimpleX links</source>
|
||||
<target>SimpleX ссылки</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
|
||||
<source>SimpleX links are prohibited in this group.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
|
||||
<source>SimpleX links not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX one-time invitation" xml:space="preserve">
|
||||
@@ -4974,6 +5350,11 @@ Error: %@</source>
|
||||
<target>Остановить SimpleX</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat" xml:space="preserve">
|
||||
<source>Stop chat</source>
|
||||
<target>Остановить чат</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat to enable database actions" xml:space="preserve">
|
||||
<source>Stop chat to enable database actions</source>
|
||||
<target>Остановите чат, чтобы разблокировать операции с архивом чата</target>
|
||||
@@ -5014,6 +5395,11 @@ Error: %@</source>
|
||||
<target>Прекратить делиться адресом?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stopping chat" xml:space="preserve">
|
||||
<source>Stopping chat</source>
|
||||
<target>Остановка чата</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Submit" xml:space="preserve">
|
||||
<source>Submit</source>
|
||||
<target>Продолжить</target>
|
||||
@@ -5261,6 +5647,16 @@ It can happen because of some bug or when the connection is compromised.</source
|
||||
<target>Это действие нельзя отменить — Ваш профиль, контакты, сообщения и файлы будут безвозвратно утеряны.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by end-to-end encryption.</source>
|
||||
<target>Чат защищен end-to-end шифрованием.</target>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
|
||||
<target>Чат защищен квантово-устойчивым end-to-end шифрованием.</target>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This device name" xml:space="preserve">
|
||||
<source>This device name</source>
|
||||
<target>Имя этого устройства</target>
|
||||
@@ -5555,11 +5951,21 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Обновить и открыть чат</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload failed" xml:space="preserve">
|
||||
<source>Upload failed</source>
|
||||
<target>Ошибка загрузки</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload file" xml:space="preserve">
|
||||
<source>Upload file</source>
|
||||
<target>Загрузка файла</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uploading archive" xml:space="preserve">
|
||||
<source>Uploading archive</source>
|
||||
<target>Загрузка архива</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use .onion hosts" xml:space="preserve">
|
||||
<source>Use .onion hosts</source>
|
||||
<target>Использовать .onion хосты</target>
|
||||
@@ -5610,6 +6016,11 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Использовать сервер</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
<source>Use the app while in the call.</source>
|
||||
<target>Используйте приложение во время звонка.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="User profile" xml:space="preserve">
|
||||
<source>User profile</source>
|
||||
<target>Профиль чата</target>
|
||||
@@ -5645,6 +6056,16 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Проверять соединения</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify database passphrase" xml:space="preserve">
|
||||
<source>Verify database passphrase</source>
|
||||
<target>Проверка пароля базы данных</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify passphrase" xml:space="preserve">
|
||||
<source>Verify passphrase</source>
|
||||
<target>Проверить пароль</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify security code" xml:space="preserve">
|
||||
<source>Verify security code</source>
|
||||
<target>Подтвердить код безопасности</target>
|
||||
@@ -5705,6 +6126,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Голосовые сообщения запрещены в этой группе.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages not allowed" xml:space="preserve">
|
||||
<source>Voice messages not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages prohibited!" xml:space="preserve">
|
||||
<source>Voice messages prohibited!</source>
|
||||
<target>Голосовые сообщения запрещены!</target>
|
||||
@@ -5735,6 +6160,11 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Ожидание видео</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
|
||||
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
|
||||
<target>Внимание: запуск чата на нескольких устройствах не поддерживается и приведет к сбоям доставки сообщений</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: you may lose some data!" xml:space="preserve">
|
||||
<source>Warning: you may lose some data!</source>
|
||||
<target>Предупреждение: Вы можете потерять какие то данные!</target>
|
||||
@@ -5755,6 +6185,11 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Приветственное сообщение</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Welcome message is too long" xml:space="preserve">
|
||||
<source>Welcome message is too long</source>
|
||||
<target>Приветственное сообщение слишком длинное</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="What's new" xml:space="preserve">
|
||||
<source>What's new</source>
|
||||
<target>Новые функции</target>
|
||||
@@ -5775,6 +6210,14 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Когда Вы соединены с контактом инкогнито, тот же самый инкогнито профиль будет использоваться для групп с этим контактом.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WiFi" xml:space="preserve">
|
||||
<source>WiFi</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wired ethernet" xml:space="preserve">
|
||||
<source>Wired ethernet</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="With encrypted files and media." xml:space="preserve">
|
||||
<source>With encrypted files and media.</source>
|
||||
<target>С зашифрованными файлами и медиа.</target>
|
||||
@@ -5810,6 +6253,11 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>Вы</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
|
||||
<source>You **must not** use the same database on two devices.</source>
|
||||
<target>Вы **не должны** использовать одну и ту же базу данных на двух устройствах.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You accepted connection" xml:space="preserve">
|
||||
<source>You accepted connection</source>
|
||||
<target>Вы приняли приглашение соединиться</target>
|
||||
@@ -5897,6 +6345,11 @@ Repeat join request?</source>
|
||||
<target>Вы можете включить их позже в настройках Конфиденциальности.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can give another try." xml:space="preserve">
|
||||
<source>You can give another try.</source>
|
||||
<target>Вы можете попробовать еще раз.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
|
||||
<source>You can hide or mute a user profile - swipe it to the right.</source>
|
||||
<target>Вы можете скрыть профиль или выключить уведомления - потяните его вправо.</target>
|
||||
@@ -6248,6 +6701,10 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<target>админ</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="admins" xml:space="preserve">
|
||||
<source>admins</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="agreeing encryption for %@…" xml:space="preserve">
|
||||
<source>agreeing encryption for %@…</source>
|
||||
<target>шифрование согласовывается для %@…</target>
|
||||
@@ -6258,6 +6715,10 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<target>шифрование согласовывается…</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="all members" xml:space="preserve">
|
||||
<source>all members</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="always" xml:space="preserve">
|
||||
<source>always</source>
|
||||
<target>всегда</target>
|
||||
@@ -6291,7 +6752,7 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<trans-unit id="blocked" xml:space="preserve">
|
||||
<source>blocked</source>
|
||||
<target>заблокировано</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked %@" xml:space="preserve">
|
||||
<source>blocked %@</source>
|
||||
@@ -6301,7 +6762,7 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<trans-unit id="blocked by admin" xml:space="preserve">
|
||||
<source>blocked by admin</source>
|
||||
<target>заблокировано администратором</target>
|
||||
<note>blocked chat item</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bold" xml:space="preserve">
|
||||
<source>bold</source>
|
||||
@@ -6588,6 +7049,10 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<target>событие произошло</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="forwarded" xml:space="preserve">
|
||||
<source>forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="group deleted" xml:space="preserve">
|
||||
<source>group deleted</source>
|
||||
<target>группа удалена</target>
|
||||
@@ -6731,7 +7196,7 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<trans-unit id="moderated by %@" xml:space="preserve">
|
||||
<source>moderated by %@</source>
|
||||
<target>удалено %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="months" xml:space="preserve">
|
||||
<source>months</source>
|
||||
@@ -6795,11 +7260,20 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<target>владелец</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="owners" xml:space="preserve">
|
||||
<source>owners</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="peer-to-peer" xml:space="preserve">
|
||||
<source>peer-to-peer</source>
|
||||
<target>peer-to-peer</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
|
||||
<source>quantum resistant e2e encryption</source>
|
||||
<target>квантово-устойчивое e2e шифрование</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="received answer…" xml:space="preserve">
|
||||
<source>received answer…</source>
|
||||
<target>получен ответ…</target>
|
||||
@@ -6840,6 +7314,14 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<target>удалил(а) Вас из группы</target>
|
||||
<note>rcv group event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved" xml:space="preserve">
|
||||
<source>saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved from %@" xml:space="preserve">
|
||||
<source>saved from %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sec" xml:space="preserve">
|
||||
<source>sec</source>
|
||||
<target>сек</target>
|
||||
@@ -6875,6 +7357,11 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<target>установлена новая картинка профиля</target>
|
||||
<note>profile update event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
|
||||
<source>standard end-to-end encryption</source>
|
||||
<target>стандартное end-to-end шифрование</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="starting…" xml:space="preserve">
|
||||
<source>starting…</source>
|
||||
<target>инициализация…</target>
|
||||
@@ -6975,6 +7462,10 @@ SimpleX серверы не могут получить доступ к Ваше
|
||||
<target>да</target>
|
||||
<note>pref value</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you" xml:space="preserve">
|
||||
<source>you</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you are invited to group" xml:space="preserve">
|
||||
<source>you are invited to group</source>
|
||||
<target>Вы приглашены в группу</target>
|
||||
|
||||
@@ -101,6 +101,10 @@
|
||||
<source>%@ connected</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ downloaded" xml:space="preserve">
|
||||
<source>%@ downloaded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ is connected!" xml:space="preserve">
|
||||
<source>%@ is connected!</source>
|
||||
<target>%@ เชื่อมต่อสำเร็จ!</target>
|
||||
@@ -121,6 +125,10 @@
|
||||
<target>%@ เซิร์ฟเวอร์</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ uploaded" xml:space="preserve">
|
||||
<source>%@ uploaded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="%@ wants to connect!" xml:space="preserve">
|
||||
<source>%@ wants to connect!</source>
|
||||
<target>%@ อยากเชื่อมต่อ!</target>
|
||||
@@ -324,6 +332,10 @@
|
||||
<target>**ส่วนตัวที่สุด**: ไม่ใช้เซิร์ฟเวอร์การแจ้งเตือนของ SimpleX Chat ตรวจสอบข้อความเป็นระยะในพื้นหลัง (ขึ้นอยู่กับความถี่ที่คุณใช้แอป)</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." xml:space="preserve">
|
||||
<source>**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
|
||||
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
|
||||
<target>**โปรดทราบ**: คุณจะไม่สามารถกู้คืนหรือเปลี่ยนรหัสผ่านได้หากคุณทำรหัสผ่านหาย</target>
|
||||
@@ -339,6 +351,10 @@
|
||||
<target>**คำเตือน**: การแจ้งเตือนแบบพุชทันทีจำเป็นต้องบันทึกรหัสผ่านไว้ใน Keychain</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**Warning**: the archive will be removed." xml:space="preserve">
|
||||
<source>**Warning**: the archive will be removed.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="**e2e encrypted** audio call" xml:space="preserve">
|
||||
<source>**e2e encrypted** audio call</source>
|
||||
<target>การโทรเสียงแบบ **encrypted จากต้นจนจบ**</target>
|
||||
@@ -585,6 +601,10 @@
|
||||
<target>การเปลี่ยนแปลงที่อยู่จะถูกยกเลิก จะใช้ที่อยู่เก่าของผู้รับ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can block a member for all." xml:space="preserve">
|
||||
<source>Admins can block a member for all.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
|
||||
<source>Admins can create the links to join groups.</source>
|
||||
<target>ผู้ดูแลระบบสามารถสร้างลิงก์เพื่อเข้าร่วมกลุ่มต่างๆได้</target>
|
||||
@@ -638,6 +658,10 @@
|
||||
<target>ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่. ผู้ติดต่อทั้งหมดของคุณจะยังคงเชื่อมต่ออยู่ การอัปเดตโปรไฟล์จะถูกส่งไปยังผู้ติดต่อของคุณ.</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." xml:space="preserve">
|
||||
<source>All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow" xml:space="preserve">
|
||||
<source>Allow</source>
|
||||
<target>อนุญาต</target>
|
||||
@@ -683,6 +707,10 @@
|
||||
<target>อนุญาตให้ลบข้อความที่ส่งไปแล้วอย่างถาวร</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send SimpleX links." xml:space="preserve">
|
||||
<source>Allow to send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Allow to send files and media." xml:space="preserve">
|
||||
<source>Allow to send files and media.</source>
|
||||
<target>อนุญาตให้ส่งไฟล์และสื่อ</target>
|
||||
@@ -761,6 +789,10 @@
|
||||
<target>รุ่นแอป: %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App data migration" xml:space="preserve">
|
||||
<source>App data migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="App encrypts new local files (except videos)." xml:space="preserve">
|
||||
<source>App encrypts new local files (except videos).</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -795,6 +827,18 @@
|
||||
<target>รูปร่างลักษณะ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Apply" xml:space="preserve">
|
||||
<source>Apply</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archive and upload" xml:space="preserve">
|
||||
<source>Archive and upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Archiving database" xml:space="preserve">
|
||||
<source>Archiving database</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Attach" xml:space="preserve">
|
||||
<source>Attach</source>
|
||||
<target>แนบ</target>
|
||||
@@ -974,6 +1018,10 @@
|
||||
<target>ยกเลิก</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cancel migration" xml:space="preserve">
|
||||
<source>Cancel migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cannot access keychain to save database password" xml:space="preserve">
|
||||
<source>Cannot access keychain to save database password</source>
|
||||
<target>ไม่สามารถเข้าถึง keychain เพื่อบันทึกรหัสผ่านฐานข้อมูล</target>
|
||||
@@ -984,6 +1032,10 @@
|
||||
<target>ไม่สามารถรับไฟล์ได้</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Cellular" xml:space="preserve">
|
||||
<source>Cellular</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Change" xml:space="preserve">
|
||||
<source>Change</source>
|
||||
<target>เปลี่ยน</target>
|
||||
@@ -1074,6 +1126,10 @@
|
||||
<source>Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat migrated!" xml:space="preserve">
|
||||
<source>Chat migrated!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Chat preferences" xml:space="preserve">
|
||||
<source>Chat preferences</source>
|
||||
<target>ค่ากําหนดในการแชท</target>
|
||||
@@ -1094,6 +1150,10 @@
|
||||
<target>อินเทอร์เฟซภาษาจีนและสเปน</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose _Migrate from another device_ on the new device and scan QR code." xml:space="preserve">
|
||||
<source>Choose _Migrate from another device_ on the new device and scan QR code.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Choose file" xml:space="preserve">
|
||||
<source>Choose file</source>
|
||||
<target>เลือกไฟล์</target>
|
||||
@@ -1163,6 +1223,10 @@
|
||||
<target>ยืนยันการอัพเกรดฐานข้อมูล</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm network settings" xml:space="preserve">
|
||||
<source>Confirm network settings</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm new passphrase…" xml:space="preserve">
|
||||
<source>Confirm new passphrase…</source>
|
||||
<target>ยืนยันรหัสผ่านใหม่…</target>
|
||||
@@ -1173,6 +1237,14 @@
|
||||
<target>ยืนยันรหัสผ่าน</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm that you remember database passphrase to migrate it." xml:space="preserve">
|
||||
<source>Confirm that you remember database passphrase to migrate it.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Confirm upload" xml:space="preserve">
|
||||
<source>Confirm upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Connect" xml:space="preserve">
|
||||
<source>Connect</source>
|
||||
<target>เชื่อมต่อ</target>
|
||||
@@ -1410,6 +1482,10 @@ This is your own one-time link!</source>
|
||||
<target>สร้างเมื่อ %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating archive link" xml:space="preserve">
|
||||
<source>Creating archive link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Creating link…" xml:space="preserve">
|
||||
<source>Creating link…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -1625,6 +1701,10 @@ This cannot be undone!</source>
|
||||
<target>ลบฐานข้อมูล</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete database from this device" xml:space="preserve">
|
||||
<source>Delete database from this device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Delete file" xml:space="preserve">
|
||||
<source>Delete file</source>
|
||||
<target>ลบไฟล์</target>
|
||||
@@ -1907,11 +1987,27 @@ This cannot be undone!</source>
|
||||
<target>ปรับลดรุ่นและเปิดแชท</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download" xml:space="preserve">
|
||||
<source>Download</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download failed" xml:space="preserve">
|
||||
<source>Download failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Download file" xml:space="preserve">
|
||||
<source>Download file</source>
|
||||
<target>ดาวน์โหลดไฟล์</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading archive" xml:space="preserve">
|
||||
<source>Downloading archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Downloading link details" xml:space="preserve">
|
||||
<source>Downloading link details</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Duplicate display name!" xml:space="preserve">
|
||||
<source>Duplicate display name!</source>
|
||||
<target>ชื่อที่แสดงซ้ำ!</target>
|
||||
@@ -1966,6 +2062,10 @@ This cannot be undone!</source>
|
||||
<target>เปิดใช้งานสําหรับทุกคน</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable in direct chats (BETA)!" xml:space="preserve">
|
||||
<source>Enable in direct chats (BETA)!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enable instant notifications?" xml:space="preserve">
|
||||
<source>Enable instant notifications?</source>
|
||||
<target>เปิดใช้งานการแจ้งเตือนทันที?</target>
|
||||
@@ -1996,6 +2096,10 @@ This cannot be undone!</source>
|
||||
<target>เปิดใช้งานรหัสผ่านแบบทําลายตัวเอง</target>
|
||||
<note>set passcode view</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enabled for" xml:space="preserve">
|
||||
<source>Enabled for</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Encrypt" xml:space="preserve">
|
||||
<source>Encrypt</source>
|
||||
<target>Encrypt</target>
|
||||
@@ -2075,6 +2179,10 @@ This cannot be undone!</source>
|
||||
<source>Enter group name…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase" xml:space="preserve">
|
||||
<source>Enter passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Enter passphrase…" xml:space="preserve">
|
||||
<source>Enter passphrase…</source>
|
||||
<target>ใส่รหัสผ่าน</target>
|
||||
@@ -2133,6 +2241,10 @@ This cannot be undone!</source>
|
||||
<target>เกิดข้อผิดพลาดในการเพิ่มสมาชิก</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error allowing contact PQ encryption" xml:space="preserve">
|
||||
<source>Error allowing contact PQ encryption</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error changing address" xml:space="preserve">
|
||||
<source>Error changing address</source>
|
||||
<target>เกิดข้อผิดพลาดในการเปลี่ยนที่อยู่</target>
|
||||
@@ -2220,6 +2332,10 @@ This cannot be undone!</source>
|
||||
<target>เกิดข้อผิดพลาดในการลบโปรไฟล์ผู้ใช้</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error downloading the archive" xml:space="preserve">
|
||||
<source>Error downloading the archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error enabling delivery receipts!" xml:space="preserve">
|
||||
<source>Error enabling delivery receipts!</source>
|
||||
<target>เกิดข้อผิดพลาดในการเปิดใช้ใบเสร็จการจัดส่ง!</target>
|
||||
@@ -2294,6 +2410,10 @@ This cannot be undone!</source>
|
||||
<target>เกิดข้อผิดพลาดในการบันทึกรหัสผ่านไปยัง keychain</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving settings" xml:space="preserve">
|
||||
<source>Error saving settings</source>
|
||||
<note>when migrating</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error saving user password" xml:space="preserve">
|
||||
<source>Error saving user password</source>
|
||||
<target>เกิดข้อผิดพลาดในการบันทึกรหัสผ่านผู้ใช้</target>
|
||||
@@ -2362,6 +2482,14 @@ This cannot be undone!</source>
|
||||
<target>เกิดข้อผิดพลาดในการอัปเดตข้อมูลส่วนตัวของผู้ใช้</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error uploading the archive" xml:space="preserve">
|
||||
<source>Error uploading the archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error verifying passphrase:" xml:space="preserve">
|
||||
<source>Error verifying passphrase:</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Error: " xml:space="preserve">
|
||||
<source>Error: </source>
|
||||
<target>ผิดพลาด: </target>
|
||||
@@ -2411,6 +2539,10 @@ This cannot be undone!</source>
|
||||
<target>ที่เก็บถาวรฐานข้อมูลที่ส่งออก</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exported file doesn't exist" xml:space="preserve">
|
||||
<source>Exported file doesn't exist</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Exporting database archive…" xml:space="preserve">
|
||||
<source>Exporting database archive…</source>
|
||||
<target>กำลังส่งออกที่เก็บถาวรฐานข้อมูล…</target>
|
||||
@@ -2470,6 +2602,10 @@ This cannot be undone!</source>
|
||||
<target>ไฟล์และสื่อเป็นสิ่งต้องห้ามในกลุ่มนี้</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media not allowed" xml:space="preserve">
|
||||
<source>Files and media not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Files and media prohibited!" xml:space="preserve">
|
||||
<source>Files and media prohibited!</source>
|
||||
<target>ไฟล์และสื่อต้องห้าม!</target>
|
||||
@@ -2480,6 +2616,14 @@ This cannot be undone!</source>
|
||||
<target>กรองแชทที่ยังไม่อ่านและแชทโปรด</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration" xml:space="preserve">
|
||||
<source>Finalize migration</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finalize migration on another device." xml:space="preserve">
|
||||
<source>Finalize migration on another device.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
|
||||
<source>Finally, we have them! 🚀</source>
|
||||
<target>ในที่สุดเราก็มีแล้ว! 🚀</target>
|
||||
@@ -2525,6 +2669,18 @@ This cannot be undone!</source>
|
||||
<target>สำหรับคอนโซล</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forward" xml:space="preserve">
|
||||
<source>Forward</source>
|
||||
<note>chat item action</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded" xml:space="preserve">
|
||||
<source>Forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Forwarded from" xml:space="preserve">
|
||||
<source>Forwarded from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Found desktop" xml:space="preserve">
|
||||
<source>Found desktop</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2631,6 +2787,10 @@ This cannot be undone!</source>
|
||||
<target>สมาชิกกลุ่มสามารถลบข้อความที่ส่งแล้วอย่างถาวร</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send SimpleX links." xml:space="preserve">
|
||||
<source>Group members can send SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Group members can send direct messages." xml:space="preserve">
|
||||
<source>Group members can send direct messages.</source>
|
||||
<target>สมาชิกกลุ่มสามารถส่งข้อความโดยตรงได้</target>
|
||||
@@ -2765,6 +2925,10 @@ This cannot be undone!</source>
|
||||
<target>วิธีใช้เซิร์ฟเวอร์ของคุณ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Hungarian interface" xml:space="preserve">
|
||||
<source>Hungarian interface</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
|
||||
<source>ICE servers (one per line)</source>
|
||||
<target>เซิร์ฟเวอร์ ICE (หนึ่งเครื่องต่อสาย)</target>
|
||||
@@ -2830,6 +2994,14 @@ This cannot be undone!</source>
|
||||
<target>นำเข้าฐานข้อมูล</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Import failed" xml:space="preserve">
|
||||
<source>Import failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Importing archive" xml:space="preserve">
|
||||
<source>Importing archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Improved message delivery" xml:space="preserve">
|
||||
<source>Improved message delivery</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -2844,6 +3016,10 @@ This cannot be undone!</source>
|
||||
<target>ปรับปรุงการกําหนดค่าเซิร์ฟเวอร์แล้ว</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In order to continue, chat should be stopped." xml:space="preserve">
|
||||
<source>In order to continue, chat should be stopped.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="In reply to" xml:space="preserve">
|
||||
<source>In reply to</source>
|
||||
<target>ในการตอบกลับถึง</target>
|
||||
@@ -2950,6 +3126,10 @@ This cannot be undone!</source>
|
||||
<source>Invalid link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid migration confirmation" xml:space="preserve">
|
||||
<source>Invalid migration confirmation</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Invalid name!" xml:space="preserve">
|
||||
<source>Invalid name!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -3304,6 +3484,10 @@ This is your link for group %@!</source>
|
||||
<target>ข้อความ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Message too large" xml:space="preserve">
|
||||
<source>Message too large</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages" xml:space="preserve">
|
||||
<source>Messages</source>
|
||||
<target>ข้อความ</target>
|
||||
@@ -3318,11 +3502,47 @@ This is your link for group %@!</source>
|
||||
<source>Messages from %@ will be shown!</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **end-to-end encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery." xml:space="preserve">
|
||||
<source>Messages, files and calls are protected by **quantum resistant e2e encryption** with perfect forward secrecy, repudiation and break-in recovery.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate device" xml:space="preserve">
|
||||
<source>Migrate device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate from another device" xml:space="preserve">
|
||||
<source>Migrate from another device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate here" xml:space="preserve">
|
||||
<source>Migrate here</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device" xml:space="preserve">
|
||||
<source>Migrate to another device</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrate to another device via QR code." xml:space="preserve">
|
||||
<source>Migrate to another device via QR code.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating" xml:space="preserve">
|
||||
<source>Migrating</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migrating database archive…" xml:space="preserve">
|
||||
<source>Migrating database archive…</source>
|
||||
<target>กำลังย้ายข้อมูลที่เก็บถาวรของฐานข้อมูล…</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration complete" xml:space="preserve">
|
||||
<source>Migration complete</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Migration error:" xml:space="preserve">
|
||||
<source>Migration error:</source>
|
||||
<target>ข้อผิดพลาดในการย้ายข้อมูล:</target>
|
||||
@@ -3397,6 +3617,10 @@ This is your link for group %@!</source>
|
||||
<target>เครือข่ายและเซิร์ฟเวอร์</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network connection" xml:space="preserve">
|
||||
<source>Network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Network settings" xml:space="preserve">
|
||||
<source>Network settings</source>
|
||||
<target>การตั้งค่าเครือข่าย</target>
|
||||
@@ -3504,6 +3728,10 @@ This is your link for group %@!</source>
|
||||
<target>ไม่มีประวัติ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No network connection" xml:space="preserve">
|
||||
<source>No network connection</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="No permission to record voice message" xml:space="preserve">
|
||||
<source>No permission to record voice message</source>
|
||||
<target>ไม่อนุญาตให้บันทึกข้อความเสียง</target>
|
||||
@@ -3674,6 +3902,10 @@ This is your link for group %@!</source>
|
||||
<source>Open group</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open migration to another device" xml:space="preserve">
|
||||
<source>Open migration to another device</source>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Open user profiles" xml:space="preserve">
|
||||
<source>Open user profiles</source>
|
||||
<target>เปิดโปรไฟล์ผู้ใช้</target>
|
||||
@@ -3688,14 +3920,26 @@ This is your link for group %@!</source>
|
||||
<source>Opening app…</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or paste archive link" xml:space="preserve">
|
||||
<source>Or paste archive link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or scan QR code" xml:space="preserve">
|
||||
<source>Or scan QR code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or securely share this file link" xml:space="preserve">
|
||||
<source>Or securely share this file link</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Or show this code" xml:space="preserve">
|
||||
<source>Or show this code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Other" xml:space="preserve">
|
||||
<source>Other</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PING count" xml:space="preserve">
|
||||
<source>PING count</source>
|
||||
<target>จํานวน PING</target>
|
||||
@@ -3772,6 +4016,10 @@ This is your link for group %@!</source>
|
||||
<target>ข้อผิดพลาดในการถอดรหัสอย่างถาวร</target>
|
||||
<note>message decrypt error item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Picture-in-picture calls" xml:space="preserve">
|
||||
<source>Picture-in-picture calls</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please ask your contact to enable sending voice messages." xml:space="preserve">
|
||||
<source>Please ask your contact to enable sending voice messages.</source>
|
||||
<target>โปรดขอให้ผู้ติดต่อของคุณเปิดใช้งานการส่งข้อความเสียง</target>
|
||||
@@ -3792,6 +4040,10 @@ This is your link for group %@!</source>
|
||||
<target>โปรดตรวจสอบความต้องการของคุณและการตั้งค่าผู้ติดต่อ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please confirm that network settings are correct for this device." xml:space="preserve">
|
||||
<source>Please confirm that network settings are correct for this device.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Please contact developers. Error: %@" xml:space="preserve">
|
||||
<source>Please contact developers.
|
||||
Error: %@</source>
|
||||
@@ -3847,6 +4099,10 @@ Error: %@</source>
|
||||
<target>อาจเป็นไปได้ว่าลายนิ้วมือของ certificate ในที่อยู่เซิร์ฟเวอร์ไม่ถูกต้อง</target>
|
||||
<note>server test error</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Post-quantum E2EE" xml:space="preserve">
|
||||
<source>Post-quantum E2EE</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Preserve the last message draft, with attachments." xml:space="preserve">
|
||||
<source>Preserve the last message draft, with attachments.</source>
|
||||
<target>เก็บข้อความที่ร่างไว้ล่าสุดพร้อมไฟล์แนบ</target>
|
||||
@@ -3934,6 +4190,10 @@ Error: %@</source>
|
||||
<target>ห้ามแสดงปฏิกิริยาต่อข้อความ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending SimpleX links." xml:space="preserve">
|
||||
<source>Prohibit sending SimpleX links.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Prohibit sending direct messages to members." xml:space="preserve">
|
||||
<source>Prohibit sending direct messages to members.</source>
|
||||
<target>ห้ามส่งข้อความโดยตรงถึงสมาชิก</target>
|
||||
@@ -3979,6 +4239,14 @@ Error: %@</source>
|
||||
<target>การแจ้งเตือนแบบทันที</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Push server" xml:space="preserve">
|
||||
<source>Push server</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Quantum resistant encryption" xml:space="preserve">
|
||||
<source>Quantum resistant encryption</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Rate the app" xml:space="preserve">
|
||||
<source>Rate the app</source>
|
||||
<target>ให้คะแนนแอป</target>
|
||||
@@ -4052,6 +4320,10 @@ Error: %@</source>
|
||||
<target>ที่อยู่ผู้รับจะถูกเปลี่ยนเป็นเซิร์ฟเวอร์อื่น การเปลี่ยนแปลงที่อยู่จะเสร็จสมบูรณ์หลังจากที่ผู้ส่งออนไลน์</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving concurrency" xml:space="preserve">
|
||||
<source>Receiving concurrency</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
|
||||
<source>Receiving file will be stopped.</source>
|
||||
<target>การรับไฟล์จะหยุดลง</target>
|
||||
@@ -4066,6 +4338,10 @@ Error: %@</source>
|
||||
<source>Recent history and improved [directory bot](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipient(s) can't see who this message is from." xml:space="preserve">
|
||||
<source>Recipient(s) can't see who this message is from.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Recipients see updates as you type them." xml:space="preserve">
|
||||
<source>Recipients see updates as you type them.</source>
|
||||
<target>ผู้รับจะเห็นการอัปเดตเมื่อคุณพิมพ์</target>
|
||||
@@ -4159,10 +4435,22 @@ Error: %@</source>
|
||||
<source>Repeat connection request?</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat download" xml:space="preserve">
|
||||
<source>Repeat download</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat import" xml:space="preserve">
|
||||
<source>Repeat import</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat join request?" xml:space="preserve">
|
||||
<source>Repeat join request?</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Repeat upload" xml:space="preserve">
|
||||
<source>Repeat upload</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Reply" xml:space="preserve">
|
||||
<source>Reply</source>
|
||||
<target>ตอบ</target>
|
||||
@@ -4262,6 +4550,10 @@ Error: %@</source>
|
||||
<target>เซิร์ฟเวอร์ SMP</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Safer groups" xml:space="preserve">
|
||||
<source>Safer groups</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Save" xml:space="preserve">
|
||||
<source>Save</source>
|
||||
<target>บันทึก</target>
|
||||
@@ -4342,11 +4634,19 @@ Error: %@</source>
|
||||
<target>บันทึกข้อความต้อนรับ?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved" xml:space="preserve">
|
||||
<source>Saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
|
||||
<source>Saved WebRTC ICE servers will be removed</source>
|
||||
<target>เซิร์ฟเวอร์ WebRTC ICE ที่บันทึกไว้จะถูกลบออก</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved from" xml:space="preserve">
|
||||
<source>Saved from</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Saved message" xml:space="preserve">
|
||||
<source>Saved message</source>
|
||||
<note>message info title</note>
|
||||
@@ -4618,6 +4918,10 @@ Error: %@</source>
|
||||
<target>ตั้งรหัสผ่าน</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase" xml:space="preserve">
|
||||
<source>Set passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Set passphrase to export" xml:space="preserve">
|
||||
<source>Set passphrase to export</source>
|
||||
<target>ตั้งรหัสผ่านเพื่อส่งออก</target>
|
||||
@@ -4672,6 +4976,10 @@ Error: %@</source>
|
||||
<target>แชร์กับผู้ติดต่อ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show QR code" xml:space="preserve">
|
||||
<source>Show QR code</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Show calls in phone history" xml:space="preserve">
|
||||
<source>Show calls in phone history</source>
|
||||
<target>แสดงการโทรในประวัติการโทร</target>
|
||||
@@ -4749,6 +5057,14 @@ Error: %@</source>
|
||||
<trans-unit id="SimpleX links" xml:space="preserve">
|
||||
<source>SimpleX links</source>
|
||||
<target>ลิงก์ SimpleX</target>
|
||||
<note>chat feature</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links are prohibited in this group." xml:space="preserve">
|
||||
<source>SimpleX links are prohibited in this group.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX links not allowed" xml:space="preserve">
|
||||
<source>SimpleX links not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SimpleX one-time invitation" xml:space="preserve">
|
||||
@@ -4808,6 +5124,10 @@ Error: %@</source>
|
||||
<target>หยุด SimpleX</target>
|
||||
<note>authentication reason</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat" xml:space="preserve">
|
||||
<source>Stop chat</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stop chat to enable database actions" xml:space="preserve">
|
||||
<source>Stop chat to enable database actions</source>
|
||||
<target>หยุดการแชทเพื่อเปิดใช้งานการดำเนินการกับฐานข้อมูล</target>
|
||||
@@ -4848,6 +5168,10 @@ Error: %@</source>
|
||||
<target>หยุดแชร์ที่อยู่ไหม?</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Stopping chat" xml:space="preserve">
|
||||
<source>Stopping chat</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Submit" xml:space="preserve">
|
||||
<source>Submit</source>
|
||||
<target>ส่ง</target>
|
||||
@@ -5090,6 +5414,14 @@ It can happen because of some bug or when the connection is compromised.</source
|
||||
<target>การดำเนินการนี้ไม่สามารถยกเลิกได้ - โปรไฟล์ ผู้ติดต่อ ข้อความ และไฟล์ของคุณจะสูญหายไปอย่างถาวร</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by end-to-end encryption.</source>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This chat is protected by quantum resistant end-to-end encryption." xml:space="preserve">
|
||||
<source>This chat is protected by quantum resistant end-to-end encryption.</source>
|
||||
<note>E2EE info chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="This device name" xml:space="preserve">
|
||||
<source>This device name</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -5368,11 +5700,19 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>อัปเกรดและเปิดการแชท</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload failed" xml:space="preserve">
|
||||
<source>Upload failed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Upload file" xml:space="preserve">
|
||||
<source>Upload file</source>
|
||||
<target>อัปโหลดไฟล์</target>
|
||||
<note>server test step</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uploading archive" xml:space="preserve">
|
||||
<source>Uploading archive</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use .onion hosts" xml:space="preserve">
|
||||
<source>Use .onion hosts</source>
|
||||
<target>ใช้โฮสต์ .onion</target>
|
||||
@@ -5419,6 +5759,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>ใช้เซิร์ฟเวอร์</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Use the app while in the call." xml:space="preserve">
|
||||
<source>Use the app while in the call.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="User profile" xml:space="preserve">
|
||||
<source>User profile</source>
|
||||
<target>โปรไฟล์ผู้ใช้</target>
|
||||
@@ -5451,6 +5795,14 @@ To connect, please ask your contact to create another connection link and check
|
||||
<source>Verify connections</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify database passphrase" xml:space="preserve">
|
||||
<source>Verify database passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify passphrase" xml:space="preserve">
|
||||
<source>Verify passphrase</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Verify security code" xml:space="preserve">
|
||||
<source>Verify security code</source>
|
||||
<target>ตรวจสอบรหัสความปลอดภัย</target>
|
||||
@@ -5509,6 +5861,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>ข้อความเสียงเป็นสิ่งต้องห้ามในกลุ่มนี้</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages not allowed" xml:space="preserve">
|
||||
<source>Voice messages not allowed</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Voice messages prohibited!" xml:space="preserve">
|
||||
<source>Voice messages prohibited!</source>
|
||||
<target>ห้ามข้อความเสียง!</target>
|
||||
@@ -5538,6 +5894,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>กําลังรอวิดีโอ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: starting chat on multiple devices is not supported and will cause message delivery failures" xml:space="preserve">
|
||||
<source>Warning: starting chat on multiple devices is not supported and will cause message delivery failures</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Warning: you may lose some data!" xml:space="preserve">
|
||||
<source>Warning: you may lose some data!</source>
|
||||
<target>คำเตือน: คุณอาจสูญเสียข้อมูลบางส่วน!</target>
|
||||
@@ -5558,6 +5918,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>ข้อความต้อนรับ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Welcome message is too long" xml:space="preserve">
|
||||
<source>Welcome message is too long</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="What's new" xml:space="preserve">
|
||||
<source>What's new</source>
|
||||
<target>มีอะไรใหม่</target>
|
||||
@@ -5578,6 +5942,14 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>เมื่อคุณแชร์โปรไฟล์ที่ไม่ระบุตัวตนกับใครสักคน โปรไฟล์นี้จะใช้สำหรับกลุ่มที่พวกเขาเชิญคุณ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="WiFi" xml:space="preserve">
|
||||
<source>WiFi</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="Wired ethernet" xml:space="preserve">
|
||||
<source>Wired ethernet</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="With encrypted files and media." xml:space="preserve">
|
||||
<source>With encrypted files and media.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
@@ -5611,6 +5983,10 @@ To connect, please ask your contact to create another connection link and check
|
||||
<target>คุณ</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You **must not** use the same database on two devices." xml:space="preserve">
|
||||
<source>You **must not** use the same database on two devices.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You accepted connection" xml:space="preserve">
|
||||
<source>You accepted connection</source>
|
||||
<target>คุณยอมรับการเชื่อมต่อ</target>
|
||||
@@ -5690,6 +6066,10 @@ Repeat join request?</source>
|
||||
<target>คุณสามารถเปิดใช้งานได้ในภายหลังผ่านการตั้งค่าความเป็นส่วนตัวและความปลอดภัยของแอป</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can give another try." xml:space="preserve">
|
||||
<source>You can give another try.</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="You can hide or mute a user profile - swipe it to the right." xml:space="preserve">
|
||||
<source>You can hide or mute a user profile - swipe it to the right.</source>
|
||||
<target>คุณสามารถซ่อนหรือปิดเสียงโปรไฟล์ผู้ใช้ - ปัดไปทางขวา</target>
|
||||
@@ -6031,6 +6411,10 @@ SimpleX servers cannot see your profile.</source>
|
||||
<target>ผู้ดูแลระบบ</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="admins" xml:space="preserve">
|
||||
<source>admins</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="agreeing encryption for %@…" xml:space="preserve">
|
||||
<source>agreeing encryption for %@…</source>
|
||||
<target>ยอมรับ encryption สำหรับ %@…</target>
|
||||
@@ -6041,6 +6425,10 @@ SimpleX servers cannot see your profile.</source>
|
||||
<target>เห็นด้วยกับการ encryption…</target>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="all members" xml:space="preserve">
|
||||
<source>all members</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="always" xml:space="preserve">
|
||||
<source>always</source>
|
||||
<target>เสมอ</target>
|
||||
@@ -6071,7 +6459,7 @@ SimpleX servers cannot see your profile.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked" xml:space="preserve">
|
||||
<source>blocked</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked %@" xml:space="preserve">
|
||||
<source>blocked %@</source>
|
||||
@@ -6079,7 +6467,7 @@ SimpleX servers cannot see your profile.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="blocked by admin" xml:space="preserve">
|
||||
<source>blocked by admin</source>
|
||||
<note>blocked chat item</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="bold" xml:space="preserve">
|
||||
<source>bold</source>
|
||||
@@ -6361,6 +6749,10 @@ SimpleX servers cannot see your profile.</source>
|
||||
<source>event happened</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="forwarded" xml:space="preserve">
|
||||
<source>forwarded</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="group deleted" xml:space="preserve">
|
||||
<source>group deleted</source>
|
||||
<target>ลบกลุ่มแล้ว</target>
|
||||
@@ -6503,7 +6895,7 @@ SimpleX servers cannot see your profile.</source>
|
||||
<trans-unit id="moderated by %@" xml:space="preserve">
|
||||
<source>moderated by %@</source>
|
||||
<target>กลั่นกรองโดย %@</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
<note>marked deleted chat item preview text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="months" xml:space="preserve">
|
||||
<source>months</source>
|
||||
@@ -6567,11 +6959,19 @@ SimpleX servers cannot see your profile.</source>
|
||||
<target>เจ้าของ</target>
|
||||
<note>member role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="owners" xml:space="preserve">
|
||||
<source>owners</source>
|
||||
<note>feature role</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="peer-to-peer" xml:space="preserve">
|
||||
<source>peer-to-peer</source>
|
||||
<target>เพื่อนต่อเพื่อน</target>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="quantum resistant e2e encryption" xml:space="preserve">
|
||||
<source>quantum resistant e2e encryption</source>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="received answer…" xml:space="preserve">
|
||||
<source>received answer…</source>
|
||||
<target>ได้รับคำตอบ…</target>
|
||||
@@ -6610,6 +7010,14 @@ SimpleX servers cannot see your profile.</source>
|
||||
<target>ลบคุณออกแล้ว</target>
|
||||
<note>rcv group event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved" xml:space="preserve">
|
||||
<source>saved</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="saved from %@" xml:space="preserve">
|
||||
<source>saved from %@</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="sec" xml:space="preserve">
|
||||
<source>sec</source>
|
||||
<target>วินาที</target>
|
||||
@@ -6642,6 +7050,10 @@ SimpleX servers cannot see your profile.</source>
|
||||
<source>set new profile picture</source>
|
||||
<note>profile update event chat item</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="standard end-to-end encryption" xml:space="preserve">
|
||||
<source>standard end-to-end encryption</source>
|
||||
<note>chat item text</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="starting…" xml:space="preserve">
|
||||
<source>starting…</source>
|
||||
<target>กำลังเริ่มต้น…</target>
|
||||
@@ -6738,6 +7150,10 @@ SimpleX servers cannot see your profile.</source>
|
||||
<target>ใช่</target>
|
||||
<note>pref value</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you" xml:space="preserve">
|
||||
<source>you</source>
|
||||
<note>No comment provided by engineer.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="you are invited to group" xml:space="preserve">
|
||||
<source>you are invited to group</source>
|
||||
<target>คุณได้รับเชิญให้เข้าร่วมกลุ่ม</target>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,64 +0,0 @@
|
||||
//
|
||||
// ConcurrentQueue.swift
|
||||
// SimpleX NSE
|
||||
//
|
||||
// Created by Evgeny on 08/12/2023.
|
||||
// Copyright © 2023 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct DequeueElement<T> {
|
||||
var elementId: UUID?
|
||||
var task: Task<T?, Never>
|
||||
}
|
||||
|
||||
class ConcurrentQueue<T> {
|
||||
private var queue: [T] = []
|
||||
private var queueLock = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.concurrent-queue.lock.\(UUID())")
|
||||
private var continuations = [(elementId: UUID, continuation: CheckedContinuation<T?, Never>)]()
|
||||
|
||||
func enqueue(_ el: T) {
|
||||
resumeContinuation(el) { self.queue.append(el) }
|
||||
}
|
||||
|
||||
func frontEnqueue(_ el: T) {
|
||||
resumeContinuation(el) { self.queue.insert(el, at: 0) }
|
||||
}
|
||||
|
||||
private func resumeContinuation(_ el: T, add: @escaping () -> Void) {
|
||||
queueLock.sync {
|
||||
if let (_, cont) = continuations.first {
|
||||
continuations.remove(at: 0)
|
||||
cont.resume(returning: el)
|
||||
} else {
|
||||
add()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dequeue() -> DequeueElement<T> {
|
||||
queueLock.sync {
|
||||
if queue.isEmpty {
|
||||
let elementId = UUID()
|
||||
let task = Task {
|
||||
await withCheckedContinuation { cont in
|
||||
continuations.append((elementId, cont))
|
||||
}
|
||||
}
|
||||
return DequeueElement(elementId: elementId, task: task)
|
||||
} else {
|
||||
let el = queue.remove(at: 0)
|
||||
return DequeueElement(task: Task { el })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cancelDequeue(_ elementId: UUID) {
|
||||
queueLock.sync {
|
||||
let cancelled = continuations.filter { $0.elementId == elementId }
|
||||
continuations.removeAll { $0.elementId == elementId }
|
||||
cancelled.forEach { $0.continuation.resume(returning: nil) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,110 +22,6 @@ let nseSuspendSchedule: SuspendSchedule = (2, 4)
|
||||
|
||||
let fastNSESuspendSchedule: SuspendSchedule = (1, 1)
|
||||
|
||||
typealias NtfStream = ConcurrentQueue<NSENotification>
|
||||
|
||||
// Notifications are delivered via concurrent queues, as they are all received from chat controller in a single loop that
|
||||
// writes to ConcurrentQueue and when notification is processed, the instance of Notification service extension reads from the queue.
|
||||
// One queue per connection (entity) is used.
|
||||
// The concurrent queues allow read cancellation, to ensure that notifications are not lost in case the current thread completes
|
||||
// before expected notification is read (multiple notifications can be expected, because one notification can be delivered for several messages).
|
||||
actor PendingNtfs {
|
||||
static let shared = PendingNtfs()
|
||||
private var ntfStreams: [String: NtfStream] = [:]
|
||||
|
||||
func createStream(_ id: String) async {
|
||||
logger.debug("NotificationService PendingNtfs.createStream: \(id)")
|
||||
if ntfStreams[id] == nil {
|
||||
ntfStreams[id] = ConcurrentQueue()
|
||||
logger.debug("NotificationService PendingNtfs.createStream: created ConcurrentQueue")
|
||||
}
|
||||
}
|
||||
|
||||
func readStream(_ id: String, for nse: NotificationService, ntfInfo: NtfMessages) async {
|
||||
logger.debug("NotificationService PendingNtfs.readStream: \(id) \(ntfInfo.ntfMessages.count)")
|
||||
if !ntfInfo.user.showNotifications {
|
||||
nse.setBestAttemptNtf(.empty)
|
||||
}
|
||||
if let s = ntfStreams[id] {
|
||||
logger.debug("NotificationService PendingNtfs.readStream: has stream")
|
||||
var expected = Set(ntfInfo.ntfMessages.map { $0.msgId })
|
||||
logger.debug("NotificationService PendingNtfs.readStream: expecting: \(expected)")
|
||||
var readCancelled = false
|
||||
var dequeued: DequeueElement<NSENotification>?
|
||||
nse.cancelRead = {
|
||||
readCancelled = true
|
||||
if let elementId = dequeued?.elementId {
|
||||
s.cancelDequeue(elementId)
|
||||
}
|
||||
}
|
||||
while !readCancelled {
|
||||
dequeued = s.dequeue()
|
||||
if let ntf = await dequeued?.task.value {
|
||||
if readCancelled {
|
||||
logger.debug("NotificationService PendingNtfs.readStream: read cancelled, put ntf to queue front")
|
||||
s.frontEnqueue(ntf)
|
||||
break
|
||||
} else if case let .msgInfo(info) = ntf {
|
||||
let found = expected.remove(info.msgId)
|
||||
if found != nil {
|
||||
logger.debug("NotificationService PendingNtfs.readStream: msgInfo, last: \(expected.isEmpty)")
|
||||
if expected.isEmpty { break }
|
||||
} else if let msgTs = ntfInfo.msgTs, info.msgTs > msgTs {
|
||||
logger.debug("NotificationService PendingNtfs.readStream: unexpected msgInfo")
|
||||
s.frontEnqueue(ntf)
|
||||
break
|
||||
}
|
||||
} else if ntfInfo.user.showNotifications {
|
||||
logger.debug("NotificationService PendingNtfs.readStream: setting best attempt")
|
||||
nse.setBestAttemptNtf(ntf)
|
||||
if ntf.isCallInvitation { break }
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
nse.cancelRead = nil
|
||||
logger.debug("NotificationService PendingNtfs.readStream: exiting")
|
||||
}
|
||||
}
|
||||
|
||||
func writeStream(_ id: String, _ ntf: NSENotification) async {
|
||||
logger.debug("NotificationService PendingNtfs.writeStream: \(id)")
|
||||
if let s = ntfStreams[id] {
|
||||
logger.debug("NotificationService PendingNtfs.writeStream: writing ntf")
|
||||
s.enqueue(ntf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The current implementation assumes concurrent notification delivery and uses semaphores
|
||||
// to process only one notification per connection (entity) at a time.
|
||||
class NtfStreamSemaphores {
|
||||
static let shared = NtfStreamSemaphores()
|
||||
private static let queue = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.notification-semaphores.lock")
|
||||
private var semaphores: [String: DispatchSemaphore] = [:]
|
||||
|
||||
func waitForStream(_ id: String) {
|
||||
streamSemaphore(id, value: 0)?.wait()
|
||||
}
|
||||
|
||||
func signalStreamReady(_ id: String) {
|
||||
streamSemaphore(id, value: 1)?.signal()
|
||||
}
|
||||
|
||||
// this function returns nil if semaphore is just created, so passed value shoud be coordinated with the desired end value of the semaphore
|
||||
private func streamSemaphore(_ id: String, value: Int) -> DispatchSemaphore? {
|
||||
NtfStreamSemaphores.queue.sync {
|
||||
if let s = semaphores[id] {
|
||||
return s
|
||||
} else {
|
||||
semaphores[id] = DispatchSemaphore(value: value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum NSENotification {
|
||||
case nse(UNMutableNotificationContent)
|
||||
case callkit(RcvCallInvitation)
|
||||
@@ -149,7 +45,7 @@ class NSEThreads {
|
||||
static let shared = NSEThreads()
|
||||
private static let queue = DispatchQueue(label: "chat.simplex.app.SimpleX-NSE.notification-threads.lock")
|
||||
private var allThreads: Set<UUID> = []
|
||||
private var activeThreads: Set<UUID> = []
|
||||
private var activeThreads: [(UUID, NotificationService)] = []
|
||||
|
||||
func newThread() -> UUID {
|
||||
NSEThreads.queue.sync {
|
||||
@@ -158,19 +54,42 @@ class NSEThreads {
|
||||
}
|
||||
}
|
||||
|
||||
func startThread(_ t: UUID) {
|
||||
func startThread(_ t: UUID, _ service: NotificationService) {
|
||||
NSEThreads.queue.sync {
|
||||
if allThreads.contains(t) {
|
||||
_ = activeThreads.insert(t)
|
||||
activeThreads.append((t, service))
|
||||
} else {
|
||||
logger.warning("NotificationService startThread: thread \(t) was removed before it started")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processNotification(_ id: ChatId, _ ntf: NSENotification) async -> Void {
|
||||
var waitTime: Int64 = 5_000_000000
|
||||
while waitTime > 0 {
|
||||
if let (_, nse) = rcvEntityThread(id),
|
||||
nse.shouldProcessNtf && nse.processReceivedNtf(ntf) {
|
||||
break
|
||||
} else {
|
||||
try? await Task.sleep(nanoseconds: 10_000000)
|
||||
waitTime -= 10_000000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func rcvEntityThread(_ id: ChatId) -> (UUID, NotificationService)? {
|
||||
NSEThreads.queue.sync {
|
||||
activeThreads.first(where: { (_, nse) in nse.receiveEntityId == id })
|
||||
}
|
||||
}
|
||||
|
||||
func endThread(_ t: UUID) -> Bool {
|
||||
NSEThreads.queue.sync {
|
||||
let tActive = activeThreads.remove(t)
|
||||
let tActive: UUID? = if let index = activeThreads.firstIndex(where: { $0.0 == t }) {
|
||||
activeThreads.remove(at: index).0
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
let t = allThreads.remove(t)
|
||||
if tActive != nil && activeThreads.isEmpty {
|
||||
return true
|
||||
@@ -198,8 +117,11 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
// thread is added to allThreads here - if thread did not start chat,
|
||||
// chat does not need to be suspended but NSE state still needs to be set to "suspended".
|
||||
var threadId: UUID? = NSEThreads.shared.newThread()
|
||||
var notificationInfo: NtfMessages?
|
||||
var receiveEntityId: String?
|
||||
var cancelRead: (() -> Void)?
|
||||
var expectedMessages: Set<String> = []
|
||||
// return true if the message is taken - it prevents sending it to another NotificationService instance for processing
|
||||
var shouldProcessNtf = false
|
||||
var appSubscriber: AppSubscriber?
|
||||
var returnedSuspension = false
|
||||
|
||||
@@ -265,7 +187,7 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
// check it here again
|
||||
appStateGroupDefault.get().inactive {
|
||||
// thread is added to activeThreads tracking set here - if thread started chat it needs to be suspended
|
||||
if let t = threadId { NSEThreads.shared.startThread(t) }
|
||||
if let t = threadId { NSEThreads.shared.startThread(t, self) }
|
||||
let dbStatus = startChat()
|
||||
if case .ok = dbStatus,
|
||||
let ntfInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) {
|
||||
@@ -276,17 +198,11 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
? .nse(createConnectionEventNtf(ntfInfo.user, connEntity))
|
||||
: .empty
|
||||
)
|
||||
if let id = connEntity.id {
|
||||
if let id = connEntity.id, ntfInfo.msgTs != nil {
|
||||
notificationInfo = ntfInfo
|
||||
receiveEntityId = id
|
||||
NtfStreamSemaphores.shared.waitForStream(id)
|
||||
if receiveEntityId != nil {
|
||||
Task {
|
||||
logger.debug("NotificationService: receiveNtfMessages: in Task, connEntity id \(id)")
|
||||
await PendingNtfs.shared.createStream(id)
|
||||
await PendingNtfs.shared.readStream(id, for: self, ntfInfo: ntfInfo)
|
||||
deliverBestAttemptNtf()
|
||||
}
|
||||
}
|
||||
expectedMessages = Set(ntfInfo.ntfMessages.map { $0.msgId })
|
||||
shouldProcessNtf = true
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -302,6 +218,38 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
deliverBestAttemptNtf(urgent: true)
|
||||
}
|
||||
|
||||
func processReceivedNtf(_ ntf: NSENotification) -> Bool {
|
||||
guard let ntfInfo = notificationInfo, let msgTs = ntfInfo.msgTs else { return false }
|
||||
if !ntfInfo.user.showNotifications {
|
||||
self.setBestAttemptNtf(.empty)
|
||||
}
|
||||
if case let .msgInfo(info) = ntf {
|
||||
let found = expectedMessages.remove(info.msgId)
|
||||
if found != nil {
|
||||
logger.debug("NotificationService processNtf: msgInfo, last: \(self.expectedMessages.isEmpty)")
|
||||
if expectedMessages.isEmpty {
|
||||
self.deliverBestAttemptNtf()
|
||||
}
|
||||
return true
|
||||
} else if info.msgTs > msgTs {
|
||||
logger.debug("NotificationService processNtf: unexpected msgInfo, let other instance to process it, stopping this one")
|
||||
self.deliverBestAttemptNtf()
|
||||
return false
|
||||
} else {
|
||||
logger.debug("NotificationService processNtf: unknown message, let other instance to process it")
|
||||
return false
|
||||
}
|
||||
} else if ntfInfo.user.showNotifications {
|
||||
logger.debug("NotificationService processNtf: setting best attempt")
|
||||
self.setBestAttemptNtf(ntf)
|
||||
if ntf.isCallInvitation {
|
||||
self.deliverBestAttemptNtf()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func setBadgeCount() {
|
||||
badgeCount = ntfBadgeCountGroupDefault.get() + 1
|
||||
ntfBadgeCountGroupDefault.set(badgeCount)
|
||||
@@ -323,14 +271,9 @@ class NotificationService: UNNotificationServiceExtension {
|
||||
|
||||
private func deliverBestAttemptNtf(urgent: Bool = false) {
|
||||
logger.debug("NotificationService.deliverBestAttemptNtf")
|
||||
if let cancel = cancelRead {
|
||||
cancelRead = nil
|
||||
cancel()
|
||||
}
|
||||
if let id = receiveEntityId {
|
||||
receiveEntityId = nil
|
||||
NtfStreamSemaphores.shared.signalStreamReady(id)
|
||||
}
|
||||
// stop processing other messages
|
||||
shouldProcessNtf = false
|
||||
|
||||
let suspend: Bool
|
||||
if let t = threadId {
|
||||
threadId = nil
|
||||
@@ -572,7 +515,7 @@ func chatSuspended() {
|
||||
}
|
||||
|
||||
// A single loop is used per Notification service extension process to receive and process all messages depending on the NSE state
|
||||
// If the extension is not active yet, or suspended/suspending, or the app is running, the notifications will no be received.
|
||||
// If the extension is not active yet, or suspended/suspending, or the app is running, the notifications will not be received.
|
||||
func receiveMessages() async {
|
||||
logger.debug("NotificationService receiveMessages")
|
||||
while true {
|
||||
@@ -591,8 +534,7 @@ func receiveMessages() async {
|
||||
logger.debug("NotificationService receiveMsg: message")
|
||||
if let (id, ntf) = await receivedMsgNtf(msg) {
|
||||
logger.debug("NotificationService receiveMsg: notification")
|
||||
await PendingNtfs.shared.createStream(id)
|
||||
await PendingNtfs.shared.writeStream(id, ntf)
|
||||
await NSEThreads.shared.processNotification(id, ntf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -640,10 +582,9 @@ func receivedMsgNtf(_ res: ChatResponse) async -> (String, NSENotification)? {
|
||||
cleanupDirectFile(aChatItem)
|
||||
return nil
|
||||
case let .sndFileRcvCancelled(_, aChatItem, _):
|
||||
cleanupDirectFile(aChatItem)
|
||||
return nil
|
||||
case let .sndFileCompleteXFTP(_, aChatItem, _):
|
||||
cleanupFile(aChatItem)
|
||||
if let aChatItem = aChatItem {
|
||||
cleanupDirectFile(aChatItem)
|
||||
}
|
||||
return nil
|
||||
case let .callInvitation(invitation):
|
||||
// Do not post it without CallKit support, iOS will stop launching the app without showing CallKit
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Bundle display name */
|
||||
"CFBundleDisplayName" = "SimpleX NSE";
|
||||
|
||||
/* Bundle name */
|
||||
"CFBundleName" = "SimpleX NSE";
|
||||
|
||||
/* Copyright (human-readable) */
|
||||
"NSHumanReadableCopyright" = "Copyright © 2022 SimpleX Chat. Minden jog fenntartva.";
|
||||
|
||||
@@ -29,6 +29,11 @@
|
||||
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
|
||||
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
|
||||
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
|
||||
5C2217842BD4465500A8B0E7 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C22177F2BD4465500A8B0E7 /* libgmpxx.a */; };
|
||||
5C2217852BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217802BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a */; };
|
||||
5C2217862BD4465500A8B0E7 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217812BD4465500A8B0E7 /* libgmp.a */; };
|
||||
5C2217872BD4465500A8B0E7 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217822BD4465500A8B0E7 /* libffi.a */; };
|
||||
5C2217882BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217832BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a */; };
|
||||
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
|
||||
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
|
||||
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; };
|
||||
@@ -61,11 +66,6 @@
|
||||
5C7505A527B679EE00BE3227 /* NavLinkPlain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */; };
|
||||
5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A727B6D34800BE3227 /* ChatInfoToolbar.swift */; };
|
||||
5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C764E88279CBCB3000C6508 /* ChatModel.swift */; };
|
||||
5C777BD82B99B38B00C72EFF /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C777BD32B99B38B00C72EFF /* libgmp.a */; };
|
||||
5C777BD92B99B38B00C72EFF /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C777BD42B99B38B00C72EFF /* libgmpxx.a */; };
|
||||
5C777BDA2B99B38B00C72EFF /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C777BD52B99B38B00C72EFF /* libffi.a */; };
|
||||
5C777BDB2B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C777BD62B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg-ghc9.6.3.a */; };
|
||||
5C777BDC2B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C777BD72B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg.a */; };
|
||||
5C8F01CD27A6F0D8007D2C8D /* CodeScanner in Frameworks */ = {isa = PBXBuildFile; productRef = 5C8F01CC27A6F0D8007D2C8D /* CodeScanner */; };
|
||||
5C93292F29239A170090FFF9 /* ProtocolServersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C93292E29239A170090FFF9 /* ProtocolServersView.swift */; };
|
||||
5C93293129239BED0090FFF9 /* ProtocolServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C93293029239BED0090FFF9 /* ProtocolServerView.swift */; };
|
||||
@@ -144,7 +144,6 @@
|
||||
5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */; };
|
||||
5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */; };
|
||||
5CEBD7482A5F115D00665FE2 /* SetDeliveryReceiptsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */; };
|
||||
5CF9371E2B23429500E1D781 /* ConcurrentQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF9371D2B23429500E1D781 /* ConcurrentQueue.swift */; };
|
||||
5CF937202B24DE8C00E1D781 /* SharedFileSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */; };
|
||||
5CF937232B2503D000E1D781 /* NSESubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF937212B25034A00E1D781 /* NSESubscriber.swift */; };
|
||||
5CFA59C42860BC6200863A68 /* MigrateToAppGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */; };
|
||||
@@ -173,6 +172,7 @@
|
||||
646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; };
|
||||
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; };
|
||||
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
|
||||
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */; };
|
||||
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
|
||||
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
|
||||
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
|
||||
@@ -185,6 +185,10 @@
|
||||
64E972072881BB22008DBC02 /* CIGroupInvitationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */; };
|
||||
64F1CC3B28B39D8600CD1FB1 /* IncognitoHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */; };
|
||||
8C05382E2B39887E006436DC /* VideoUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C05382D2B39887E006436DC /* VideoUtils.swift */; };
|
||||
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */; };
|
||||
8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */; };
|
||||
8C7DF3202B7CDB0A00C886D0 /* MigrateFromDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */; };
|
||||
8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC956ED2BC0041000412A11 /* NetworkObserver.swift */; };
|
||||
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
|
||||
D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; };
|
||||
D741547829AF89AF0022400A /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547729AF89AF0022400A /* StoreKit.framework */; };
|
||||
@@ -275,6 +279,11 @@
|
||||
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
|
||||
5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = "<group>"; };
|
||||
5C22177F2BD4465500A8B0E7 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C2217802BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
5C2217812BD4465500A8B0E7 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C2217822BD4465500A8B0E7 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C2217832BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a"; sourceTree = "<group>"; };
|
||||
5C245F3C2B501E98001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
5C245F3D2B501F13001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = "tr.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
5C245F3E2B501F13001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
@@ -285,6 +294,9 @@
|
||||
5C35CFC727B2782E00FB6C6D /* BGManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGManager.swift; sourceTree = "<group>"; };
|
||||
5C35CFCA27B2E91D00FB6C6D /* NtfManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NtfManager.swift; sourceTree = "<group>"; };
|
||||
5C36027227F47AD5009F19D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
5C371E4E2BA9AAA200100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
5C371E4F2BA9AB6400100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = "hu.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
5C371E502BA9AB6400100AD3 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
5C3A88CD27DF50170060F1C2 /* DetermineWidth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetermineWidth.swift; sourceTree = "<group>"; };
|
||||
5C3A88D027DF57800060F1C2 /* FramedItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FramedItemView.swift; sourceTree = "<group>"; };
|
||||
5C3CCFCB2AE6BD3100C3F0C3 /* ConnectDesktopView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectDesktopView.swift; sourceTree = "<group>"; };
|
||||
@@ -325,11 +337,6 @@
|
||||
5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavLinkPlain.swift; sourceTree = "<group>"; };
|
||||
5C7505A727B6D34800BE3227 /* ChatInfoToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoToolbar.swift; sourceTree = "<group>"; };
|
||||
5C764E88279CBCB3000C6508 /* ChatModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatModel.swift; sourceTree = "<group>"; };
|
||||
5C777BD32B99B38B00C72EFF /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C777BD42B99B38B00C72EFF /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C777BD52B99B38B00C72EFF /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C777BD62B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
5C777BD72B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg.a"; sourceTree = "<group>"; };
|
||||
5C84FE9129A216C800D95B1A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
5C84FE9329A2179C00D95B1A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = "nl.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
5C84FE9429A2179C00D95B1A /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
@@ -431,7 +438,6 @@
|
||||
5CEACCEC27DEA495000BD591 /* MsgContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsgContentView.swift; sourceTree = "<group>"; };
|
||||
5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPadding.swift; sourceTree = "<group>"; };
|
||||
5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDeliveryReceiptsView.swift; sourceTree = "<group>"; };
|
||||
5CF9371D2B23429500E1D781 /* ConcurrentQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentQueue.swift; sourceTree = "<group>"; };
|
||||
5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedFileSubscriber.swift; sourceTree = "<group>"; };
|
||||
5CF937212B25034A00E1D781 /* NSESubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSESubscriber.swift; sourceTree = "<group>"; };
|
||||
5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToAppGroupView.swift; sourceTree = "<group>"; };
|
||||
@@ -459,6 +465,7 @@
|
||||
646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = "<group>"; };
|
||||
647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = "<group>"; };
|
||||
648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; };
|
||||
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemForwardingView.swift; sourceTree = "<group>"; };
|
||||
6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; };
|
||||
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
|
||||
@@ -473,6 +480,10 @@
|
||||
64E972062881BB22008DBC02 /* CIGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIGroupInvitationView.swift; sourceTree = "<group>"; };
|
||||
64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncognitoHelp.swift; sourceTree = "<group>"; };
|
||||
8C05382D2B39887E006436DC /* VideoUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoUtils.swift; sourceTree = "<group>"; };
|
||||
8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
|
||||
8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToDevice.swift; sourceTree = "<group>"; };
|
||||
8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateFromDevice.swift; sourceTree = "<group>"; };
|
||||
8CC956ED2BC0041000412A11 /* NetworkObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkObserver.swift; sourceTree = "<group>"; };
|
||||
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; };
|
||||
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
@@ -514,13 +525,13 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C777BD92B99B38B00C72EFF /* libgmpxx.a in Frameworks */,
|
||||
5C777BDB2B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg-ghc9.6.3.a in Frameworks */,
|
||||
5C2217842BD4465500A8B0E7 /* libgmpxx.a in Frameworks */,
|
||||
5C2217872BD4465500A8B0E7 /* libffi.a in Frameworks */,
|
||||
5C2217862BD4465500A8B0E7 /* libgmp.a in Frameworks */,
|
||||
5C2217882BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a in Frameworks */,
|
||||
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
||||
5C777BD82B99B38B00C72EFF /* libgmp.a in Frameworks */,
|
||||
5C777BDA2B99B38B00C72EFF /* libffi.a in Frameworks */,
|
||||
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
||||
5C777BDC2B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg.a in Frameworks */,
|
||||
5C2217852BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -553,6 +564,7 @@
|
||||
5CB924DD27A8622200ACCCDD /* NewChat */,
|
||||
5CFA59C22860B04D00863A68 /* Database */,
|
||||
5CB634AB29E46CDB0066AD6B /* LocalAuth */,
|
||||
8C7D94982B8894D300B7B9E1 /* Migration */,
|
||||
5CA8D01B2AD9B076001FD661 /* RemoteAccess */,
|
||||
5CB924DF27A8678B00ACCCDD /* UserSettings */,
|
||||
5C2E261127A30FEA00F70299 /* TerminalView.swift */,
|
||||
@@ -575,6 +587,7 @@
|
||||
5CBE6C11294487F7002D9531 /* VerifyCodeView.swift */,
|
||||
5CBE6C132944CC12002D9531 /* ScanCodeView.swift */,
|
||||
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */,
|
||||
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */,
|
||||
);
|
||||
path = Chat;
|
||||
sourceTree = "<group>";
|
||||
@@ -582,11 +595,11 @@
|
||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C777BD52B99B38B00C72EFF /* libffi.a */,
|
||||
5C777BD32B99B38B00C72EFF /* libgmp.a */,
|
||||
5C777BD42B99B38B00C72EFF /* libgmpxx.a */,
|
||||
5C777BD62B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg-ghc9.6.3.a */,
|
||||
5C777BD72B99B38B00C72EFF /* libHSsimplex-chat-5.5.6.0-AiwFoGVZWFALIHlLc8SJrg.a */,
|
||||
5C2217822BD4465500A8B0E7 /* libffi.a */,
|
||||
5C2217812BD4465500A8B0E7 /* libgmp.a */,
|
||||
5C22177F2BD4465500A8B0E7 /* libgmpxx.a */,
|
||||
5C2217802BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy-ghc9.6.3.a */,
|
||||
5C2217832BD4465500A8B0E7 /* libHSsimplex-chat-5.7.0.1-4ZWOoOvQtRR3xwBSWKICWy.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -615,6 +628,7 @@
|
||||
5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */,
|
||||
5C93293E2928E0FD0090FFF9 /* AudioRecPlay.swift */,
|
||||
5CBD2859295711D700EC2CF4 /* ImageUtils.swift */,
|
||||
8CC956ED2BC0041000412A11 /* NetworkObserver.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@@ -766,6 +780,7 @@
|
||||
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */,
|
||||
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */,
|
||||
5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */,
|
||||
8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */,
|
||||
);
|
||||
path = UserSettings;
|
||||
sourceTree = "<group>";
|
||||
@@ -789,7 +804,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CDCAD5128186DE400503DA2 /* SimpleX NSE.entitlements */,
|
||||
5CF9371D2B23429500E1D781 /* ConcurrentQueue.swift */,
|
||||
5CDCAD472818589900503DA2 /* NotificationService.swift */,
|
||||
5CDCAD492818589900503DA2 /* Info.plist */,
|
||||
5CB0BA862826CB3A00B3292C /* InfoPlist.strings */,
|
||||
@@ -893,6 +907,15 @@
|
||||
path = Group;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8C7D94982B8894D300B7B9E1 /* Migration */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */,
|
||||
8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */,
|
||||
);
|
||||
path = Migration;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -1043,6 +1066,7 @@
|
||||
uk,
|
||||
bg,
|
||||
tr,
|
||||
hu,
|
||||
);
|
||||
mainGroup = 5CA059BD279559F40002BEB4;
|
||||
packageReferences = (
|
||||
@@ -1124,6 +1148,7 @@
|
||||
5CBD285A295711D700EC2CF4 /* ImageUtils.swift in Sources */,
|
||||
6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */,
|
||||
5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */,
|
||||
8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */,
|
||||
5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */,
|
||||
5C029EAA283942EA004A9677 /* CallController.swift in Sources */,
|
||||
5CBE6C142944CC12002D9531 /* ScanCodeView.swift in Sources */,
|
||||
@@ -1139,6 +1164,7 @@
|
||||
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */,
|
||||
5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */,
|
||||
3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */,
|
||||
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */,
|
||||
64466DC829FC2B3B00E3D48D /* CreateSimpleXAddress.swift in Sources */,
|
||||
3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */,
|
||||
5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */,
|
||||
@@ -1157,6 +1183,7 @@
|
||||
5C9A5BDB2871E05400A5B906 /* SetNotificationsMode.swift in Sources */,
|
||||
5CB0BA8E2827126500B3292C /* OnboardingView.swift in Sources */,
|
||||
6442E0BE2880182D00CEC0F9 /* GroupChatInfoView.swift in Sources */,
|
||||
8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */,
|
||||
5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */,
|
||||
5C9FD96E27A5D6ED0075386C /* SendMessageView.swift in Sources */,
|
||||
5CA7DFC329302AF000F7FDDE /* AppSheet.swift in Sources */,
|
||||
@@ -1179,6 +1206,7 @@
|
||||
5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */,
|
||||
5C35CFC827B2782E00FB6C6D /* BGManager.swift in Sources */,
|
||||
5CB634B129E5EFEA0066AD6B /* PasscodeView.swift in Sources */,
|
||||
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */,
|
||||
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */,
|
||||
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */,
|
||||
6442E0BA287F169300CEC0F9 /* AddGroupView.swift in Sources */,
|
||||
@@ -1220,6 +1248,7 @@
|
||||
5CB0BA92282713FD00B3292C /* CreateProfile.swift in Sources */,
|
||||
5C5F2B7027EBC704006A9D5F /* ProfileImage.swift in Sources */,
|
||||
5C9329412929248A0090FFF9 /* ScanProtocolServer.swift in Sources */,
|
||||
8C7DF3202B7CDB0A00C886D0 /* MigrateFromDevice.swift in Sources */,
|
||||
64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */,
|
||||
5C93293F2928E0FD0090FFF9 /* AudioRecPlay.swift in Sources */,
|
||||
5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */,
|
||||
@@ -1261,7 +1290,6 @@
|
||||
files = (
|
||||
5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */,
|
||||
5CFE0922282EEAF60002594B /* ZoomableScrollView.swift in Sources */,
|
||||
5CF9371E2B23429500E1D781 /* ConcurrentQueue.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1331,6 +1359,7 @@
|
||||
5C636F672AAB3D2400751C84 /* uk */,
|
||||
5C5B67932ABAF56000DA9412 /* bg */,
|
||||
5C245F3E2B501F13001CC39F /* tr */,
|
||||
5C371E502BA9AB6400100AD3 /* hu */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -1354,6 +1383,7 @@
|
||||
5CE6C7B42AAB1527007F345C /* uk */,
|
||||
5C5B67912ABAF4B500DA9412 /* bg */,
|
||||
5C245F3C2B501E98001CC39F /* tr */,
|
||||
5C371E4E2BA9AAA200100AD3 /* hu */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -1376,6 +1406,7 @@
|
||||
5C636F662AAB3D2400751C84 /* uk */,
|
||||
5C5B67922ABAF56000DA9412 /* bg */,
|
||||
5C245F3D2B501F13001CC39F /* tr */,
|
||||
5C371E4F2BA9AB6400100AD3 /* hu */,
|
||||
);
|
||||
name = "SimpleX--iOS--InfoPlist.strings";
|
||||
sourceTree = "<group>";
|
||||
@@ -1418,6 +1449,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -1479,6 +1511,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -1507,12 +1540,16 @@
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 208;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "SimpleX--iOS--Info.plist";
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
|
||||
@@ -1531,11 +1568,13 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.5.6;
|
||||
LLVM_LTO = YES_THIN;
|
||||
MARKETING_VERSION = 5.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
@@ -1550,12 +1589,16 @@
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 208;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_CODE_COVERAGE = NO;
|
||||
ENABLE_PREVIEWS = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "SimpleX--iOS--Info.plist";
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "SimpleX needs camera access to scan QR codes to connect to other users and for video calls.";
|
||||
@@ -1574,7 +1617,8 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.5.6;
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 5.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
|
||||
PRODUCT_NAME = SimpleX;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -1630,12 +1674,15 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 208;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "SimpleX NSE/Info.plist";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "SimpleX NSE";
|
||||
@@ -1646,13 +1693,15 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.5.6;
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 5.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Osize";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
@@ -1662,12 +1711,15 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 208;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_CODE_COVERAGE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "SimpleX NSE/Info.plist";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "SimpleX NSE";
|
||||
@@ -1678,13 +1730,15 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 5.5.6;
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 5.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Osize";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
@@ -1696,14 +1750,17 @@
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 208;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved.";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
@@ -1721,7 +1778,8 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
MARKETING_VERSION = 5.5.6;
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 5.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -1730,6 +1788,7 @@
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_INCLUDE_PATHS = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = ./SimpleXChat/SimpleX.h;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -1742,14 +1801,17 @@
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 208;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_CODE_COVERAGE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 SimpleX Chat. All rights reserved.";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
@@ -1767,7 +1829,8 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Libraries/sim",
|
||||
);
|
||||
MARKETING_VERSION = 5.5.6;
|
||||
LLVM_LTO = YES;
|
||||
MARKETING_VERSION = 5.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -1776,6 +1839,7 @@
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_INCLUDE_PATHS = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = ./SimpleXChat/SimpleX.h;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
|
||||
@@ -54,7 +54,44 @@ public func chatMigrateInit(_ useKey: String? = nil, confirmMigrations: Migratio
|
||||
return result
|
||||
}
|
||||
|
||||
public func chatInitTemporaryDatabase(url: URL, key: String? = nil, confirmation: MigrationConfirmation = .error) -> (DBMigrationResult, chat_ctrl?) {
|
||||
let dbPath = url.path
|
||||
let dbKey = key ?? randomDatabasePassword()
|
||||
logger.debug("chatInitTemporaryDatabase path: \(dbPath)")
|
||||
var temporaryController: chat_ctrl? = nil
|
||||
var cPath = dbPath.cString(using: .utf8)!
|
||||
var cKey = dbKey.cString(using: .utf8)!
|
||||
var cConfirm = confirmation.rawValue.cString(using: .utf8)!
|
||||
let cjson = chat_migrate_init_key(&cPath, &cKey, 1, &cConfirm, 0, &temporaryController)!
|
||||
return (dbMigrationResult(fromCString(cjson)), temporaryController)
|
||||
}
|
||||
|
||||
public func chatInitControllerRemovingDatabases() {
|
||||
let dbPath = getAppDatabasePath().path
|
||||
let fm = FileManager.default
|
||||
// Remove previous databases, otherwise, can be .errorNotADatabase with nil controller
|
||||
try? fm.removeItem(atPath: dbPath + CHAT_DB)
|
||||
try? fm.removeItem(atPath: dbPath + AGENT_DB)
|
||||
|
||||
let dbKey = randomDatabasePassword()
|
||||
logger.debug("chatInitControllerRemovingDatabases path: \(dbPath)")
|
||||
var cPath = dbPath.cString(using: .utf8)!
|
||||
var cKey = dbKey.cString(using: .utf8)!
|
||||
var cConfirm = MigrationConfirmation.error.rawValue.cString(using: .utf8)!
|
||||
chat_migrate_init_key(&cPath, &cKey, 1, &cConfirm, 0, &chatController)
|
||||
|
||||
// We need only controller, not databases
|
||||
try? fm.removeItem(atPath: dbPath + CHAT_DB)
|
||||
try? fm.removeItem(atPath: dbPath + AGENT_DB)
|
||||
}
|
||||
|
||||
|
||||
public func chatCloseStore() {
|
||||
// Prevent crash when exiting the app with already closed store (for example, after changing a database passpharase)
|
||||
guard hasChatCtrl() else {
|
||||
logger.error("chatCloseStore: already closed, chatCtrl is nil")
|
||||
return
|
||||
}
|
||||
let err = fromCString(chat_close_store(getChatCtrl()))
|
||||
if err != "" {
|
||||
logger.error("chatCloseStore error: \(err)")
|
||||
@@ -73,17 +110,17 @@ public func resetChatCtrl() {
|
||||
migrationResult = nil
|
||||
}
|
||||
|
||||
public func sendSimpleXCmd(_ cmd: ChatCommand) -> ChatResponse {
|
||||
public func sendSimpleXCmd(_ cmd: ChatCommand, _ ctrl: chat_ctrl? = nil) -> ChatResponse {
|
||||
var c = cmd.cmdString.cString(using: .utf8)!
|
||||
let cjson = chat_send_cmd(getChatCtrl(), &c)!
|
||||
let cjson = chat_send_cmd(ctrl ?? getChatCtrl(), &c)!
|
||||
return chatResponse(fromCString(cjson))
|
||||
}
|
||||
|
||||
// in microseconds
|
||||
let MESSAGE_TIMEOUT: Int32 = 15_000_000
|
||||
|
||||
public func recvSimpleXMsg() -> ChatResponse? {
|
||||
if let cjson = chat_recv_msg_wait(getChatCtrl(), MESSAGE_TIMEOUT) {
|
||||
public func recvSimpleXMsg(_ ctrl: chat_ctrl? = nil) -> ChatResponse? {
|
||||
if let cjson = chat_recv_msg_wait(ctrl ?? getChatCtrl(), MESSAGE_TIMEOUT) {
|
||||
let s = fromCString(cjson)
|
||||
return s == "" ? nil : chatResponse(s)
|
||||
}
|
||||
@@ -181,13 +218,11 @@ public func chatResponse(_ s: String) -> ChatResponse {
|
||||
}
|
||||
} else if type == "chatCmdError" {
|
||||
if let jError = jResp["chatCmdError"] as? NSDictionary {
|
||||
let user: UserRef? = try? decodeObject(jError["user_"] as Any)
|
||||
return .chatCmdError(user_: user, chatError: .invalidJSON(json: prettyJSON(jError) ?? ""))
|
||||
return .chatCmdError(user_: decodeUser_(jError), chatError: .invalidJSON(json: prettyJSON(jError) ?? ""))
|
||||
}
|
||||
} else if type == "chatError" {
|
||||
if let jError = jResp["chatError"] as? NSDictionary {
|
||||
let user: UserRef? = try? decodeObject(jError["user_"] as Any)
|
||||
return .chatError(user_: user, chatError: .invalidJSON(json: prettyJSON(jError) ?? ""))
|
||||
return .chatError(user_: decodeUser_(jError), chatError: .invalidJSON(json: prettyJSON(jError) ?? ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,6 +231,14 @@ public func chatResponse(_ s: String) -> ChatResponse {
|
||||
return ChatResponse.response(type: type ?? "invalid", json: json ?? s)
|
||||
}
|
||||
|
||||
private func decodeUser_(_ jDict: NSDictionary) -> UserRef? {
|
||||
if let user_ = jDict["user_"] {
|
||||
try? decodeObject(user_ as Any)
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
func parseChatData(_ jChat: Any) throws -> ChatData {
|
||||
let jChatDict = jChat as! NSDictionary
|
||||
let chatInfo: ChatInfo = try decodeObject(jChatDict["chatInfo"]!)
|
||||
|
||||
@@ -32,12 +32,15 @@ public enum ChatCommand {
|
||||
case setTempFolder(tempFolder: String)
|
||||
case setFilesFolder(filesFolder: String)
|
||||
case apiSetEncryptLocalFiles(enable: Bool)
|
||||
case apiSetPQEnabled(enable: Bool)
|
||||
case apiAllowContactPQ(contactId: Int64)
|
||||
case apiSetPQEncryption(enable: Bool)
|
||||
case apiSetContactPQ(contactId: Int64, enable: Bool)
|
||||
case apiExportArchive(config: ArchiveConfig)
|
||||
case apiImportArchive(config: ArchiveConfig)
|
||||
case apiDeleteStorage
|
||||
case apiStorageEncryption(config: DBEncryptionConfig)
|
||||
case testStorageEncryption(key: String)
|
||||
case apiSaveSettings(settings: AppSettings)
|
||||
case apiGetSettings(settings: AppSettings)
|
||||
case apiGetChats(userId: Int64)
|
||||
case apiGetChat(type: ChatType, id: Int64, pagination: ChatPagination, search: String)
|
||||
case apiGetChatItemInfo(type: ChatType, id: Int64, itemId: Int64)
|
||||
@@ -47,6 +50,7 @@ public enum ChatCommand {
|
||||
case apiDeleteChatItem(type: ChatType, id: Int64, itemId: Int64, mode: CIDeleteMode)
|
||||
case apiDeleteMemberChatItem(groupId: Int64, groupMemberId: Int64, itemId: Int64)
|
||||
case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction)
|
||||
case apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64)
|
||||
case apiGetNtfToken
|
||||
case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode)
|
||||
case apiVerifyToken(token: DeviceToken, nonce: String, code: String)
|
||||
@@ -74,6 +78,7 @@ public enum ChatCommand {
|
||||
case apiGetChatItemTTL(userId: Int64)
|
||||
case apiSetNetworkConfig(networkConfig: NetCfg)
|
||||
case apiGetNetworkConfig
|
||||
case apiSetNetworkInfo(networkInfo: UserNetworkInfo)
|
||||
case reconnectAllServers
|
||||
case apiSetChatSettings(type: ChatType, id: Int64, chatSettings: ChatSettings)
|
||||
case apiSetMemberSettings(groupId: Int64, groupMemberId: Int64, memberSettings: GroupMemberSettings)
|
||||
@@ -132,6 +137,9 @@ public enum ChatCommand {
|
||||
case listRemoteCtrls
|
||||
case stopRemoteCtrl
|
||||
case deleteRemoteCtrl(remoteCtrlId: Int64)
|
||||
case apiUploadStandaloneFile(userId: Int64, file: CryptoFile)
|
||||
case apiDownloadStandaloneFile(userId: Int64, url: String, file: CryptoFile)
|
||||
case apiStandaloneFileInfo(url: String)
|
||||
// misc
|
||||
case showVersion
|
||||
case string(String)
|
||||
@@ -164,12 +172,15 @@ public enum ChatCommand {
|
||||
case let .setTempFolder(tempFolder): return "/_temp_folder \(tempFolder)"
|
||||
case let .setFilesFolder(filesFolder): return "/_files_folder \(filesFolder)"
|
||||
case let .apiSetEncryptLocalFiles(enable): return "/_files_encrypt \(onOff(enable))"
|
||||
case let .apiSetPQEnabled(enable): return "/_pq \(onOff(enable))"
|
||||
case let .apiAllowContactPQ(contactId): return "/_pq allow \(contactId)"
|
||||
case let .apiSetPQEncryption(enable): return "/pq \(onOff(enable))"
|
||||
case let .apiSetContactPQ(contactId, enable): return "/_pq @\(contactId) \(onOff(enable))"
|
||||
case let .apiExportArchive(cfg): return "/_db export \(encodeJSON(cfg))"
|
||||
case let .apiImportArchive(cfg): return "/_db import \(encodeJSON(cfg))"
|
||||
case .apiDeleteStorage: return "/_db delete"
|
||||
case let .apiStorageEncryption(cfg): return "/_db encryption \(encodeJSON(cfg))"
|
||||
case let .testStorageEncryption(key): return "/db test key \(key)"
|
||||
case let .apiSaveSettings(settings): return "/_save app settings \(encodeJSON(settings))"
|
||||
case let .apiGetSettings(settings): return "/_get app settings \(encodeJSON(settings))"
|
||||
case let .apiGetChats(userId): return "/_get chats \(userId) pcc=on"
|
||||
case let .apiGetChat(type, id, pagination, search): return "/_get chat \(ref(type, id)) \(pagination.cmdString)" +
|
||||
(search == "" ? "" : " search=\(search)")
|
||||
@@ -185,6 +196,7 @@ public enum ChatCommand {
|
||||
case let .apiDeleteChatItem(type, id, itemId, mode): return "/_delete item \(ref(type, id)) \(itemId) \(mode.rawValue)"
|
||||
case let .apiDeleteMemberChatItem(groupId, groupMemberId, itemId): return "/_delete member item #\(groupId) \(groupMemberId) \(itemId)"
|
||||
case let .apiChatItemReaction(type, id, itemId, add, reaction): return "/_reaction \(ref(type, id)) \(itemId) \(onOff(add)) \(encodeJSON(reaction))"
|
||||
case let .apiForwardChatItem(toChatType, toChatId, fromChatType, fromChatId, itemId): return "/_forward \(ref(toChatType, toChatId)) \(ref(fromChatType, fromChatId)) \(itemId)"
|
||||
case .apiGetNtfToken: return "/_ntf get "
|
||||
case let .apiRegisterToken(token, notificationMode): return "/_ntf register \(token.cmdString) \(notificationMode.rawValue)"
|
||||
case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)"
|
||||
@@ -212,6 +224,7 @@ public enum ChatCommand {
|
||||
case let .apiGetChatItemTTL(userId): return "/_ttl \(userId)"
|
||||
case let .apiSetNetworkConfig(networkConfig): return "/_network \(encodeJSON(networkConfig))"
|
||||
case .apiGetNetworkConfig: return "/network"
|
||||
case let .apiSetNetworkInfo(networkInfo): return "/_network info \(encodeJSON(networkInfo))"
|
||||
case .reconnectAllServers: return "/reconnect"
|
||||
case let .apiSetChatSettings(type, id, chatSettings): return "/_settings \(ref(type, id)) \(encodeJSON(chatSettings))"
|
||||
case let .apiSetMemberSettings(groupId, groupMemberId, memberSettings): return "/_member settings #\(groupId) \(groupMemberId) \(encodeJSON(memberSettings))"
|
||||
@@ -282,6 +295,9 @@ public enum ChatCommand {
|
||||
case .listRemoteCtrls: return "/list remote ctrls"
|
||||
case .stopRemoteCtrl: return "/stop remote ctrl"
|
||||
case let .deleteRemoteCtrl(rcId): return "/delete remote ctrl \(rcId)"
|
||||
case let .apiUploadStandaloneFile(userId, file): return "/_upload \(userId) \(file.filePath)"
|
||||
case let .apiDownloadStandaloneFile(userId, link, file): return "/_download \(userId) \(link) \(file.filePath)"
|
||||
case let .apiStandaloneFileInfo(link): return "/_download info \(link)"
|
||||
case .showVersion: return "/version"
|
||||
case let .string(str): return str
|
||||
}
|
||||
@@ -310,12 +326,15 @@ public enum ChatCommand {
|
||||
case .setTempFolder: return "setTempFolder"
|
||||
case .setFilesFolder: return "setFilesFolder"
|
||||
case .apiSetEncryptLocalFiles: return "apiSetEncryptLocalFiles"
|
||||
case .apiSetPQEnabled: return "apiSetPQEnabled"
|
||||
case .apiAllowContactPQ: return "apiAllowContactPQ"
|
||||
case .apiSetPQEncryption: return "apiSetPQEncryption"
|
||||
case .apiSetContactPQ: return "apiSetContactPQ"
|
||||
case .apiExportArchive: return "apiExportArchive"
|
||||
case .apiImportArchive: return "apiImportArchive"
|
||||
case .apiDeleteStorage: return "apiDeleteStorage"
|
||||
case .apiStorageEncryption: return "apiStorageEncryption"
|
||||
case .testStorageEncryption: return "testStorageEncryption"
|
||||
case .apiSaveSettings: return "apiSaveSettings"
|
||||
case .apiGetSettings: return "apiGetSettings"
|
||||
case .apiGetChats: return "apiGetChats"
|
||||
case .apiGetChat: return "apiGetChat"
|
||||
case .apiGetChatItemInfo: return "apiGetChatItemInfo"
|
||||
@@ -326,6 +345,7 @@ public enum ChatCommand {
|
||||
case .apiConnectContactViaAddress: return "apiConnectContactViaAddress"
|
||||
case .apiDeleteMemberChatItem: return "apiDeleteMemberChatItem"
|
||||
case .apiChatItemReaction: return "apiChatItemReaction"
|
||||
case .apiForwardChatItem: return "apiForwardChatItem"
|
||||
case .apiGetNtfToken: return "apiGetNtfToken"
|
||||
case .apiRegisterToken: return "apiRegisterToken"
|
||||
case .apiVerifyToken: return "apiVerifyToken"
|
||||
@@ -353,6 +373,7 @@ public enum ChatCommand {
|
||||
case .apiGetChatItemTTL: return "apiGetChatItemTTL"
|
||||
case .apiSetNetworkConfig: return "apiSetNetworkConfig"
|
||||
case .apiGetNetworkConfig: return "apiGetNetworkConfig"
|
||||
case .apiSetNetworkInfo: return "apiSetNetworkInfo"
|
||||
case .reconnectAllServers: return "reconnectAllServers"
|
||||
case .apiSetChatSettings: return "apiSetChatSettings"
|
||||
case .apiSetMemberSettings: return "apiSetMemberSettings"
|
||||
@@ -408,6 +429,9 @@ public enum ChatCommand {
|
||||
case .listRemoteCtrls: return "listRemoteCtrls"
|
||||
case .stopRemoteCtrl: return "stopRemoteCtrl"
|
||||
case .deleteRemoteCtrl: return "deleteRemoteCtrl"
|
||||
case .apiUploadStandaloneFile: return "apiUploadStandaloneFile"
|
||||
case .apiDownloadStandaloneFile: return "apiDownloadStandaloneFile"
|
||||
case .apiStandaloneFileInfo: return "apiStandaloneFileInfo"
|
||||
case .showVersion: return "showVersion"
|
||||
case .string: return "console command"
|
||||
}
|
||||
@@ -442,6 +466,8 @@ public enum ChatCommand {
|
||||
return .apiUnhideUser(userId: userId, viewPwd: obfuscate(viewPwd))
|
||||
case let .apiDeleteUser(userId, delSMPQueues, viewPwd):
|
||||
return .apiDeleteUser(userId: userId, delSMPQueues: delSMPQueues, viewPwd: obfuscate(viewPwd))
|
||||
case let .testStorageEncryption(key):
|
||||
return .testStorageEncryption(key: obfuscate(key))
|
||||
default: return self
|
||||
}
|
||||
}
|
||||
@@ -537,11 +563,6 @@ public enum ChatResponse: Decodable, Error {
|
||||
case contactRequestRejected(user: UserRef)
|
||||
case contactUpdated(user: UserRef, toContact: Contact)
|
||||
case groupMemberUpdated(user: UserRef, groupInfo: GroupInfo, fromMember: GroupMember, toMember: GroupMember)
|
||||
// TODO remove events below
|
||||
case contactsSubscribed(server: String, contactRefs: [ContactRef])
|
||||
case contactsDisconnected(server: String, contactRefs: [ContactRef])
|
||||
case contactSubSummary(user: UserRef, contactSubscriptions: [ContactSubStatus])
|
||||
// TODO remove events above
|
||||
case networkStatus(networkStatus: NetworkStatus, connections: [String])
|
||||
case networkStatuses(user_: UserRef?, networkStatuses: [ConnNetworkStatus])
|
||||
case groupSubscribed(user: UserRef, groupInfo: GroupRef)
|
||||
@@ -590,20 +611,28 @@ public enum ChatResponse: Decodable, Error {
|
||||
// receiving file events
|
||||
case rcvFileAccepted(user: UserRef, chatItem: AChatItem)
|
||||
case rcvFileAcceptedSndCancelled(user: UserRef, rcvFileTransfer: RcvFileTransfer)
|
||||
case rcvFileStart(user: UserRef, chatItem: AChatItem)
|
||||
case rcvFileProgressXFTP(user: UserRef, chatItem: AChatItem, receivedSize: Int64, totalSize: Int64)
|
||||
case standaloneFileInfo(fileMeta: MigrationFileLinkData?)
|
||||
case rcvStandaloneFileCreated(user: UserRef, rcvFileTransfer: RcvFileTransfer)
|
||||
case rcvFileStart(user: UserRef, chatItem: AChatItem) // send by chats
|
||||
case rcvFileProgressXFTP(user: UserRef, chatItem_: AChatItem?, receivedSize: Int64, totalSize: Int64, rcvFileTransfer: RcvFileTransfer)
|
||||
case rcvFileComplete(user: UserRef, chatItem: AChatItem)
|
||||
case rcvFileCancelled(user: UserRef, chatItem: AChatItem, rcvFileTransfer: RcvFileTransfer)
|
||||
case rcvStandaloneFileComplete(user: UserRef, targetPath: String, rcvFileTransfer: RcvFileTransfer)
|
||||
case rcvFileCancelled(user: UserRef, chatItem_: AChatItem?, rcvFileTransfer: RcvFileTransfer)
|
||||
case rcvFileSndCancelled(user: UserRef, chatItem: AChatItem, rcvFileTransfer: RcvFileTransfer)
|
||||
case rcvFileError(user: UserRef, chatItem: AChatItem)
|
||||
case rcvFileError(user: UserRef, chatItem_: AChatItem?, rcvFileTransfer: RcvFileTransfer)
|
||||
// sending file events
|
||||
case sndFileStart(user: UserRef, chatItem: AChatItem, sndFileTransfer: SndFileTransfer)
|
||||
case sndFileComplete(user: UserRef, chatItem: AChatItem, sndFileTransfer: SndFileTransfer)
|
||||
case sndFileCancelled(user: UserRef, chatItem: AChatItem, fileTransferMeta: FileTransferMeta, sndFileTransfers: [SndFileTransfer])
|
||||
case sndFileRcvCancelled(user: UserRef, chatItem: AChatItem, sndFileTransfer: SndFileTransfer)
|
||||
case sndFileProgressXFTP(user: UserRef, chatItem: AChatItem, fileTransferMeta: FileTransferMeta, sentSize: Int64, totalSize: Int64)
|
||||
case sndFileRcvCancelled(user: UserRef, chatItem_: AChatItem?, sndFileTransfer: SndFileTransfer)
|
||||
case sndFileCancelled(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta, sndFileTransfers: [SndFileTransfer])
|
||||
case sndStandaloneFileCreated(user: UserRef, fileTransferMeta: FileTransferMeta) // returned by _upload
|
||||
case sndFileStartXFTP(user: UserRef, chatItem: AChatItem, fileTransferMeta: FileTransferMeta) // not used
|
||||
case sndFileProgressXFTP(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta, sentSize: Int64, totalSize: Int64)
|
||||
case sndFileRedirectStartXFTP(user: UserRef, fileTransferMeta: FileTransferMeta, redirectMeta: FileTransferMeta)
|
||||
case sndFileCompleteXFTP(user: UserRef, chatItem: AChatItem, fileTransferMeta: FileTransferMeta)
|
||||
case sndFileError(user: UserRef, chatItem: AChatItem)
|
||||
case sndStandaloneFileComplete(user: UserRef, fileTransferMeta: FileTransferMeta, rcvURIs: [String])
|
||||
case sndFileCancelledXFTP(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta)
|
||||
case sndFileError(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta)
|
||||
// call events
|
||||
case callInvitation(callInvitation: RcvCallInvitation)
|
||||
case callOffer(user: UserRef, contact: Contact, callType: CallType, offer: WebRTCSession, sharedKey: String?, askConfirmation: Bool)
|
||||
@@ -624,7 +653,7 @@ public enum ChatResponse: Decodable, Error {
|
||||
case remoteCtrlConnected(remoteCtrl: RemoteCtrlInfo)
|
||||
case remoteCtrlStopped(rcsState: RemoteCtrlSessionState, rcStopReason: RemoteCtrlStopReason)
|
||||
// pq
|
||||
case contactPQAllowed(user: UserRef, contact: Contact)
|
||||
case contactPQAllowed(user: UserRef, contact: Contact, pqEncryption: Bool)
|
||||
case contactPQEnabled(user: UserRef, contact: Contact, pqEnabled: Bool)
|
||||
// misc
|
||||
case versionInfo(versionInfo: CoreVersionInfo, chatMigrations: [UpMigration], agentMigrations: [UpMigration])
|
||||
@@ -632,6 +661,7 @@ public enum ChatResponse: Decodable, Error {
|
||||
case chatCmdError(user_: UserRef?, chatError: ChatError)
|
||||
case chatError(user_: UserRef?, chatError: ChatError)
|
||||
case archiveImported(archiveErrors: [ArchiveError])
|
||||
case appSettings(appSettings: AppSettings)
|
||||
|
||||
public var responseType: String {
|
||||
get {
|
||||
@@ -695,9 +725,6 @@ public enum ChatResponse: Decodable, Error {
|
||||
case .contactRequestRejected: return "contactRequestRejected"
|
||||
case .contactUpdated: return "contactUpdated"
|
||||
case .groupMemberUpdated: return "groupMemberUpdated"
|
||||
case .contactsSubscribed: return "contactsSubscribed"
|
||||
case .contactsDisconnected: return "contactsDisconnected"
|
||||
case .contactSubSummary: return "contactSubSummary"
|
||||
case .networkStatus: return "networkStatus"
|
||||
case .networkStatuses: return "networkStatuses"
|
||||
case .groupSubscribed: return "groupSubscribed"
|
||||
@@ -744,18 +771,26 @@ public enum ChatResponse: Decodable, Error {
|
||||
case .newMemberContactReceivedInv: return "newMemberContactReceivedInv"
|
||||
case .rcvFileAccepted: return "rcvFileAccepted"
|
||||
case .rcvFileAcceptedSndCancelled: return "rcvFileAcceptedSndCancelled"
|
||||
case .standaloneFileInfo: return "standaloneFileInfo"
|
||||
case .rcvStandaloneFileCreated: return "rcvStandaloneFileCreated"
|
||||
case .rcvFileStart: return "rcvFileStart"
|
||||
case .rcvFileProgressXFTP: return "rcvFileProgressXFTP"
|
||||
case .rcvFileComplete: return "rcvFileComplete"
|
||||
case .rcvStandaloneFileComplete: return "rcvStandaloneFileComplete"
|
||||
case .rcvFileCancelled: return "rcvFileCancelled"
|
||||
case .rcvFileSndCancelled: return "rcvFileSndCancelled"
|
||||
case .rcvFileError: return "rcvFileError"
|
||||
case .sndFileStart: return "sndFileStart"
|
||||
case .sndFileComplete: return "sndFileComplete"
|
||||
case .sndFileCancelled: return "sndFileCancelled"
|
||||
case .sndFileRcvCancelled: return "sndFileRcvCancelled"
|
||||
case .sndStandaloneFileCreated: return "sndStandaloneFileCreated"
|
||||
case .sndFileStartXFTP: return "sndFileStartXFTP"
|
||||
case .sndFileProgressXFTP: return "sndFileProgressXFTP"
|
||||
case .sndFileRedirectStartXFTP: return "sndFileRedirectStartXFTP"
|
||||
case .sndFileRcvCancelled: return "sndFileRcvCancelled"
|
||||
case .sndFileCompleteXFTP: return "sndFileCompleteXFTP"
|
||||
case .sndStandaloneFileComplete: return "sndStandaloneFileComplete"
|
||||
case .sndFileCancelledXFTP: return "sndFileCancelledXFTP"
|
||||
case .sndFileError: return "sndFileError"
|
||||
case .callInvitation: return "callInvitation"
|
||||
case .callOffer: return "callOffer"
|
||||
@@ -781,6 +816,7 @@ public enum ChatResponse: Decodable, Error {
|
||||
case .chatCmdError: return "chatCmdError"
|
||||
case .chatError: return "chatError"
|
||||
case .archiveImported: return "archiveImported"
|
||||
case .appSettings: return "appSettings"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -847,9 +883,6 @@ public enum ChatResponse: Decodable, Error {
|
||||
case .contactRequestRejected: return noDetails
|
||||
case let .contactUpdated(u, toContact): return withUser(u, String(describing: toContact))
|
||||
case let .groupMemberUpdated(u, groupInfo, fromMember, toMember): return withUser(u, "groupInfo: \(groupInfo)\nfromMember: \(fromMember)\ntoMember: \(toMember)")
|
||||
case let .contactsSubscribed(server, contactRefs): return "server: \(server)\ncontacts:\n\(String(describing: contactRefs))"
|
||||
case let .contactsDisconnected(server, contactRefs): return "server: \(server)\ncontacts:\n\(String(describing: contactRefs))"
|
||||
case let .contactSubSummary(u, contactSubscriptions): return withUser(u, String(describing: contactSubscriptions))
|
||||
case let .networkStatus(status, conns): return "networkStatus: \(String(describing: status))\nconnections: \(String(describing: conns))"
|
||||
case let .networkStatuses(u, statuses): return withUser(u, String(describing: statuses))
|
||||
case let .groupSubscribed(u, groupInfo): return withUser(u, String(describing: groupInfo))
|
||||
@@ -896,19 +929,27 @@ public enum ChatResponse: Decodable, Error {
|
||||
case let .newMemberContactReceivedInv(u, contact, groupInfo, member): return withUser(u, "contact: \(contact)\ngroupInfo: \(groupInfo)\nmember: \(member)")
|
||||
case let .rcvFileAccepted(u, chatItem): return withUser(u, String(describing: chatItem))
|
||||
case .rcvFileAcceptedSndCancelled: return noDetails
|
||||
case let .standaloneFileInfo(fileMeta): return String(describing: fileMeta)
|
||||
case .rcvStandaloneFileCreated: return noDetails
|
||||
case let .rcvFileStart(u, chatItem): return withUser(u, String(describing: chatItem))
|
||||
case let .rcvFileProgressXFTP(u, chatItem, receivedSize, totalSize): return withUser(u, "chatItem: \(String(describing: chatItem))\nreceivedSize: \(receivedSize)\ntotalSize: \(totalSize)")
|
||||
case let .rcvFileProgressXFTP(u, chatItem, receivedSize, totalSize, _): return withUser(u, "chatItem: \(String(describing: chatItem))\nreceivedSize: \(receivedSize)\ntotalSize: \(totalSize)")
|
||||
case let .rcvStandaloneFileComplete(u, targetPath, _): return withUser(u, targetPath)
|
||||
case let .rcvFileComplete(u, chatItem): return withUser(u, String(describing: chatItem))
|
||||
case let .rcvFileCancelled(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .rcvFileSndCancelled(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .rcvFileError(u, chatItem): return withUser(u, String(describing: chatItem))
|
||||
case let .rcvFileError(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileStart(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileComplete(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileCancelled(u, chatItem, _, _): return withUser(u, String(describing: chatItem))
|
||||
case .sndStandaloneFileCreated: return noDetails
|
||||
case let .sndFileStartXFTP(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileRcvCancelled(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileProgressXFTP(u, chatItem, _, sentSize, totalSize): return withUser(u, "chatItem: \(String(describing: chatItem))\nsentSize: \(sentSize)\ntotalSize: \(totalSize)")
|
||||
case let .sndFileRedirectStartXFTP(u, _, redirectMeta): return withUser(u, String(describing: redirectMeta))
|
||||
case let .sndFileCompleteXFTP(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileError(u, chatItem): return withUser(u, String(describing: chatItem))
|
||||
case let .sndStandaloneFileComplete(u, _, rcvURIs): return withUser(u, String(rcvURIs.count))
|
||||
case let .sndFileCancelledXFTP(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .sndFileError(u, chatItem, _): return withUser(u, String(describing: chatItem))
|
||||
case let .callInvitation(inv): return String(describing: inv)
|
||||
case let .callOffer(u, contact, callType, offer, sharedKey, askConfirmation): return withUser(u, "contact: \(contact.id)\ncallType: \(String(describing: callType))\nsharedKey: \(sharedKey ?? "")\naskConfirmation: \(askConfirmation)\noffer: \(String(describing: offer))")
|
||||
case let .callAnswer(u, contact, answer): return withUser(u, "contact: \(contact.id)\nanswer: \(String(describing: answer))")
|
||||
@@ -926,13 +967,14 @@ public enum ChatResponse: Decodable, Error {
|
||||
case let .remoteCtrlSessionCode(remoteCtrl_, sessionCode): return "remoteCtrl_:\n\(String(describing: remoteCtrl_))\nsessionCode: \(sessionCode)"
|
||||
case let .remoteCtrlConnected(remoteCtrl): return String(describing: remoteCtrl)
|
||||
case .remoteCtrlStopped: return noDetails
|
||||
case let .contactPQAllowed(u, contact): return withUser(u, "contact: \(String(describing: contact))")
|
||||
case let .contactPQAllowed(u, contact, pqEncryption): return withUser(u, "contact: \(String(describing: contact))\npqEncryption: \(pqEncryption)")
|
||||
case let .contactPQEnabled(u, contact, pqEnabled): return withUser(u, "contact: \(String(describing: contact))\npqEnabled: \(pqEnabled)")
|
||||
case let .versionInfo(versionInfo, chatMigrations, agentMigrations): return "\(String(describing: versionInfo))\n\nchat migrations: \(chatMigrations.map(\.upName))\n\nagent migrations: \(agentMigrations.map(\.upName))"
|
||||
case .cmdOk: return noDetails
|
||||
case let .chatCmdError(u, chatError): return withUser(u, String(describing: chatError))
|
||||
case let .chatError(u, chatError): return withUser(u, String(describing: chatError))
|
||||
case let .archiveImported(archiveErrors): return String(describing: archiveErrors)
|
||||
case let .appSettings(appSettings): return String(describing: appSettings)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1215,6 +1257,7 @@ public struct NetCfg: Codable, Equatable {
|
||||
public var tcpConnectTimeout: Int // microseconds
|
||||
public var tcpTimeout: Int // microseconds
|
||||
public var tcpTimeoutPerKb: Int // microseconds
|
||||
public var rcvConcurrency: Int // pool size
|
||||
public var tcpKeepAlive: KeepAliveOpts?
|
||||
public var smpPingInterval: Int // microseconds
|
||||
public var smpPingCount: Int // times
|
||||
@@ -1223,9 +1266,10 @@ public struct NetCfg: Codable, Equatable {
|
||||
public static let defaults: NetCfg = NetCfg(
|
||||
socksProxy: nil,
|
||||
sessionMode: TransportSessionMode.user,
|
||||
tcpConnectTimeout: 20_000_000,
|
||||
tcpConnectTimeout: 10_000_000,
|
||||
tcpTimeout: 15_000_000,
|
||||
tcpTimeoutPerKb: 45_000,
|
||||
tcpTimeoutPerKb: 10_000,
|
||||
rcvConcurrency: 12,
|
||||
tcpKeepAlive: KeepAliveOpts.defaults,
|
||||
smpPingInterval: 1200_000_000,
|
||||
smpPingCount: 3,
|
||||
@@ -1235,9 +1279,10 @@ public struct NetCfg: Codable, Equatable {
|
||||
public static let proxyDefaults: NetCfg = NetCfg(
|
||||
socksProxy: nil,
|
||||
sessionMode: TransportSessionMode.user,
|
||||
tcpConnectTimeout: 30_000_000,
|
||||
tcpConnectTimeout: 20_000_000,
|
||||
tcpTimeout: 20_000_000,
|
||||
tcpTimeoutPerKb: 60_000,
|
||||
tcpTimeoutPerKb: 15_000,
|
||||
rcvConcurrency: 8,
|
||||
tcpKeepAlive: KeepAliveOpts.defaults,
|
||||
smpPingInterval: 1200_000_000,
|
||||
smpPingCount: 3,
|
||||
@@ -1534,7 +1579,7 @@ public enum NotificationsMode: String, Decodable, SelectableItem {
|
||||
public static var values: [NotificationsMode] = [.instant, .periodic, .off]
|
||||
}
|
||||
|
||||
public enum NotificationPreviewMode: String, SelectableItem {
|
||||
public enum NotificationPreviewMode: String, SelectableItem, Codable {
|
||||
case hidden
|
||||
case contact
|
||||
case message
|
||||
@@ -1678,6 +1723,8 @@ public enum ChatErrorType: Decodable {
|
||||
case fallbackToSMPProhibited(fileId: Int64)
|
||||
case inlineFileProhibited(fileId: Int64)
|
||||
case invalidQuote
|
||||
case invalidForward
|
||||
case forwardNoFile
|
||||
case invalidChatItemUpdate
|
||||
case invalidChatItemDelete
|
||||
case hasCurrentCall
|
||||
@@ -1734,6 +1781,7 @@ public enum StoreError: Decodable {
|
||||
case fileIdNotFoundBySharedMsgId(sharedMsgId: String)
|
||||
case sndFileNotFoundXFTP(agentSndFileId: String)
|
||||
case rcvFileNotFoundXFTP(agentRcvFileId: String)
|
||||
case extraFileDescrNotFoundXFTP(fileId: Int64)
|
||||
case connectionNotFound(agentConnId: String)
|
||||
case connectionNotFoundById(connId: Int64)
|
||||
case connectionNotFoundByMemberId(groupMemberId: Int64)
|
||||
@@ -1779,6 +1827,7 @@ public enum AgentErrorType: Decodable {
|
||||
case BROKER(brokerAddress: String, brokerErr: BrokerErrorType)
|
||||
case AGENT(agentErr: SMPAgentError)
|
||||
case INTERNAL(internalErr: String)
|
||||
case CRITICAL(offerRestart: Bool, criticalErr: String)
|
||||
case INACTIVE
|
||||
}
|
||||
|
||||
@@ -1830,6 +1879,8 @@ public enum XFTPErrorType: Decodable {
|
||||
case NO_FILE
|
||||
case HAS_FILE
|
||||
case FILE_IO
|
||||
case TIMEOUT
|
||||
case REDIRECT(redirectError: String)
|
||||
case INTERNAL
|
||||
}
|
||||
|
||||
@@ -1837,6 +1888,8 @@ public enum RCErrorType: Decodable {
|
||||
case `internal`(internalErr: String)
|
||||
case identity
|
||||
case noLocalAddress
|
||||
case newController
|
||||
case notDiscovered
|
||||
case tlsStartFailed
|
||||
case exception(exception: String)
|
||||
case ctrlAuth
|
||||
@@ -1862,6 +1915,7 @@ public enum ProtocolTransportError: Decodable {
|
||||
case badBlock
|
||||
case largeMsg
|
||||
case badSession
|
||||
case noServerAuth
|
||||
case handshake(handshakeErr: SMPHandshakeError)
|
||||
}
|
||||
|
||||
@@ -1869,6 +1923,7 @@ public enum SMPHandshakeError: Decodable {
|
||||
case PARSE
|
||||
case VERSION
|
||||
case IDENTITY
|
||||
case BAD_AUTH
|
||||
}
|
||||
|
||||
public enum SMPAgentError: Decodable {
|
||||
@@ -1890,8 +1945,183 @@ public enum RemoteCtrlError: Decodable {
|
||||
case badState
|
||||
case busy
|
||||
case timeout
|
||||
case noKnownControllers
|
||||
case badController
|
||||
case disconnected(remoteCtrlId: Int64, reason: String)
|
||||
case badInvitation
|
||||
case badVersion(appVersion: String)
|
||||
// case protocolError(protocolError: RemoteProtocolError)
|
||||
case hTTP2Error(http2Error: String)
|
||||
case protocolError
|
||||
}
|
||||
|
||||
public struct MigrationFileLinkData: Codable {
|
||||
let networkConfig: NetworkConfig?
|
||||
|
||||
public init(networkConfig: NetworkConfig) {
|
||||
self.networkConfig = networkConfig
|
||||
}
|
||||
|
||||
public struct NetworkConfig: Codable {
|
||||
let socksProxy: String?
|
||||
let hostMode: HostMode?
|
||||
let requiredHostMode: Bool?
|
||||
|
||||
public init(socksProxy: String?, hostMode: HostMode?, requiredHostMode: Bool?) {
|
||||
self.socksProxy = socksProxy
|
||||
self.hostMode = hostMode
|
||||
self.requiredHostMode = requiredHostMode
|
||||
}
|
||||
|
||||
public func transformToPlatformSupported() -> NetworkConfig {
|
||||
return if let hostMode, let requiredHostMode {
|
||||
NetworkConfig(
|
||||
socksProxy: nil,
|
||||
hostMode: hostMode == .onionViaSocks ? .onionHost : hostMode,
|
||||
requiredHostMode: requiredHostMode
|
||||
)
|
||||
} else { self }
|
||||
}
|
||||
}
|
||||
|
||||
public func addToLink(link: String) -> String {
|
||||
"\(link)&data=\(encodeJSON(self).addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!)"
|
||||
}
|
||||
|
||||
public static func readFromLink(link: String) -> MigrationFileLinkData? {
|
||||
// standaloneFileInfo(link)
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
public struct AppSettings: Codable, Equatable {
|
||||
public var networkConfig: NetCfg? = nil
|
||||
public var privacyEncryptLocalFiles: Bool? = nil
|
||||
public var privacyAcceptImages: Bool? = nil
|
||||
public var privacyLinkPreviews: Bool? = nil
|
||||
public var privacyShowChatPreviews: Bool? = nil
|
||||
public var privacySaveLastDraft: Bool? = nil
|
||||
public var privacyProtectScreen: Bool? = nil
|
||||
public var notificationMode: AppSettingsNotificationMode? = nil
|
||||
public var notificationPreviewMode: NotificationPreviewMode? = nil
|
||||
public var webrtcPolicyRelay: Bool? = nil
|
||||
public var webrtcICEServers: [String]? = nil
|
||||
public var confirmRemoteSessions: Bool? = nil
|
||||
public var connectRemoteViaMulticast: Bool? = nil
|
||||
public var connectRemoteViaMulticastAuto: Bool? = nil
|
||||
public var developerTools: Bool? = nil
|
||||
public var confirmDBUpgrades: Bool? = nil
|
||||
public var androidCallOnLockScreen: AppSettingsLockScreenCalls? = nil
|
||||
public var iosCallKitEnabled: Bool? = nil
|
||||
public var iosCallKitCallsInRecents: Bool? = nil
|
||||
|
||||
public func prepareForExport() -> AppSettings {
|
||||
var empty = AppSettings()
|
||||
let def = AppSettings.defaults
|
||||
if networkConfig != def.networkConfig { empty.networkConfig = networkConfig }
|
||||
if privacyEncryptLocalFiles != def.privacyEncryptLocalFiles { empty.privacyEncryptLocalFiles = privacyEncryptLocalFiles }
|
||||
if privacyAcceptImages != def.privacyAcceptImages { empty.privacyAcceptImages = privacyAcceptImages }
|
||||
if privacyLinkPreviews != def.privacyLinkPreviews { empty.privacyLinkPreviews = privacyLinkPreviews }
|
||||
if privacyShowChatPreviews != def.privacyShowChatPreviews { empty.privacyShowChatPreviews = privacyShowChatPreviews }
|
||||
if privacySaveLastDraft != def.privacySaveLastDraft { empty.privacySaveLastDraft = privacySaveLastDraft }
|
||||
if privacyProtectScreen != def.privacyProtectScreen { empty.privacyProtectScreen = privacyProtectScreen }
|
||||
if notificationMode != def.notificationMode { empty.notificationMode = notificationMode }
|
||||
if notificationPreviewMode != def.notificationPreviewMode { empty.notificationPreviewMode = notificationPreviewMode }
|
||||
if webrtcPolicyRelay != def.webrtcPolicyRelay { empty.webrtcPolicyRelay = webrtcPolicyRelay }
|
||||
if webrtcICEServers != def.webrtcICEServers { empty.webrtcICEServers = webrtcICEServers }
|
||||
if confirmRemoteSessions != def.confirmRemoteSessions { empty.confirmRemoteSessions = confirmRemoteSessions }
|
||||
if connectRemoteViaMulticast != def.connectRemoteViaMulticast {empty.connectRemoteViaMulticast = connectRemoteViaMulticast }
|
||||
if connectRemoteViaMulticastAuto != def.connectRemoteViaMulticastAuto { empty.connectRemoteViaMulticastAuto = connectRemoteViaMulticastAuto }
|
||||
if developerTools != def.developerTools { empty.developerTools = developerTools }
|
||||
if confirmDBUpgrades != def.confirmDBUpgrades { empty.confirmDBUpgrades = confirmDBUpgrades }
|
||||
if androidCallOnLockScreen != def.androidCallOnLockScreen { empty.androidCallOnLockScreen = androidCallOnLockScreen }
|
||||
if iosCallKitEnabled != def.iosCallKitEnabled { empty.iosCallKitEnabled = iosCallKitEnabled }
|
||||
if iosCallKitCallsInRecents != def.iosCallKitCallsInRecents { empty.iosCallKitCallsInRecents = iosCallKitCallsInRecents }
|
||||
return empty
|
||||
}
|
||||
|
||||
public static var defaults: AppSettings {
|
||||
AppSettings (
|
||||
networkConfig: NetCfg.defaults,
|
||||
privacyEncryptLocalFiles: true,
|
||||
privacyAcceptImages: true,
|
||||
privacyLinkPreviews: true,
|
||||
privacyShowChatPreviews: true,
|
||||
privacySaveLastDraft: true,
|
||||
privacyProtectScreen: false,
|
||||
notificationMode: AppSettingsNotificationMode.instant,
|
||||
notificationPreviewMode: NotificationPreviewMode.message,
|
||||
webrtcPolicyRelay: true,
|
||||
webrtcICEServers: [],
|
||||
confirmRemoteSessions: false,
|
||||
connectRemoteViaMulticast: true,
|
||||
connectRemoteViaMulticastAuto: true,
|
||||
developerTools: false,
|
||||
confirmDBUpgrades: false,
|
||||
androidCallOnLockScreen: AppSettingsLockScreenCalls.show,
|
||||
iosCallKitEnabled: true,
|
||||
iosCallKitCallsInRecents: false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public enum AppSettingsNotificationMode: String, Codable {
|
||||
case off
|
||||
case periodic
|
||||
case instant
|
||||
|
||||
public func toNotificationsMode() -> NotificationsMode {
|
||||
switch self {
|
||||
case .instant: .instant
|
||||
case .periodic: .periodic
|
||||
case .off: .off
|
||||
}
|
||||
}
|
||||
|
||||
public static func from(_ mode: NotificationsMode) -> AppSettingsNotificationMode {
|
||||
switch mode {
|
||||
case .instant: .instant
|
||||
case .periodic: .periodic
|
||||
case .off: .off
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//public enum NotificationPreviewMode: Codable {
|
||||
// case hidden
|
||||
// case contact
|
||||
// case message
|
||||
//}
|
||||
|
||||
public enum AppSettingsLockScreenCalls: String, Codable {
|
||||
case disable
|
||||
case show
|
||||
case accept
|
||||
}
|
||||
|
||||
public struct UserNetworkInfo: Codable, Equatable {
|
||||
public let networkType: UserNetworkType
|
||||
public let online: Bool
|
||||
|
||||
public init(networkType: UserNetworkType, online: Bool) {
|
||||
self.networkType = networkType
|
||||
self.online = online
|
||||
}
|
||||
}
|
||||
|
||||
public enum UserNetworkType: String, Codable {
|
||||
case none
|
||||
case cellular
|
||||
case wifi
|
||||
case ethernet
|
||||
case other
|
||||
|
||||
public var text: LocalizedStringKey {
|
||||
switch self {
|
||||
case .none: "No network connection"
|
||||
case .cellular: "Cellular"
|
||||
case .wifi: "WiFi"
|
||||
case .ethernet: "Wired ethernet"
|
||||
case .other: "Other"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ public let GROUP_DEFAULT_CHAT_LAST_BACKGROUND_RUN = "chatLastBackgroundRun"
|
||||
let GROUP_DEFAULT_NTF_PREVIEW_MODE = "ntfPreviewMode"
|
||||
public let GROUP_DEFAULT_NTF_ENABLE_LOCAL = "ntfEnableLocal" // no longer used
|
||||
public let GROUP_DEFAULT_NTF_ENABLE_PERIODIC = "ntfEnablePeriodic" // no longer used
|
||||
// This setting is a main one, while having an unused duplicate from the past: DEFAULT_PRIVACY_ACCEPT_IMAGES
|
||||
let GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages"
|
||||
public let GROUP_DEFAULT_PRIVACY_TRANSFER_IMAGES_INLINE = "privacyTransferImagesInline" // no longer used
|
||||
public let GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES = "privacyEncryptLocalFiles"
|
||||
@@ -28,6 +29,7 @@ let GROUP_DEFAULT_NETWORK_SESSION_MODE = "networkSessionMode"
|
||||
let GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT = "networkTCPConnectTimeout"
|
||||
let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT = "networkTCPTimeout"
|
||||
let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb"
|
||||
let GROUP_DEFAULT_NETWORK_RCV_CONCURRENCY = "networkRcvConcurrency"
|
||||
let GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL = "networkSMPPingInterval"
|
||||
let GROUP_DEFAULT_NETWORK_SMP_PING_COUNT = "networkSMPPingCount"
|
||||
let GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE = "networkEnableKeepAlive"
|
||||
@@ -36,7 +38,7 @@ let GROUP_DEFAULT_NETWORK_TCP_KEEP_INTVL = "networkTCPKeepIntvl"
|
||||
let GROUP_DEFAULT_NETWORK_TCP_KEEP_CNT = "networkTCPKeepCnt"
|
||||
public let GROUP_DEFAULT_INCOGNITO = "incognito"
|
||||
let GROUP_DEFAULT_STORE_DB_PASSPHRASE = "storeDBPassphrase"
|
||||
let GROUP_DEFAULT_INITIAL_RANDOM_DB_PASSPHRASE = "initialRandomDBPassphrase"
|
||||
public let GROUP_DEFAULT_INITIAL_RANDOM_DB_PASSPHRASE = "initialRandomDBPassphrase"
|
||||
public let GROUP_DEFAULT_CONFIRM_DB_UPGRADES = "confirmDBUpgrades"
|
||||
public let GROUP_DEFAULT_CALL_KIT_ENABLED = "callKitEnabled"
|
||||
public let GROUP_DEFAULT_PQ_EXPERIMENTAL_ENABLED = "pqExperimentalEnabled"
|
||||
@@ -54,6 +56,7 @@ public func registerGroupDefaults() {
|
||||
GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT: NetCfg.defaults.tcpConnectTimeout,
|
||||
GROUP_DEFAULT_NETWORK_TCP_TIMEOUT: NetCfg.defaults.tcpTimeout,
|
||||
GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB: NetCfg.defaults.tcpTimeoutPerKb,
|
||||
GROUP_DEFAULT_NETWORK_RCV_CONCURRENCY: NetCfg.defaults.rcvConcurrency,
|
||||
GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL: NetCfg.defaults.smpPingInterval,
|
||||
GROUP_DEFAULT_NETWORK_SMP_PING_COUNT: NetCfg.defaults.smpPingCount,
|
||||
GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE: NetCfg.defaults.enableKeepAlive,
|
||||
@@ -169,6 +172,7 @@ public let ntfPreviewModeGroupDefault = EnumDefault<NotificationPreviewMode>(
|
||||
|
||||
public let incognitoGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_INCOGNITO)
|
||||
|
||||
// This setting is a main one, while having an unused duplicate from the past: DEFAULT_PRIVACY_ACCEPT_IMAGES
|
||||
public let privacyAcceptImagesGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PRIVACY_ACCEPT_IMAGES)
|
||||
|
||||
public let privacyEncryptLocalFilesGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES)
|
||||
@@ -195,7 +199,7 @@ public let confirmDBUpgradesGroupDefault = BoolDefault(defaults: groupDefaults,
|
||||
|
||||
public let callKitEnabledGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_CALL_KIT_ENABLED)
|
||||
|
||||
public let pqExperimentalEnabledDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PRIVACY_ENCRYPT_LOCAL_FILES)
|
||||
public let pqExperimentalEnabledDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_PQ_EXPERIMENTAL_ENABLED)
|
||||
|
||||
public class DateDefault {
|
||||
var defaults: UserDefaults
|
||||
@@ -276,6 +280,7 @@ public func getNetCfg() -> NetCfg {
|
||||
let tcpConnectTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT)
|
||||
let tcpTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT)
|
||||
let tcpTimeoutPerKb = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB)
|
||||
let rcvConcurrency = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_RCV_CONCURRENCY)
|
||||
let smpPingInterval = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL)
|
||||
let smpPingCount = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT)
|
||||
let enableKeepAlive = groupDefaults.bool(forKey: GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE)
|
||||
@@ -295,6 +300,7 @@ public func getNetCfg() -> NetCfg {
|
||||
tcpConnectTimeout: tcpConnectTimeout,
|
||||
tcpTimeout: tcpTimeout,
|
||||
tcpTimeoutPerKb: tcpTimeoutPerKb,
|
||||
rcvConcurrency: rcvConcurrency,
|
||||
tcpKeepAlive: tcpKeepAlive,
|
||||
smpPingInterval: smpPingInterval,
|
||||
smpPingCount: smpPingCount,
|
||||
@@ -308,6 +314,7 @@ public func setNetCfg(_ cfg: NetCfg) {
|
||||
groupDefaults.set(cfg.tcpConnectTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT)
|
||||
groupDefaults.set(cfg.tcpTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT)
|
||||
groupDefaults.set(cfg.tcpTimeoutPerKb, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB)
|
||||
groupDefaults.set(cfg.rcvConcurrency, forKey: GROUP_DEFAULT_NETWORK_RCV_CONCURRENCY)
|
||||
groupDefaults.set(cfg.smpPingInterval, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL)
|
||||
groupDefaults.set(cfg.smpPingCount, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT)
|
||||
if let tcpKeepAlive = cfg.tcpKeepAlive {
|
||||
|
||||
@@ -543,6 +543,7 @@ public protocol Feature {
|
||||
var iconFilled: String { get }
|
||||
var iconScale: CGFloat { get }
|
||||
var hasParam: Bool { get }
|
||||
var hasRole: Bool { get }
|
||||
var text: String { get }
|
||||
}
|
||||
|
||||
@@ -569,6 +570,8 @@ public enum ChatFeature: String, Decodable, Feature {
|
||||
}
|
||||
}
|
||||
|
||||
public var hasRole: Bool { false }
|
||||
|
||||
public var text: String {
|
||||
switch self {
|
||||
case .timedMessages: return NSLocalizedString("Disappearing messages", comment: "chat feature")
|
||||
@@ -694,6 +697,7 @@ public enum GroupFeature: String, Decodable, Feature {
|
||||
case reactions
|
||||
case voice
|
||||
case files
|
||||
case simplexLinks
|
||||
case history
|
||||
|
||||
public var id: Self { self }
|
||||
@@ -705,6 +709,19 @@ public enum GroupFeature: String, Decodable, Feature {
|
||||
}
|
||||
}
|
||||
|
||||
public var hasRole: Bool {
|
||||
switch self {
|
||||
case .timedMessages: false
|
||||
case .directMessages: true
|
||||
case .fullDelete: false
|
||||
case .reactions: false
|
||||
case .voice: true
|
||||
case .files: true
|
||||
case .simplexLinks: true
|
||||
case .history: false
|
||||
}
|
||||
}
|
||||
|
||||
public var text: String {
|
||||
switch self {
|
||||
case .timedMessages: return NSLocalizedString("Disappearing messages", comment: "chat feature")
|
||||
@@ -713,6 +730,7 @@ public enum GroupFeature: String, Decodable, Feature {
|
||||
case .reactions: return NSLocalizedString("Message reactions", comment: "chat feature")
|
||||
case .voice: return NSLocalizedString("Voice messages", comment: "chat feature")
|
||||
case .files: return NSLocalizedString("Files and media", comment: "chat feature")
|
||||
case .simplexLinks: return NSLocalizedString("SimpleX links", comment: "chat feature")
|
||||
case .history: return NSLocalizedString("Visible history", comment: "chat feature")
|
||||
}
|
||||
}
|
||||
@@ -725,6 +743,7 @@ public enum GroupFeature: String, Decodable, Feature {
|
||||
case .reactions: return "face.smiling"
|
||||
case .voice: return "mic"
|
||||
case .files: return "doc"
|
||||
case .simplexLinks: return "link.circle"
|
||||
case .history: return "clock"
|
||||
}
|
||||
}
|
||||
@@ -737,6 +756,7 @@ public enum GroupFeature: String, Decodable, Feature {
|
||||
case .reactions: return "face.smiling.fill"
|
||||
case .voice: return "mic.fill"
|
||||
case .files: return "doc.fill"
|
||||
case .simplexLinks: return "link.circle.fill"
|
||||
case .history: return "clock.fill"
|
||||
}
|
||||
}
|
||||
@@ -781,6 +801,11 @@ public enum GroupFeature: String, Decodable, Feature {
|
||||
case .on: return "Allow to send files and media."
|
||||
case .off: return "Prohibit sending files and media."
|
||||
}
|
||||
case .simplexLinks:
|
||||
switch enabled {
|
||||
case .on: return "Allow to send SimpleX links."
|
||||
case .off: return "Prohibit sending SimpleX links."
|
||||
}
|
||||
case .history:
|
||||
switch enabled {
|
||||
case .on: return "Send up to 100 last messages to new members."
|
||||
@@ -819,6 +844,11 @@ public enum GroupFeature: String, Decodable, Feature {
|
||||
case .on: return "Group members can send files and media."
|
||||
case .off: return "Files and media are prohibited in this group."
|
||||
}
|
||||
case .simplexLinks:
|
||||
switch enabled {
|
||||
case .on: return "Group members can send SimpleX links."
|
||||
case .off: return "SimpleX links are prohibited in this group."
|
||||
}
|
||||
case .history:
|
||||
switch enabled {
|
||||
case .on: return "Up to 100 last messages are sent to new members."
|
||||
@@ -958,20 +988,22 @@ public enum FeatureAllowed: String, Codable, Identifiable {
|
||||
|
||||
public struct FullGroupPreferences: Decodable, Equatable {
|
||||
public var timedMessages: TimedMessagesGroupPreference
|
||||
public var directMessages: GroupPreference
|
||||
public var directMessages: RoleGroupPreference
|
||||
public var fullDelete: GroupPreference
|
||||
public var reactions: GroupPreference
|
||||
public var voice: GroupPreference
|
||||
public var files: GroupPreference
|
||||
public var voice: RoleGroupPreference
|
||||
public var files: RoleGroupPreference
|
||||
public var simplexLinks: RoleGroupPreference
|
||||
public var history: GroupPreference
|
||||
|
||||
public init(
|
||||
timedMessages: TimedMessagesGroupPreference,
|
||||
directMessages: GroupPreference,
|
||||
directMessages: RoleGroupPreference,
|
||||
fullDelete: GroupPreference,
|
||||
reactions: GroupPreference,
|
||||
voice: GroupPreference,
|
||||
files: GroupPreference,
|
||||
voice: RoleGroupPreference,
|
||||
files: RoleGroupPreference,
|
||||
simplexLinks: RoleGroupPreference,
|
||||
history: GroupPreference
|
||||
) {
|
||||
self.timedMessages = timedMessages
|
||||
@@ -980,36 +1012,40 @@ public struct FullGroupPreferences: Decodable, Equatable {
|
||||
self.reactions = reactions
|
||||
self.voice = voice
|
||||
self.files = files
|
||||
self.simplexLinks = simplexLinks
|
||||
self.history = history
|
||||
}
|
||||
|
||||
public static let sampleData = FullGroupPreferences(
|
||||
timedMessages: TimedMessagesGroupPreference(enable: .off),
|
||||
directMessages: GroupPreference(enable: .off),
|
||||
directMessages: RoleGroupPreference(enable: .off, role: nil),
|
||||
fullDelete: GroupPreference(enable: .off),
|
||||
reactions: GroupPreference(enable: .on),
|
||||
voice: GroupPreference(enable: .on),
|
||||
files: GroupPreference(enable: .on),
|
||||
voice: RoleGroupPreference(enable: .on, role: nil),
|
||||
files: RoleGroupPreference(enable: .on, role: nil),
|
||||
simplexLinks: RoleGroupPreference(enable: .on, role: nil),
|
||||
history: GroupPreference(enable: .on)
|
||||
)
|
||||
}
|
||||
|
||||
public struct GroupPreferences: Codable {
|
||||
public var timedMessages: TimedMessagesGroupPreference?
|
||||
public var directMessages: GroupPreference?
|
||||
public var directMessages: RoleGroupPreference?
|
||||
public var fullDelete: GroupPreference?
|
||||
public var reactions: GroupPreference?
|
||||
public var voice: GroupPreference?
|
||||
public var files: GroupPreference?
|
||||
public var voice: RoleGroupPreference?
|
||||
public var files: RoleGroupPreference?
|
||||
public var simplexLinks: RoleGroupPreference?
|
||||
public var history: GroupPreference?
|
||||
|
||||
public init(
|
||||
timedMessages: TimedMessagesGroupPreference? = nil,
|
||||
directMessages: GroupPreference? = nil,
|
||||
directMessages: RoleGroupPreference? = nil,
|
||||
fullDelete: GroupPreference? = nil,
|
||||
reactions: GroupPreference? = nil,
|
||||
voice: GroupPreference? = nil,
|
||||
files: GroupPreference? = nil,
|
||||
voice: RoleGroupPreference? = nil,
|
||||
files: RoleGroupPreference? = nil,
|
||||
simplexLinks: RoleGroupPreference? = nil,
|
||||
history: GroupPreference? = nil
|
||||
) {
|
||||
self.timedMessages = timedMessages
|
||||
@@ -1018,16 +1054,18 @@ public struct GroupPreferences: Codable {
|
||||
self.reactions = reactions
|
||||
self.voice = voice
|
||||
self.files = files
|
||||
self.simplexLinks = simplexLinks
|
||||
self.history = history
|
||||
}
|
||||
|
||||
public static let sampleData = GroupPreferences(
|
||||
timedMessages: TimedMessagesGroupPreference(enable: .off),
|
||||
directMessages: GroupPreference(enable: .off),
|
||||
directMessages: RoleGroupPreference(enable: .off, role: nil),
|
||||
fullDelete: GroupPreference(enable: .off),
|
||||
reactions: GroupPreference(enable: .on),
|
||||
voice: GroupPreference(enable: .on),
|
||||
files: GroupPreference(enable: .on),
|
||||
voice: RoleGroupPreference(enable: .on, role: nil),
|
||||
files: RoleGroupPreference(enable: .on, role: nil),
|
||||
simplexLinks: RoleGroupPreference(enable: .on, role: nil),
|
||||
history: GroupPreference(enable: .on)
|
||||
)
|
||||
}
|
||||
@@ -1040,6 +1078,7 @@ public func toGroupPreferences(_ fullPreferences: FullGroupPreferences) -> Group
|
||||
reactions: fullPreferences.reactions,
|
||||
voice: fullPreferences.voice,
|
||||
files: fullPreferences.files,
|
||||
simplexLinks: fullPreferences.simplexLinks,
|
||||
history: fullPreferences.history
|
||||
)
|
||||
}
|
||||
@@ -1051,11 +1090,37 @@ public struct GroupPreference: Codable, Equatable {
|
||||
enable == .on
|
||||
}
|
||||
|
||||
public func enabled(_ role: GroupMemberRole?, for m: GroupMember?) -> GroupFeatureEnabled {
|
||||
switch enable {
|
||||
case .off: .off
|
||||
case .on:
|
||||
if let role, let m {
|
||||
m.memberRole >= role ? .on : .off
|
||||
} else {
|
||||
.on
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init(enable: GroupFeatureEnabled) {
|
||||
self.enable = enable
|
||||
}
|
||||
}
|
||||
|
||||
public struct RoleGroupPreference: Codable, Equatable {
|
||||
public var enable: GroupFeatureEnabled
|
||||
public var role: GroupMemberRole?
|
||||
|
||||
public func on(for m: GroupMember) -> Bool {
|
||||
enable == .on && m.memberRole >= (role ?? .observer)
|
||||
}
|
||||
|
||||
public init(enable: GroupFeatureEnabled, role: GroupMemberRole?) {
|
||||
self.enable = enable
|
||||
self.role = role
|
||||
}
|
||||
}
|
||||
|
||||
public struct TimedMessagesGroupPreference: Codable, Equatable {
|
||||
public var enable: GroupFeatureEnabled
|
||||
public var ttl: Int?
|
||||
@@ -1280,7 +1345,7 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat {
|
||||
case .timedMessages: return prefs.timedMessages.on
|
||||
case .fullDelete: return prefs.fullDelete.on
|
||||
case .reactions: return prefs.reactions.on
|
||||
case .voice: return prefs.voice.on
|
||||
case .voice: return prefs.voice.on(for: groupInfo.membership)
|
||||
case .calls: return false
|
||||
}
|
||||
case .local:
|
||||
@@ -1323,7 +1388,7 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat {
|
||||
return .other
|
||||
}
|
||||
case let .group(groupInfo):
|
||||
if !groupInfo.fullGroupPreferences.voice.on {
|
||||
if !groupInfo.fullGroupPreferences.voice.on(for: groupInfo.membership) {
|
||||
return .groupOwnerCan
|
||||
} else {
|
||||
return .other
|
||||
@@ -1532,14 +1597,15 @@ public struct Connection: Decodable {
|
||||
public var viaGroupLink: Bool
|
||||
public var customUserProfileId: Int64?
|
||||
public var connectionCode: SecurityCode?
|
||||
public var enablePQ: Bool
|
||||
public var pqSupport: Bool
|
||||
public var pqEncryption: Bool
|
||||
public var pqSndEnabled: Bool?
|
||||
public var pqRcvEnabled: Bool?
|
||||
|
||||
public var connectionStats: ConnectionStats? = nil
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case connId, agentConnId, peerChatVRange, connStatus, connLevel, viaGroupLink, customUserProfileId, connectionCode, enablePQ, pqSndEnabled, pqRcvEnabled
|
||||
case connId, agentConnId, peerChatVRange, connStatus, connLevel, viaGroupLink, customUserProfileId, connectionCode, pqSupport, pqEncryption, pqSndEnabled, pqRcvEnabled
|
||||
}
|
||||
|
||||
public var id: ChatId { get { ":\(connId)" } }
|
||||
@@ -1555,7 +1621,8 @@ public struct Connection: Decodable {
|
||||
connStatus: .ready,
|
||||
connLevel: 0,
|
||||
viaGroupLink: false,
|
||||
enablePQ: false
|
||||
pqSupport: false,
|
||||
pqEncryption: false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1973,7 +2040,7 @@ public struct GroupMemberIds: Decodable {
|
||||
var groupId: Int64
|
||||
}
|
||||
|
||||
public enum GroupMemberRole: String, Identifiable, CaseIterable, Comparable, Decodable {
|
||||
public enum GroupMemberRole: String, Identifiable, CaseIterable, Comparable, Codable {
|
||||
case observer = "observer"
|
||||
case author = "author"
|
||||
case member = "member"
|
||||
@@ -2118,7 +2185,7 @@ public enum ConnectionEntity: Decodable {
|
||||
public var id: String? {
|
||||
switch self {
|
||||
case let .rcvDirectMsgConnection(contact):
|
||||
return contact?.id ?? nil
|
||||
return contact?.id
|
||||
case let .rcvGroupMsgConnection(_, groupMember):
|
||||
return groupMember.id
|
||||
case let .userContactConnection(userContact):
|
||||
@@ -2370,10 +2437,10 @@ public struct ChatItem: Identifiable, Decodable {
|
||||
}
|
||||
}
|
||||
|
||||
public static func getSample (_ id: Int64, _ dir: CIDirection, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, quotedItem: CIQuote? = nil, file: CIFile? = nil, itemDeleted: CIDeleted? = nil, itemEdited: Bool = false, itemLive: Bool = false, editable: Bool = true) -> ChatItem {
|
||||
public static func getSample (_ id: Int64, _ dir: CIDirection, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, quotedItem: CIQuote? = nil, file: CIFile? = nil, itemDeleted: CIDeleted? = nil, itemEdited: Bool = false, itemLive: Bool = false, deletable: Bool = true, editable: Bool = true) -> ChatItem {
|
||||
ChatItem(
|
||||
chatDir: dir,
|
||||
meta: CIMeta.getSample(id, ts, text, status, itemDeleted: itemDeleted, itemEdited: itemEdited, itemLive: itemLive, editable: editable),
|
||||
meta: CIMeta.getSample(id, ts, text, status, itemDeleted: itemDeleted, itemEdited: itemEdited, itemLive: itemLive, deletable: deletable, editable: editable),
|
||||
content: .sndMsgContent(msgContent: .text(text)),
|
||||
quotedItem: quotedItem,
|
||||
file: file
|
||||
@@ -2464,6 +2531,7 @@ public struct ChatItem: Identifiable, Decodable {
|
||||
itemDeleted: nil,
|
||||
itemEdited: false,
|
||||
itemLive: false,
|
||||
deletable: false,
|
||||
editable: false
|
||||
),
|
||||
content: .rcvDeleted(deleteMode: .cidmBroadcast),
|
||||
@@ -2485,6 +2553,7 @@ public struct ChatItem: Identifiable, Decodable {
|
||||
itemDeleted: nil,
|
||||
itemEdited: false,
|
||||
itemLive: true,
|
||||
deletable: false,
|
||||
editable: false
|
||||
),
|
||||
content: .sndMsgContent(msgContent: .text("")),
|
||||
@@ -2544,10 +2613,12 @@ public struct CIMeta: Decodable {
|
||||
public var itemStatus: CIStatus
|
||||
public var createdAt: Date
|
||||
public var updatedAt: Date
|
||||
public var itemForwarded: CIForwardedFrom?
|
||||
public var itemDeleted: CIDeleted?
|
||||
public var itemEdited: Bool
|
||||
public var itemTimed: CITimed?
|
||||
public var itemLive: Bool?
|
||||
public var deletable: Bool
|
||||
public var editable: Bool
|
||||
|
||||
public var timestampText: Text { get { formatTimestampText(itemTs) } }
|
||||
@@ -2564,7 +2635,7 @@ public struct CIMeta: Decodable {
|
||||
itemStatus.statusIcon(metaColor)
|
||||
}
|
||||
|
||||
public static func getSample(_ id: Int64, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, itemDeleted: CIDeleted? = nil, itemEdited: Bool = false, itemLive: Bool = false, editable: Bool = true) -> CIMeta {
|
||||
public static func getSample(_ id: Int64, _ ts: Date, _ text: String, _ status: CIStatus = .sndNew, itemDeleted: CIDeleted? = nil, itemEdited: Bool = false, itemLive: Bool = false, deletable: Bool = true, editable: Bool = true) -> CIMeta {
|
||||
CIMeta(
|
||||
itemId: id,
|
||||
itemTs: ts,
|
||||
@@ -2575,6 +2646,7 @@ public struct CIMeta: Decodable {
|
||||
itemDeleted: itemDeleted,
|
||||
itemEdited: itemEdited,
|
||||
itemLive: itemLive,
|
||||
deletable: deletable,
|
||||
editable: editable
|
||||
)
|
||||
}
|
||||
@@ -2590,6 +2662,7 @@ public struct CIMeta: Decodable {
|
||||
itemDeleted: nil,
|
||||
itemEdited: false,
|
||||
itemLive: false,
|
||||
deletable: false,
|
||||
editable: false
|
||||
)
|
||||
}
|
||||
@@ -2711,6 +2784,31 @@ public enum CIDeleted: Decodable {
|
||||
}
|
||||
}
|
||||
|
||||
public enum MsgDirection: String, Decodable {
|
||||
case rcv = "rcv"
|
||||
case snd = "snd"
|
||||
}
|
||||
|
||||
public enum CIForwardedFrom: Decodable {
|
||||
case unknown
|
||||
case contact(chatName: String, msgDir: MsgDirection, contactId: Int64?, chatItemId: Int64?)
|
||||
case group(chatName: String, msgDir: MsgDirection, groupId: Int64?, chatItemId: Int64?)
|
||||
|
||||
var chatName: String {
|
||||
switch self {
|
||||
case .unknown: ""
|
||||
case let .contact(chatName, _, _, _): chatName
|
||||
case let .group(chatName, _, _, _): chatName
|
||||
}
|
||||
}
|
||||
|
||||
public func text(_ chatType: ChatType) -> LocalizedStringKey {
|
||||
chatType == .local
|
||||
? (chatName == "" ? "saved" : "saved from \(chatName)")
|
||||
: "forwarded"
|
||||
}
|
||||
}
|
||||
|
||||
public enum CIDeleteMode: String, Decodable {
|
||||
case cidmBroadcast = "broadcast"
|
||||
case cidmInternal = "internal"
|
||||
@@ -2740,8 +2838,8 @@ public enum CIContent: Decodable, ItemContent {
|
||||
case sndChatFeature(feature: ChatFeature, enabled: FeatureEnabled, param: Int?)
|
||||
case rcvChatPreference(feature: ChatFeature, allowed: FeatureAllowed, param: Int?)
|
||||
case sndChatPreference(feature: ChatFeature, allowed: FeatureAllowed, param: Int?)
|
||||
case rcvGroupFeature(groupFeature: GroupFeature, preference: GroupPreference, param: Int?)
|
||||
case sndGroupFeature(groupFeature: GroupFeature, preference: GroupPreference, param: Int?)
|
||||
case rcvGroupFeature(groupFeature: GroupFeature, preference: GroupPreference, param: Int?, memberRole_: GroupMemberRole?)
|
||||
case sndGroupFeature(groupFeature: GroupFeature, preference: GroupPreference, param: Int?, memberRole_: GroupMemberRole?)
|
||||
case rcvChatFeatureRejected(feature: ChatFeature)
|
||||
case rcvGroupFeatureRejected(groupFeature: GroupFeature)
|
||||
case sndModerated
|
||||
@@ -2775,36 +2873,51 @@ public enum CIContent: Decodable, ItemContent {
|
||||
case let .sndChatFeature(feature, enabled, param): return CIContent.featureText(feature, enabled.text, param)
|
||||
case let .rcvChatPreference(feature, allowed, param): return CIContent.preferenceText(feature, allowed, param)
|
||||
case let .sndChatPreference(feature, allowed, param): return CIContent.preferenceText(feature, allowed, param)
|
||||
case let .rcvGroupFeature(feature, preference, param): return CIContent.featureText(feature, preference.enable.text, param)
|
||||
case let .sndGroupFeature(feature, preference, param): return CIContent.featureText(feature, preference.enable.text, param)
|
||||
case let .rcvGroupFeature(feature, preference, param, role): return CIContent.featureText(feature, preference.enable.text, param, role)
|
||||
case let .sndGroupFeature(feature, preference, param, role): return CIContent.featureText(feature, preference.enable.text, param, role)
|
||||
case let .rcvChatFeatureRejected(feature): return String.localizedStringWithFormat("%@: received, prohibited", feature.text)
|
||||
case let .rcvGroupFeatureRejected(groupFeature): return String.localizedStringWithFormat("%@: received, prohibited", groupFeature.text)
|
||||
case .sndModerated: return NSLocalizedString("moderated", comment: "moderated chat item")
|
||||
case .rcvModerated: return NSLocalizedString("moderated", comment: "moderated chat item")
|
||||
case .rcvBlocked: return NSLocalizedString("blocked by admin", comment: "blocked chat item")
|
||||
case let .sndDirectE2EEInfo(e2eeInfo): return directE2EEInfoToText(e2eeInfo)
|
||||
case let .rcvDirectE2EEInfo(e2eeInfo): return directE2EEInfoToText(e2eeInfo)
|
||||
case .sndGroupE2EEInfo: return e2eeInfoNoPQText
|
||||
case .rcvGroupE2EEInfo: return e2eeInfoNoPQText
|
||||
case let .sndDirectE2EEInfo(e2eeInfo): return directE2EEInfoStr(e2eeInfo)
|
||||
case let .rcvDirectE2EEInfo(e2eeInfo): return directE2EEInfoStr(e2eeInfo)
|
||||
case .sndGroupE2EEInfo: return e2eeInfoNoPQStr
|
||||
case .rcvGroupE2EEInfo: return e2eeInfoNoPQStr
|
||||
case .invalidJSON: return NSLocalizedString("invalid data", comment: "invalid chat item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func directE2EEInfoToText(_ e2eeInfo: E2EEInfo) -> String {
|
||||
private func directE2EEInfoStr(_ e2eeInfo: E2EEInfo) -> String {
|
||||
e2eeInfo.pqEnabled
|
||||
? NSLocalizedString("This conversation is protected by quantum resistant end-to-end encryption. It has perfect forward secrecy, repudiation and quantum resistant break-in recovery.", comment: "E2EE info chat item")
|
||||
: e2eeInfoNoPQText
|
||||
? NSLocalizedString("This chat is protected by quantum resistant end-to-end encryption.", comment: "E2EE info chat item")
|
||||
: e2eeInfoNoPQStr
|
||||
}
|
||||
|
||||
private var e2eeInfoNoPQText: String {
|
||||
NSLocalizedString("This conversation is protected by end-to-end encryption with perfect forward secrecy, repudiation and break-in recovery.", comment: "E2EE info chat item")
|
||||
private var e2eeInfoNoPQStr: String {
|
||||
NSLocalizedString("This chat is protected by end-to-end encryption.", comment: "E2EE info chat item")
|
||||
}
|
||||
|
||||
static func featureText(_ feature: Feature, _ enabled: String, _ param: Int?) -> String {
|
||||
feature.hasParam
|
||||
? "\(feature.text): \(timeText(param))"
|
||||
: "\(feature.text): \(enabled)"
|
||||
static func featureText(_ feature: Feature, _ enabled: String, _ param: Int?, _ role: GroupMemberRole? = nil) -> String {
|
||||
(
|
||||
feature.hasParam
|
||||
? "\(feature.text): \(timeText(param))"
|
||||
: "\(feature.text): \(enabled)"
|
||||
) +
|
||||
(
|
||||
feature.hasRole && role != nil
|
||||
? " (\(roleText(role)))"
|
||||
: ""
|
||||
)
|
||||
}
|
||||
|
||||
private static func roleText(_ role: GroupMemberRole?) -> String {
|
||||
switch role {
|
||||
case .owner: NSLocalizedString("owners", comment: "feature role")
|
||||
case .admin: NSLocalizedString("admins", comment: "feature role")
|
||||
default: NSLocalizedString("all members", comment: "feature role")
|
||||
}
|
||||
}
|
||||
|
||||
public static func preferenceText(_ feature: Feature, _ allowed: FeatureAllowed, _ param: Int?) -> String {
|
||||
@@ -3207,6 +3320,14 @@ public enum MsgContent: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public var isImageOrVideo: Bool {
|
||||
switch self {
|
||||
case .image: true
|
||||
case .video: true
|
||||
default: false
|
||||
}
|
||||
}
|
||||
|
||||
var cmdString: String {
|
||||
"json \(encodeJSON(self))"
|
||||
}
|
||||
@@ -3408,11 +3529,14 @@ public struct SndFileTransfer: Decodable {
|
||||
}
|
||||
|
||||
public struct RcvFileTransfer: Decodable {
|
||||
|
||||
public let fileId: Int64
|
||||
}
|
||||
|
||||
public struct FileTransferMeta: Decodable {
|
||||
|
||||
public let fileId: Int64
|
||||
public let fileName: String
|
||||
public let filePath: String
|
||||
public let fileSize: Int64
|
||||
}
|
||||
|
||||
public enum CICallStatus: String, Decodable {
|
||||
@@ -3623,9 +3747,9 @@ public enum RcvConnEvent: Decodable {
|
||||
return NSLocalizedString("security code changed", comment: "chat item text")
|
||||
case let .pqEnabled(enabled):
|
||||
if enabled {
|
||||
return NSLocalizedString("enabled post-quantum encryption", comment: "chat item text")
|
||||
return NSLocalizedString("quantum resistant e2e encryption", comment: "chat item text")
|
||||
} else {
|
||||
return NSLocalizedString("disabled post-quantum encryption", comment: "chat item text")
|
||||
return NSLocalizedString("standard end-to-end encryption", comment: "chat item text")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3670,9 +3794,9 @@ public enum SndConnEvent: Decodable {
|
||||
return ratchetSyncStatusToText(syncStatus)
|
||||
case let .pqEnabled(enabled):
|
||||
if enabled {
|
||||
return NSLocalizedString("enabled post-quantum encryption", comment: "chat item text")
|
||||
return NSLocalizedString("quantum resistant e2e encryption", comment: "chat item text")
|
||||
} else {
|
||||
return NSLocalizedString("disabled post-quantum encryption", comment: "chat item text")
|
||||
return NSLocalizedString("standard end-to-end encryption", comment: "chat item text")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3738,6 +3862,7 @@ public enum ChatItemTTL: Hashable, Identifiable, Comparable {
|
||||
public struct ChatItemInfo: Decodable {
|
||||
public var itemVersions: [ChatItemVersion]
|
||||
public var memberDeliveryStatuses: [MemberDeliveryStatus]?
|
||||
public var forwardedFromChatItem: AChatItem?
|
||||
}
|
||||
|
||||
public struct ChatItemVersion: Decodable {
|
||||
|
||||
@@ -28,9 +28,9 @@ public let MAX_FILE_SIZE_SMP: Int64 = 8000000
|
||||
|
||||
public let MAX_VOICE_MESSAGE_LENGTH = TimeInterval(300)
|
||||
|
||||
private let CHAT_DB: String = "_chat.db"
|
||||
let CHAT_DB: String = "_chat.db"
|
||||
|
||||
private let AGENT_DB: String = "_agent.db"
|
||||
let AGENT_DB: String = "_agent.db"
|
||||
|
||||
private let CHAT_DB_BAK: String = "_chat.db.bak"
|
||||
|
||||
@@ -83,6 +83,7 @@ public func deleteAppDatabaseAndFiles() {
|
||||
try? fm.removeItem(atPath: dbPath + CHAT_DB_BAK)
|
||||
try? fm.removeItem(atPath: dbPath + AGENT_DB_BAK)
|
||||
try? fm.removeItem(at: getTempFilesDirectory())
|
||||
try? fm.removeItem(at: getMigrationTempFilesDirectory())
|
||||
try? fm.createDirectory(at: getTempFilesDirectory(), withIntermediateDirectories: true)
|
||||
deleteAppFiles()
|
||||
_ = kcDatabasePassword.remove()
|
||||
@@ -183,6 +184,10 @@ public func getTempFilesDirectory() -> URL {
|
||||
getAppDirectory().appendingPathComponent("temp_files", isDirectory: true)
|
||||
}
|
||||
|
||||
public func getMigrationTempFilesDirectory() -> URL {
|
||||
getDocumentsDirectory().appendingPathComponent("migration_temp_files", isDirectory: true)
|
||||
}
|
||||
|
||||
public func getAppFilesDirectory() -> URL {
|
||||
getAppDirectory().appendingPathComponent("app_files", isDirectory: true)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ void haskell_init(void) {
|
||||
char *argv[] = {
|
||||
"simplex",
|
||||
"+RTS", // requires `hs_init_with_rtsopts`
|
||||
"-A16m", // chunk size for new allocations
|
||||
"-A64m", // chunk size for new allocations
|
||||
"-H64m", // initial heap size
|
||||
"-xn", // non-moving GC
|
||||
0
|
||||
|
||||
@@ -202,6 +202,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages blocked" = "%lld блокирани съобщения";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages blocked by admin" = "%lld съобщения, блокирани от администратора";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages marked deleted" = "%lld съобщения, маркирани като изтрити";
|
||||
|
||||
@@ -374,6 +377,9 @@
|
||||
/* member role */
|
||||
"admin" = "админ";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Admins can block a member for all." = "Администраторите могат да блокират член за всички.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Admins can create the links to join groups." = "Админите могат да създадат линкове за присъединяване към групи.";
|
||||
|
||||
@@ -398,6 +404,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"All group members will remain connected." = "Всички членове на групата ще останат свързани.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All messages will be deleted - this cannot be undone!" = "Всички съобщения ще бъдат изтрити - това не може да бъде отменено!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." = "Всички съобщения ще бъдат изтрити - това не може да бъде отменено! Съобщенията ще бъдат изтрити САМО за вас.";
|
||||
|
||||
@@ -410,6 +419,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"All your contacts will remain connected. Profile update will be sent to your contacts." = "Всички ваши контакти ще останат свързани. Актуализацията на профила ще бъде изпратена до вашите контакти.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." = "Всички ваши контакти, разговори и файлове ще бъдат сигурно криптирани и качени на парчета в конфигурираните XFTP релета.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Allow" = "Позволи";
|
||||
|
||||
@@ -491,6 +503,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"App build: %@" = "Компилация на приложението: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"App data migration" = "Миграция на данните от приложението";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"App encrypts new local files (except videos)." = "Приложението криптира нови локални файлове (с изключение на видеоклипове).";
|
||||
|
||||
@@ -512,6 +527,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Appearance" = "Изглед";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Apply" = "Приложи";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Archive and upload" = "Архивиране и качване";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Archiving database" = "Архивиране на база данни";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Attach" = "Прикачи";
|
||||
|
||||
@@ -581,6 +605,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Block" = "Блокирай";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block for all" = "Блокирай за всички";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block group members" = "Блокиране на членове на групата";
|
||||
|
||||
@@ -588,11 +615,23 @@
|
||||
"Block member" = "Блокирай член";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block member?" = "Блокирай члена?";
|
||||
"Block member for all?" = "Блокиране на член за всички?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block member?" = "Блокирай члена?";
|
||||
|
||||
/* marked deleted chat item preview text */
|
||||
"blocked" = "блокиран";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"blocked %@" = "блокиран %@";
|
||||
|
||||
/* marked deleted chat item preview text */
|
||||
"blocked by admin" = "блокиран от админ";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Blocked by admin" = "Блокиран от админ";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"bold" = "удебелен";
|
||||
|
||||
@@ -644,6 +683,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Cancel" = "Отказ";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Cancel migration" = "Отмени миграцията";
|
||||
|
||||
/* feature offered item */
|
||||
"cancelled %@" = "отменен %@";
|
||||
|
||||
@@ -685,7 +727,7 @@
|
||||
"Change self-destruct passcode" = "Промени кода за достъп за самоунищожение";
|
||||
|
||||
/* chat item text */
|
||||
"changed address for you" = "променен е адреса за вас";
|
||||
"changed address for you" = "адреса за изпращане е променен";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"changed role of %@ to %@" = "променена роля от %1$@ на %2$@";
|
||||
@@ -723,6 +765,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat." = "Чатът е спрян. Ако вече сте използвали тази база данни на друго устройство, трябва да я прехвърлите обратно, преди да стартирате чата отново.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Chat migrated!" = "Чатът е мигриран!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Chat preferences" = "Чат настройки";
|
||||
|
||||
@@ -750,6 +795,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Clear conversation?" = "Изчисти разговора?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Clear private notes?" = "Изчистване на лични бележки?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Clear verification" = "Изчисти проверката";
|
||||
|
||||
@@ -777,6 +825,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm database upgrades" = "Потвърди актуализаациите на базата данни";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm network settings" = "Потвърди мрежовите настройки";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm new passphrase…" = "Потвърди новата парола…";
|
||||
|
||||
@@ -786,6 +837,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm password" = "Потвърди парола";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm that you remember database passphrase to migrate it." = "Потвърдете, че помните паролата на базата данни, преди да я мигрирате.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm upload" = "Потвърди качването";
|
||||
|
||||
/* server test step */
|
||||
"Connect" = "Свързване";
|
||||
|
||||
@@ -888,6 +945,9 @@
|
||||
/* connection information */
|
||||
"connection:%@" = "връзка:%@";
|
||||
|
||||
/* profile update event chat item */
|
||||
"contact %@ changed to %@" = "името на контакта %1$@ е променено на %2$@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Contact allows" = "Контактът позволява";
|
||||
|
||||
@@ -972,9 +1032,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Create your profile" = "Създай своя профил";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Created at" = "Създаден на";
|
||||
|
||||
/* copied message info */
|
||||
"Created at: %@" = "Създаден на: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Created on %@" = "Създаден на %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Creating archive link" = "Създаване на архивен линк";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Creating link…" = "Линкът се създава…";
|
||||
|
||||
@@ -1122,6 +1191,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Delete database" = "Изтрий базата данни";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Delete database from this device" = "Изтриване на базата данни от това устройство";
|
||||
|
||||
/* server test step */
|
||||
"Delete file" = "Изтрий файл";
|
||||
|
||||
@@ -1291,7 +1363,7 @@
|
||||
"Discover and join groups" = "Открийте и се присъединете към групи";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Discover via local network" = "Открий през локалната мрежа";
|
||||
"Discover via local network" = "Откриване през локалната мрежа";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Do it later" = "Отложи";
|
||||
@@ -1314,9 +1386,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Downgrade and open chat" = "Понижи версията и отвори чата";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Download failed" = "Неуспешно изтегляне";
|
||||
|
||||
/* server test step */
|
||||
"Download file" = "Свали файл";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Downloading archive" = "Архива се изтегля";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Downloading link details" = "Подробности за линка се изтеглят";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Duplicate display name!" = "Дублирано име!";
|
||||
|
||||
@@ -1350,6 +1431,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Enable for all" = "Активиране за всички";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enable in direct chats (BETA)!" = "Активиране в личните чатове (БЕТА)!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enable instant notifications?" = "Активирай незабавни известия?";
|
||||
|
||||
@@ -1464,6 +1548,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Enter Passcode" = "Въведете kодa за достъп";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enter passphrase" = "Въведи парола";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enter passphrase…" = "Въведи парола…";
|
||||
|
||||
@@ -1503,6 +1590,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error adding member(s)" = "Грешка при добавяне на член(ове)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error allowing contact PQ encryption" = "Грешка при разрешаване на PQ криптиране за контакт";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error changing address" = "Грешка при промяна на адреса";
|
||||
|
||||
@@ -1524,6 +1614,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error creating member contact" = "Грешка при създаване на контакт с член";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error creating message" = "Грешка при създаване на съобщение";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error creating profile!" = "Грешка при създаване на профил!";
|
||||
|
||||
@@ -1554,6 +1647,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error deleting user profile" = "Грешка при изтриване на потребителския профил";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error downloading the archive" = "Грешка при изтеглянето на архива";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error enabling delivery receipts!" = "Грешка при активирането на потвърждениeто за доставка!";
|
||||
|
||||
@@ -1599,6 +1695,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error saving passphrase to keychain" = "Грешка при запазване на парола в Кeychain";
|
||||
|
||||
/* when migrating */
|
||||
"Error saving settings" = "Грешка при запазване на настройките";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error saving user password" = "Грешка при запазване на потребителска парола";
|
||||
|
||||
@@ -1641,6 +1740,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error updating user privacy" = "Грешка при актуализиране на поверителността на потребителя";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error uploading the archive" = "Грешка при качването на архива";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error verifying passphrase:" = "Грешка при проверката на паролата:";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error: " = "Грешка: ";
|
||||
|
||||
@@ -1674,6 +1779,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Exported database archive." = "Експортиран архив на базата данни.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Exported file doesn't exist" = "Експортираният файл не съществува";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Exporting database archive…" = "Експортиране на архив на базата данни…";
|
||||
|
||||
@@ -1716,6 +1824,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Filter unread and favorite chats." = "Филтрирайте непрочетените и любимите чатове.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finalize migration" = "Завърши миграцията";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finalize migration on another device." = "Завършете миграцията на другото устройство.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finally, we have them! 🚀" = "Най-накрая ги имаме! 🚀";
|
||||
|
||||
@@ -1899,6 +2013,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"How to use your servers" = "Как да използвате вашите сървъри";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Hungarian interface" = "Унгарски интерфейс";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"ICE servers (one per line)" = "ICE сървъри (по един на ред)";
|
||||
|
||||
@@ -1938,12 +2055,24 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Import database" = "Импортиране на база данни";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Import failed" = "Неуспешно импортиране";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Importing archive" = "Импортиране на архив";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved message delivery" = "Подобрена доставка на съобщения";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved privacy and security" = "Подобрена поверителност и сигурност";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved server configuration" = "Подобрена конфигурация на сървъра";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In order to continue, chat should be stopped." = "За да продължите, чатът трябва да бъде спрян.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In reply to" = "В отговор на";
|
||||
|
||||
@@ -2028,6 +2157,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid link" = "Невалиден линк";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid migration confirmation" = "Невалидно потвърждение за мигриране";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid name!" = "Невалидно име!";
|
||||
|
||||
@@ -2115,6 +2247,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Join group" = "Влез в групата";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Join group conversations" = "Присъединяване към групи";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Join group?" = "Влез в групата?";
|
||||
|
||||
@@ -2250,6 +2385,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Member" = "Член";
|
||||
|
||||
/* profile update event chat item */
|
||||
"member %@ changed to %@" = "името на члена %1$@ е променено на %2$@";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"member connected" = "свързан";
|
||||
|
||||
@@ -2286,6 +2424,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Message text" = "Текст на съобщението";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Message too large" = "Съобщението е твърде голямо";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Messages" = "Съобщения";
|
||||
|
||||
@@ -2295,9 +2436,30 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Messages from %@ will be shown!" = "Съобщенията от %@ ще бъдат показани!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate device" = "Мигрирай устройството";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate from another device" = "Мигриране от друго устройство";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate here" = "Мигрирай тук";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate to another device" = "Миграция към друго устройство";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate to another device via QR code." = "Мигрирайте към друго устройство чрез QR код.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrating" = "Мигриране";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrating database archive…" = "Архивът на базата данни се мигрира…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migration complete" = "Миграцията е завършена";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migration error:" = "Грешка при мигриране:";
|
||||
|
||||
@@ -2328,7 +2490,7 @@
|
||||
/* copied message info */
|
||||
"Moderated at: %@" = "Модерирано в: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
/* marked deleted chat item preview text */
|
||||
"moderated by %@" = "модерирано от %@";
|
||||
|
||||
/* time unit */
|
||||
@@ -2555,6 +2717,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Open group" = "Отвори група";
|
||||
|
||||
/* authentication reason */
|
||||
"Open migration to another device" = "Отвори миграцията към друго устройство";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Open Settings" = "Отвори настройки";
|
||||
|
||||
@@ -2567,9 +2732,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Opening app…" = "Приложението се отваря…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or paste archive link" = "Или постави архивен линк";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or scan QR code" = "Или сканирай QR код";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or securely share this file link" = "Или сигурно споделете този линк към файла";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or show this code" = "Или покажи този код";
|
||||
|
||||
@@ -2594,12 +2765,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Password to show" = "Парола за показване";
|
||||
|
||||
/* past/unknown group member */
|
||||
"Past member %@" = "Бивш член %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Paste desktop address" = "Постави адрес на настолно устройство";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Paste image" = "Постави изображение";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Paste link to connect!" = "Поставете линк, за да се свържете!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Paste the link you received" = "Постави получения линк";
|
||||
|
||||
@@ -2615,6 +2792,9 @@
|
||||
/* message decrypt error item */
|
||||
"Permanent decryption error" = "Постоянна грешка при декриптиране";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Picture-in-picture calls" = "Обаждания \"картина в картина\"";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"PING count" = "PING бройка";
|
||||
|
||||
@@ -2633,6 +2813,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Please check yours and your contact preferences." = "Моля, проверете вашите настройки и тези вашия за контакт.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please confirm that network settings are correct for this device." = "Моля, потвърдете, че мрежовите настройки са правилни за това устройство.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please contact developers.\nError: %@" = "Моля, свържете се с разработчиците.\nГрешка: %@";
|
||||
|
||||
@@ -2666,6 +2849,9 @@
|
||||
/* server test error */
|
||||
"Possibly, certificate fingerprint in server address is incorrect" = "Въжможно е пръстовият отпечатък на сертификата в адреса на сървъра да е неправилен";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Post-quantum E2EE" = "Постквантово E2EE";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Preserve the last message draft, with attachments." = "Запазете последната чернова на съобщението с прикачени файлове.";
|
||||
|
||||
@@ -2687,6 +2873,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Private filenames" = "Поверителни имена на файлове";
|
||||
|
||||
/* name of notes to self */
|
||||
"Private notes" = "Лични бележки";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Profile and server connections" = "Профилни и сървърни връзки";
|
||||
|
||||
@@ -2744,6 +2933,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Push notifications" = "Push известия";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Push server" = "Push сървър";
|
||||
|
||||
/* chat item text */
|
||||
"quantum resistant e2e encryption" = "квантово устойчиво e2e криптиране";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Quantum resistant encryption" = "Квантово устойчиво криптиране";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Rate the app" = "Оценете приложението";
|
||||
|
||||
@@ -2801,6 +2999,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Receiving via" = "Получаване чрез";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Recent history and improved [directory bot](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion)." = "Скорошна история и подобрен [bot за директория за групи](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPd jdLW3%23%2F%3Fv%3D1-2% 26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Recipients see updates as you type them." = "Получателите виждат актуализации, докато ги въвеждате.";
|
||||
|
||||
@@ -2855,6 +3056,12 @@
|
||||
/* rcv group event chat item */
|
||||
"removed %@" = "отстранен %@";
|
||||
|
||||
/* profile update event chat item */
|
||||
"removed contact address" = "премахнат адрес за контакт";
|
||||
|
||||
/* profile update event chat item */
|
||||
"removed profile picture" = "премахната профилна снимка";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"removed you" = "ви острани";
|
||||
|
||||
@@ -2870,9 +3077,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat connection request?" = "Изпрати отново заявката за свързване?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat download" = "Повтори изтеглянето";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat import" = "Повтори импортирането";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat join request?" = "Изпрати отново заявката за присъединяване?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat upload" = "Повтори качването";
|
||||
|
||||
/* chat item action */
|
||||
"Reply" = "Отговори";
|
||||
|
||||
@@ -2930,6 +3146,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Run chat" = "Стартиране на чат";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Safer groups" = "По-безопасни групи";
|
||||
|
||||
/* chat item action */
|
||||
"Save" = "Запази";
|
||||
|
||||
@@ -2978,6 +3197,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Save welcome message?" = "Запази съобщението при посрещане?";
|
||||
|
||||
/* message info title */
|
||||
"Saved message" = "Запазено съобщение";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Saved WebRTC ICE servers will be removed" = "Запазените WebRTC ICE сървъри ще бъдат премахнати";
|
||||
|
||||
@@ -2999,6 +3221,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Search" = "Търсене";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Search bar accepts invitation links." = "Лентата за търсене приема линк за връзка.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Search or paste SimpleX link" = "Търсене или поставяне на SimpleX линк";
|
||||
|
||||
@@ -3155,9 +3380,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Set it instead of system authentication." = "Задайте го вместо системната идентификация.";
|
||||
|
||||
/* profile update event chat item */
|
||||
"set new contact address" = "зададен нов адрес за контакт";
|
||||
|
||||
/* profile update event chat item */
|
||||
"set new profile picture" = "зададена нова профилна снимка";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passcode" = "Задай kод за достъп";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passphrase" = "Задаване на парола";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passphrase to export" = "Задай парола за експортиране";
|
||||
|
||||
@@ -3203,6 +3437,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Show preview" = "Показване на визуализация";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show QR code" = "Покажи QR код";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show:" = "Покажи:";
|
||||
|
||||
@@ -3263,6 +3500,9 @@
|
||||
/* notification title */
|
||||
"Somebody" = "Някой";
|
||||
|
||||
/* chat item text */
|
||||
"standard end-to-end encryption" = "стандартно криптиране от край до край";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Start chat" = "Започни чат";
|
||||
|
||||
@@ -3278,6 +3518,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Stop" = "Спри";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stop chat" = "Спри чата";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stop chat to enable database actions" = "Спрете чата, за да активирате действията с базата данни";
|
||||
|
||||
@@ -3305,6 +3548,9 @@
|
||||
/* authentication reason */
|
||||
"Stop SimpleX" = "Спри SimpleX";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stopping chat" = "Спиране на чата";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"strike" = "зачеркнат";
|
||||
|
||||
@@ -3455,6 +3701,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost." = "Това действие не може да бъде отменено - вашият профил, контакти, съобщения и файлове ще бъдат безвъзвратно загубени.";
|
||||
|
||||
/* E2EE info chat item */
|
||||
"This chat is protected by end-to-end encryption." = "Този чат е защитен чрез криптиране от край до край.";
|
||||
|
||||
/* E2EE info chat item */
|
||||
"This chat is protected by quantum resistant end-to-end encryption." = "Този чат е защитен от квантово устойчиво криптиране от край до край.";
|
||||
|
||||
/* notification title */
|
||||
"this contact" = "този контакт";
|
||||
|
||||
@@ -3524,6 +3776,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Trying to connect to the server used to receive messages from this contact." = "Опит за свързване със сървъра, използван за получаване на съобщения от този контакт.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Turkish interface" = "Турски интерфейс";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Turn off" = "Изключи";
|
||||
|
||||
@@ -3536,12 +3791,21 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock" = "Отблокирай";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock for all" = "Отблокирай за всички";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member" = "Отблокирай член";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member for all?" = "Отблокиране на член за всички?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member?" = "Отблокирай член?";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"unblocked %@" = "отблокиран %@";
|
||||
|
||||
/* item status description */
|
||||
"Unexpected error: %@" = "Неочаквана грешка: %@";
|
||||
|
||||
@@ -3575,6 +3839,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Unknown error" = "Непозната грешка";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"unknown status" = "неизвестен статус";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." = "Освен ако не използвате интерфейса за повикване на iOS, активирайте режима \"Не безпокой\", за да избегнете прекъсвания.";
|
||||
|
||||
@@ -3620,6 +3887,9 @@
|
||||
/* rcv group event chat item */
|
||||
"updated group profile" = "актуализиран профил на групата";
|
||||
|
||||
/* profile update event chat item */
|
||||
"updated profile" = "актуализиран профил";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Updating settings will re-connect the client to all servers." = "Актуализирането на настройките ще свърже отново клиента към всички сървъри.";
|
||||
|
||||
@@ -3629,9 +3899,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Upgrade and open chat" = "Актуализирай и отвори чата";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Upload failed" = "Неуспешно качване";
|
||||
|
||||
/* server test step */
|
||||
"Upload file" = "Качи файл";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Uploading archive" = "Архивът се качва";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use .onion hosts" = "Използвай .onion хостове";
|
||||
|
||||
@@ -3662,6 +3938,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Use SimpleX Chat servers?" = "Използвай сървърите на SimpleX Chat?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use the app while in the call." = "Използвайте приложението по време на разговора.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"User profile" = "Потребителски профил";
|
||||
|
||||
@@ -3678,19 +3957,25 @@
|
||||
"v%@ (%@)" = "v%@ (%@)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify code with desktop" = "Потвръди кода с настолното устройство";
|
||||
"Verify code with desktop" = "Потвърди кода с настолното устройство";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify connection" = "Потвръди връзките";
|
||||
"Verify connection" = "Потвърди връзка";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify connection security" = "Потвръди сигурността на връзката";
|
||||
"Verify connection security" = "Потвърди сигурността на връзката";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify connections" = "Потвръди връзките";
|
||||
"Verify connections" = "Потвърждение за свързване";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify security code" = "Потвръди кода за сигурност";
|
||||
"Verify database passphrase" = "Проверете паролата на базата данни";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify passphrase" = "Провери паролата";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify security code" = "Потвърди кода за сигурност";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Via browser" = "Чрез браузър";
|
||||
@@ -3767,6 +4052,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"wants to connect to you!" = "иска да се свърже с вас!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Warning: starting chat on multiple devices is not supported and will cause message delivery failures" = "Внимание: стартирането на чата на множество устройства не се поддържа и ще доведе до неуспешно изпращане на съобщения";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Warning: you may lose some data!" = "Предупреждение: Може да загубите някои данни!";
|
||||
|
||||
@@ -3782,6 +4070,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Welcome message" = "Съобщение при посрещане";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Welcome message is too long" = "Съобщението при посрещане е твърде дълго";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"What's new" = "Какво е новото";
|
||||
|
||||
@@ -3794,9 +4085,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." = "Когато споделяте инкогнито профил с някого, този профил ще се използва за групите, в които той ви кани.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"With encrypted files and media." = "С криптирани файлове и медия.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"With optional welcome message." = "С незадължително съобщение при посрещане.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"With reduced battery usage." = "С намален разход на батерията.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Wrong database passphrase" = "Грешна парола за базата данни";
|
||||
|
||||
@@ -3857,6 +4154,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"you are observer" = "вие сте наблюдател";
|
||||
|
||||
/* snd group event chat item */
|
||||
"you blocked %@" = "вие блокирахте %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can accept calls from lock screen, without device and app authentication." = "Можете да приемате обаждания от заключен екран, без идентификация на устройство и приложението.";
|
||||
|
||||
@@ -3869,6 +4169,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"You can enable them later via app Privacy & Security settings." = "Можете да ги активирате по-късно през настройките за \"Поверителност и сигурност\" на приложението.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can give another try." = "Можете да опитате още веднъж.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can hide or mute a user profile - swipe it to the right." = "Можете да скриете или заглушите известията за потребителски профил - плъзнете надясно.";
|
||||
|
||||
@@ -3906,10 +4209,10 @@
|
||||
"You can't send messages!" = "Не може да изпращате съобщения!";
|
||||
|
||||
/* chat item text */
|
||||
"you changed address" = "променихте адреса";
|
||||
"you changed address" = "адреса за получаване е променен";
|
||||
|
||||
/* chat item text */
|
||||
"you changed address for %@" = "променихте адреса за %@";
|
||||
"you changed address for %@" = "променихте адреса получаване за %@";
|
||||
|
||||
/* snd group event chat item */
|
||||
"you changed role for yourself to %@" = "променихте ролята си на %@";
|
||||
@@ -3968,6 +4271,9 @@
|
||||
/* chat list item description */
|
||||
"you shared one-time link incognito" = "споделихте еднократен инкогнито линк за връзка";
|
||||
|
||||
/* snd group event chat item */
|
||||
"you unblocked %@" = "вие отблокирахте %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You will be connected to group when the group host's device is online, please wait or check later!" = "Ще бъдете свързани с групата, когато устройството на домакина на групата е онлайн, моля, изчакайте или проверете по-късно!";
|
||||
|
||||
|
||||
@@ -2070,7 +2070,7 @@
|
||||
/* copied message info */
|
||||
"Moderated at: %@" = "Upraveno v: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
/* marked deleted chat item preview text */
|
||||
"moderated by %@" = "moderovaný %@";
|
||||
|
||||
/* time unit */
|
||||
|
||||
@@ -85,6 +85,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." = "**Beste Privatsphäre**: Es wird kein SimpleX-Chat-Benachrichtigungs-Server genutzt, Nachrichten werden in periodischen Abständen im Hintergrund geprüft (dies hängt davon ab, wie häufig Sie die App nutzen).";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." = "**Bitte beachten Sie**: Aus Sicherheitsgründen wird die Nachrichtenentschlüsselung Ihrer Verbindungen abgebrochen, wenn Sie die gleiche Datenbank auf zwei Geräten nutzen.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Please note**: you will NOT be able to recover or change passphrase if you lose it." = "**Bitte beachten Sie**: Das Passwort kann NICHT wiederhergestellt oder geändert werden, wenn Sie es vergessen haben oder verlieren.";
|
||||
|
||||
@@ -94,6 +97,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"**Warning**: Instant push notifications require passphrase saved in Keychain." = "**Warnung**: Sofortige Push-Benachrichtigungen erfordern die Eingabe eines Passworts, welches in Ihrem Schlüsselbund gespeichert ist.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Warning**: the archive will be removed." = "**Warnung**: Das Archiv wird gelöscht.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"*bold*" = "\\*fett*";
|
||||
|
||||
@@ -136,6 +142,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%@ connected" = "%@ wurde mit Ihnen verbunden";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%@ downloaded" = "%@ heruntergeladen";
|
||||
|
||||
/* notification title */
|
||||
"%@ is connected!" = "%@ ist mit Ihnen verbunden!";
|
||||
|
||||
@@ -148,6 +157,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%@ servers" = "%@-Server";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%@ uploaded" = "%@ hochgeladen";
|
||||
|
||||
/* notification title */
|
||||
"%@ wants to connect!" = "%@ will sich mit Ihnen verbinden!";
|
||||
|
||||
@@ -377,6 +389,9 @@
|
||||
/* member role */
|
||||
"admin" = "Admin";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Admins can block a member for all." = "Administratoren können ein Gruppenmitglied für Alle blockieren.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Admins can create the links to join groups." = "Administratoren können Links für den Beitritt zu Gruppen erzeugen.";
|
||||
|
||||
@@ -416,6 +431,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"All your contacts will remain connected. Profile update will be sent to your contacts." = "Alle Ihre Kontakte bleiben verbunden. Es wird eine Profilaktualisierung an Ihre Kontakte gesendet.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." = "Alle Ihre Kontakte, Unterhaltungen und Dateien werden sicher verschlüsselt und in Daten-Paketen auf die konfigurierten XTFP-Server hochgeladen.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Allow" = "Erlauben";
|
||||
|
||||
@@ -497,6 +515,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"App build: %@" = "App Build: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"App data migration" = "App-Daten-Migration";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"App encrypts new local files (except videos)." = "Neue lokale Dateien (außer Video-Dateien) werden von der App verschlüsselt.";
|
||||
|
||||
@@ -518,6 +539,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Appearance" = "Erscheinungsbild";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Apply" = "Anwenden";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Archive and upload" = "Archivieren und Hochladen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Archiving database" = "Datenbank wird archiviert";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Attach" = "Anhängen";
|
||||
|
||||
@@ -602,13 +632,13 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Block member?" = "Mitglied blockieren?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
/* marked deleted chat item preview text */
|
||||
"blocked" = "Blockiert";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"blocked %@" = "%@ wurde blockiert";
|
||||
|
||||
/* blocked chat item */
|
||||
/* marked deleted chat item preview text */
|
||||
"blocked by admin" = "wurde vom Administrator blockiert";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
@@ -665,6 +695,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Cancel" = "Abbrechen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Cancel migration" = "Migration abbrechen";
|
||||
|
||||
/* feature offered item */
|
||||
"cancelled %@" = "abgebrochen %@";
|
||||
|
||||
@@ -744,6 +777,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat." = "Der Chat ist angehalten. Wenn Sie diese Datenbank bereits auf einem anderen Gerät genutzt haben, sollten Sie diese vor dem Starten des Chats wieder zurückspielen.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Chat migrated!" = "Chat wurde migriert!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Chat preferences" = "Chat-Präferenzen";
|
||||
|
||||
@@ -756,6 +792,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Chinese and Spanish interface" = "Chinesische und spanische Bedienoberfläche";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Choose _Migrate from another device_ on the new device and scan QR code." = "Wählen Sie auf dem neuen Gerät _Von einem anderen Gerät migrieren_ und scannen Sie den QR-Code.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Choose file" = "Datei auswählen";
|
||||
|
||||
@@ -801,6 +840,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm database upgrades" = "Datenbank-Aktualisierungen bestätigen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm network settings" = "Bestätigen Sie die Netzwerkeinstellungen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm new passphrase…" = "Neues Passwort bestätigen…";
|
||||
|
||||
@@ -810,6 +852,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm password" = "Passwort bestätigen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm that you remember database passphrase to migrate it." = "Bitte bestätigen Sie für die Migration, dass Sie sich an Ihr Datenbank-Passwort erinnern.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm upload" = "Hochladen bestätigen";
|
||||
|
||||
/* server test step */
|
||||
"Connect" = "Verbinden";
|
||||
|
||||
@@ -913,7 +961,7 @@
|
||||
"connection:%@" = "Verbindung:%@";
|
||||
|
||||
/* profile update event chat item */
|
||||
"contact %@ changed to %@" = "Der Kontaktname %1$@ wurde auf %2$@ geändert";
|
||||
"contact %@ changed to %@" = "Der Kontaktname wurde von %1$@ auf %2$@ geändert";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Contact allows" = "Der Kontakt erlaubt";
|
||||
@@ -1008,6 +1056,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Created on %@" = "Erstellt am %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Creating archive link" = "Archiv-Link erzeugen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Creating link…" = "Link wird erstellt…";
|
||||
|
||||
@@ -1155,6 +1206,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Delete database" = "Datenbank löschen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Delete database from this device" = "Datenbank auf diesem Gerät löschen";
|
||||
|
||||
/* server test step */
|
||||
"Delete file" = "Datei löschen";
|
||||
|
||||
@@ -1347,9 +1401,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Downgrade and open chat" = "Datenbank herabstufen und den Chat öffnen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Download failed" = "Herunterladen fehlgeschlagen";
|
||||
|
||||
/* server test step */
|
||||
"Download file" = "Datei herunterladen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Downloading archive" = "Archiv wird heruntergeladen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Downloading link details" = "Link-Details werden heruntergeladen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Duplicate display name!" = "Doppelter Anzeigename!";
|
||||
|
||||
@@ -1383,6 +1446,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Enable for all" = "Für Alle aktivieren";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enable in direct chats (BETA)!" = "Kann in direkten Chats aktiviert werden (BETA)!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enable instant notifications?" = "Sofortige Benachrichtigungen aktivieren?";
|
||||
|
||||
@@ -1497,6 +1563,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Enter Passcode" = "Zugangscode eingeben";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enter passphrase" = "Passwort eingeben";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enter passphrase…" = "Passwort eingeben…";
|
||||
|
||||
@@ -1536,6 +1605,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error adding member(s)" = "Fehler beim Hinzufügen von Mitgliedern";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error allowing contact PQ encryption" = "Fehler beim Zulassen der Kontakt-PQ-Verschlüsselung";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error changing address" = "Fehler beim Wechseln der Empfängeradresse";
|
||||
|
||||
@@ -1590,6 +1662,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error deleting user profile" = "Fehler beim Löschen des Benutzerprofils";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error downloading the archive" = "Fehler beim Herunterladen des Archivs";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error enabling delivery receipts!" = "Fehler beim Aktivieren von Empfangsbestätigungen!";
|
||||
|
||||
@@ -1635,6 +1710,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error saving passphrase to keychain" = "Fehler beim Speichern des Passworts in den Schlüsselbund";
|
||||
|
||||
/* when migrating */
|
||||
"Error saving settings" = "Fehler beim Abspeichern der Einstellungen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error saving user password" = "Fehler beim Speichern des Benutzer-Passworts";
|
||||
|
||||
@@ -1677,6 +1755,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error updating user privacy" = "Fehler beim Aktualisieren der Benutzer-Privatsphäre";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error uploading the archive" = "Fehler beim Hochladen des Archivs";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error verifying passphrase:" = "Fehler bei der Überprüfung des Passworts:";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error: " = "Fehler: ";
|
||||
|
||||
@@ -1710,6 +1794,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Exported database archive." = "Exportiertes Datenbankarchiv.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Exported file doesn't exist" = "Die exportierte Datei ist nicht vorhanden";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Exporting database archive…" = "Exportieren des Datenbank-Archivs…";
|
||||
|
||||
@@ -1752,6 +1839,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Filter unread and favorite chats." = "Nach ungelesenen und favorisierten Chats filtern.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finalize migration" = "Die Migration wird abgeschlossen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finalize migration on another device." = "Die Migration auf dem anderen Gerät wird abgeschlossen.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finally, we have them! 🚀" = "Endlich haben wir sie! 🚀";
|
||||
|
||||
@@ -1935,6 +2028,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"How to use your servers" = "Wie Sie Ihre Server nutzen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Hungarian interface" = "Ungarische Bedienoberfläche";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"ICE servers (one per line)" = "ICE-Server (einer pro Zeile)";
|
||||
|
||||
@@ -1974,6 +2070,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Import database" = "Datenbank importieren";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Import failed" = "Import ist fehlgeschlagen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Importing archive" = "Archiv wird importiert";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved message delivery" = "Verbesserte Zustellung von Nachrichten";
|
||||
|
||||
@@ -1983,6 +2085,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Improved server configuration" = "Verbesserte Serverkonfiguration";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In order to continue, chat should be stopped." = "Um fortzufahren, sollte der Chat beendet werden.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In reply to" = "Als Antwort auf";
|
||||
|
||||
@@ -2067,6 +2172,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid link" = "Ungültiger Link";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid migration confirmation" = "Migrations-Bestätigung ungültig";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid name!" = "Ungültiger Name!";
|
||||
|
||||
@@ -2293,7 +2401,7 @@
|
||||
"Member" = "Mitglied";
|
||||
|
||||
/* profile update event chat item */
|
||||
"member %@ changed to %@" = "Der Mitgliedsname %1$@ wurde auf %2$@ geändert";
|
||||
"member %@ changed to %@" = "Der Mitgliedsname von %1$@ wurde auf %2$@ geändert";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"member connected" = "ist der Gruppe beigetreten";
|
||||
@@ -2331,6 +2439,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Message text" = "Nachrichtentext";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Message too large" = "Die Nachricht ist zu lang";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Messages" = "Nachrichten";
|
||||
|
||||
@@ -2340,9 +2451,36 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Messages from %@ will be shown!" = "Die Nachrichten von %@ werden angezeigt!";
|
||||
|
||||
/* 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." = "Nachrichten, Dateien und Anrufe sind durch **Ende-zu-Ende-Verschlüsselung** mit Perfect Forward Secrecy, Ablehnung und Einbruchs-Wiederherstellung geschützt.";
|
||||
|
||||
/* 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." = "Nachrichten, Dateien und Anrufe sind durch **Quantum-resistente E2E-Verschlüsselung** mit Perfect Forward Secrecy, Ablehnung und Einbruchs-Wiederherstellung geschützt.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate device" = "Gerät migrieren";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate from another device" = "Von einem anderen Gerät migrieren";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate here" = "Hierher migrieren";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate to another device" = "Auf ein anderes Gerät migrieren";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate to another device via QR code." = "Daten können über einen QR-Code auf ein anderes Gerät migriert werden.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrating" = "Migrieren";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrating database archive…" = "Datenbank-Archiv wird migriert…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migration complete" = "Migration abgeschlossen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migration error:" = "Fehler bei der Migration:";
|
||||
|
||||
@@ -2373,7 +2511,7 @@
|
||||
/* copied message info */
|
||||
"Moderated at: %@" = "Moderiert um: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
/* marked deleted chat item preview text */
|
||||
"moderated by %@" = "Von %@ moderiert";
|
||||
|
||||
/* time unit */
|
||||
@@ -2600,6 +2738,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Open group" = "Gruppe ö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";
|
||||
|
||||
@@ -2612,9 +2753,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Opening app…" = "App wird geöffnet…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or paste archive link" = "Oder fügen Sie den Archiv-Link ein";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or scan QR code" = "Oder den QR-Code scannen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or securely share this file link" = "Oder teilen Sie diesen Datei-Link sicher";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or show this code" = "Oder diesen QR-Code anzeigen";
|
||||
|
||||
@@ -2666,6 +2813,9 @@
|
||||
/* message decrypt error item */
|
||||
"Permanent decryption error" = "Entschlüsselungsfehler";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Picture-in-picture calls" = "Bild-in-Bild-Anrufe";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"PING count" = "PING-Zähler";
|
||||
|
||||
@@ -2684,6 +2834,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Please check yours and your contact preferences." = "Bitte überprüfen sie sowohl Ihre, als auch die Präferenzen Ihres Kontakts.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please confirm that network settings are correct for this device." = "Bitte bestätigen Sie, dass die Netzwerkeinstellungen auf diesem Gerät richtig sind.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please contact developers.\nError: %@" = "Bitte nehmen Sie Kontakt mit den Entwicklern auf.\nFehler: %@";
|
||||
|
||||
@@ -2717,6 +2870,9 @@
|
||||
/* server test error */
|
||||
"Possibly, certificate fingerprint in server address is incorrect" = "Der Fingerabdruck des Zertifikats in der Serveradresse ist wahrscheinlich ungültig";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Post-quantum E2EE" = "Post-Quantum E2E-Verschlüsselung";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Preserve the last message draft, with attachments." = "Den letzten Nachrichtenentwurf, auch mit seinen Anhängen, aufbewahren.";
|
||||
|
||||
@@ -2798,6 +2954,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Push notifications" = "Push-Benachrichtigungen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Push server" = "Push-Server";
|
||||
|
||||
/* chat item text */
|
||||
"quantum resistant e2e encryption" = "Quantum-resistente E2E-Verschlüsselung";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Quantum resistant encryption" = "Quantum-resistente Verschlüsselung";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Rate the app" = "Bewerten Sie die App";
|
||||
|
||||
@@ -2913,10 +3078,10 @@
|
||||
"removed %@" = "hat %@ aus der Gruppe entfernt";
|
||||
|
||||
/* profile update event chat item */
|
||||
"removed contact address" = "Kontaktadresse wurde entfernt";
|
||||
"removed contact address" = "Die Kontaktadresse wurde entfernt";
|
||||
|
||||
/* profile update event chat item */
|
||||
"removed profile picture" = "Profil-Bild wurde entfernt";
|
||||
"removed profile picture" = "Das Profil-Bild wurde entfernt";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"removed you" = "hat Sie aus der Gruppe entfernt";
|
||||
@@ -2933,9 +3098,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat connection request?" = "Verbindungsanfrage wiederholen?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat download" = "Herunterladen wiederholen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat import" = "Import wiederholen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat join request?" = "Verbindungsanfrage wiederholen?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat upload" = "Hochladen wiederholen";
|
||||
|
||||
/* chat item action */
|
||||
"Reply" = "Antwort";
|
||||
|
||||
@@ -2993,6 +3167,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Run chat" = "Chat starten";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Safer groups" = "Sicherere Gruppen";
|
||||
|
||||
/* chat item action */
|
||||
"Save" = "Speichern";
|
||||
|
||||
@@ -3066,7 +3243,7 @@
|
||||
"Search" = "Suche";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Search bar accepts invitation links." = "Von der Suchleiste werden Einladungslinks akzeptiert.";
|
||||
"Search bar accepts invitation links." = "In der Suchleiste werden nun auch Einladungslinks akzeptiert.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Search or paste SimpleX link" = "Suchen oder fügen Sie den SimpleX-Link ein";
|
||||
@@ -3225,14 +3402,17 @@
|
||||
"Set it instead of system authentication." = "Anstelle der System-Authentifizierung festlegen.";
|
||||
|
||||
/* profile update event chat item */
|
||||
"set new contact address" = "Neue Kontaktadresse wurde festgelegt";
|
||||
"set new contact address" = "Es wurde eine neue Kontaktadresse festgelegt";
|
||||
|
||||
/* profile update event chat item */
|
||||
"set new profile picture" = "Neues Profil-Bild wurde festgelegt";
|
||||
"set new profile picture" = "Es wurde ein neues Profil-Bild festgelegt";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passcode" = "Zugangscode einstellen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passphrase" = "Passwort festlegen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passphrase to export" = "Passwort für den Export festlegen";
|
||||
|
||||
@@ -3278,6 +3458,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Show preview" = "Vorschau anzeigen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show QR code" = "QR-Code anzeigen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show:" = "Anzeigen:";
|
||||
|
||||
@@ -3338,6 +3521,9 @@
|
||||
/* notification title */
|
||||
"Somebody" = "Jemand";
|
||||
|
||||
/* chat item text */
|
||||
"standard end-to-end encryption" = "Standard-Ende-zu-Ende-Verschlüsselung";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Start chat" = "Starten Sie den Chat";
|
||||
|
||||
@@ -3353,6 +3539,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Stop" = "Beenden";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stop chat" = "Chat beenden";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stop chat to enable database actions" = "Chat beenden, um Datenbankaktionen zu erlauben";
|
||||
|
||||
@@ -3380,6 +3569,9 @@
|
||||
/* authentication reason */
|
||||
"Stop SimpleX" = "Stoppen Sie SimpleX";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stopping chat" = "Chat wird beendet";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"strike" = "durchstreichen";
|
||||
|
||||
@@ -3530,6 +3722,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost." = "Diese Aktion kann nicht rückgängig gemacht werden! Ihr Profil und Ihre Kontakte, Nachrichten und Dateien gehen unwiderruflich verloren.";
|
||||
|
||||
/* E2EE info chat item */
|
||||
"This chat is protected by end-to-end encryption." = "Dieser Chat ist durch Ende-zu-Ende-Verschlüsselung geschützt.";
|
||||
|
||||
/* E2EE info chat item */
|
||||
"This chat is protected by quantum resistant end-to-end encryption." = "Dieser Chat ist durch Quantum-resistente Ende-zu-Ende-Verschlüsselung geschützt.";
|
||||
|
||||
/* notification title */
|
||||
"this contact" = "Dieser Kontakt";
|
||||
|
||||
@@ -3555,7 +3753,7 @@
|
||||
"This setting applies to messages in your current chat profile **%@**." = "Diese Einstellung gilt für Nachrichten in Ihrem aktuellen Chat-Profil **%@**.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"To ask any questions and to receive updates:" = "Um Fragen zu stellen und Aktualisierungen zu erhalten:";
|
||||
"To ask any questions and to receive updates:" = "Um Fragen zu stellen und aktuelle Informationen zu erhalten:";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"To connect, your contact can scan QR code or use the link in the app." = "Um eine Verbindung herzustellen, kann Ihr Kontakt den QR-Code scannen oder den Link in der App verwenden.";
|
||||
@@ -3722,9 +3920,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Upgrade and open chat" = "Aktualisieren und den Chat öffnen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Upload failed" = "Hochladen fehlgeschlagen";
|
||||
|
||||
/* server test step */
|
||||
"Upload file" = "Datei hochladen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Uploading archive" = "Archiv wird hochgeladen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use .onion hosts" = "Verwende .onion-Hosts";
|
||||
|
||||
@@ -3755,6 +3959,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Use SimpleX Chat servers?" = "Verwenden Sie SimpleX-Chat-Server?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use the app while in the call." = "Die App kann während eines Anrufs genutzt werden.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"User profile" = "Benutzerprofil";
|
||||
|
||||
@@ -3782,6 +3989,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Verify connections" = "Verbindungen überprüfen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify database passphrase" = "Überprüfen Sie das Datenbank-Passwort";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify passphrase" = "Überprüfen Sie das Passwort";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify security code" = "Sicherheitscode überprüfen";
|
||||
|
||||
@@ -3860,6 +4073,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"wants to connect to you!" = "möchte sich mit Ihnen verbinden!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Warning: starting chat on multiple devices is not supported and will cause message delivery failures" = "Warnung: Das Starten des Chats auf mehreren Geräten wird nicht unterstützt und wird zu Fehlern bei der Nachrichtenübermittlung führen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Warning: you may lose some data!" = "Warnung: Sie könnten einige Daten verlieren!";
|
||||
|
||||
@@ -3875,6 +4091,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Welcome message" = "Begrüßungsmeldung";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Welcome message is too long" = "Die Begrüßungsmeldung ist zu lang";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"What's new" = "Was ist neu";
|
||||
|
||||
@@ -3911,6 +4130,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"You" = "Profil";
|
||||
|
||||
/* 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.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You accepted connection" = "Sie haben die Verbindung akzeptiert";
|
||||
|
||||
@@ -3971,6 +4193,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"You can enable them later via app Privacy & Security settings." = "Sie können diese später in den Datenschutz & Sicherheits-Einstellungen der App aktivieren.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can give another try." = "Sie können es nochmal probieren.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can hide or mute a user profile - swipe it to the right." = "Sie können ein Benutzerprofil verbergen oder stummschalten - wischen Sie es nach rechts.";
|
||||
|
||||
@@ -4134,7 +4359,7 @@
|
||||
"Your contacts can allow full message deletion." = "Ihre Kontakte können die unwiederbringliche Löschung von Nachrichten erlauben.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Your contacts will remain connected." = "Ihre Kontakte bleiben verbunden.";
|
||||
"Your contacts will remain connected." = "Ihre Kontakte bleiben weiterhin verbunden.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Your current chat database will be DELETED and REPLACED with the imported one." = "Ihre aktuelle Chat-Datenbank wird GELÖSCHT und durch die Importierte ERSETZT.";
|
||||
|
||||
@@ -85,6 +85,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." = "**Más privado**: no se usa el servidor de notificaciones de SimpleX Chat, los mensajes se comprueban periódicamente en segundo plano (dependiendo de la frecuencia con la que utilices la aplicación).";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." = "**Tenga en cuenta**: usar la misma base de datos en dos dispositivos interrumpirá el descifrado de mensajes de sus conexiones, como protección de seguridad.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Please note**: you will NOT be able to recover or change passphrase if you lose it." = "**Atención**: NO podrás recuperar o cambiar la contraseña si la pierdes.";
|
||||
|
||||
@@ -94,6 +97,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"**Warning**: Instant push notifications require passphrase saved in Keychain." = "**Advertencia**: Las notificaciones automáticas instantáneas requieren una contraseña guardada en Keychain.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Warning**: the archive will be removed." = "**Atención**: el archivo será eliminado.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"*bold*" = "\\*bold*";
|
||||
|
||||
@@ -136,6 +142,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%@ connected" = "%@ conectado";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%@ downloaded" = "%@ downloaded";
|
||||
|
||||
/* notification title */
|
||||
"%@ is connected!" = "%@ ¡está conectado!";
|
||||
|
||||
@@ -148,6 +157,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%@ servers" = "Servidores %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%@ uploaded" = "%@ cargado";
|
||||
|
||||
/* notification title */
|
||||
"%@ wants to connect!" = "¡ %@ quiere contactar!";
|
||||
|
||||
@@ -202,6 +214,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages blocked" = "%lld mensaje(s) bloqueado(s)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages blocked by admin" = "%lld mensajes bloqueados por el administrador";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages marked deleted" = "%lld mensaje(s) marcado(s) eliminado(s)";
|
||||
|
||||
@@ -374,6 +389,9 @@
|
||||
/* member role */
|
||||
"admin" = "administrador";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Admins can block a member for all." = "Los admins pueden bloquear un miembro por todos.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Admins can create the links to join groups." = "Los administradores pueden crear enlaces para unirse a grupos.";
|
||||
|
||||
@@ -398,6 +416,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"All group members will remain connected." = "Todos los miembros del grupo permanecerán conectados.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All messages will be deleted - this cannot be undone!" = "Todos los mensajes serán borrados. ¡No podrá deshacerse!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All messages will be deleted - this cannot be undone! The messages will be deleted ONLY for you." = "Se eliminarán todos los mensajes SOLO para tí. ¡No podrá deshacerse!";
|
||||
|
||||
@@ -410,6 +431,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"All your contacts will remain connected. Profile update will be sent to your contacts." = "Todos tus contactos permanecerán conectados. La actualización del perfil se enviará a tus contactos.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." = "Todos sus contactos, conversaciones y archivos se cifrarán de forma segura y se subirán en fragmentos hacia puntos XFTP configurados.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Allow" = "Se permite";
|
||||
|
||||
@@ -491,6 +515,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"App build: %@" = "Compilación app: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"App data migration" = "Migración de datos de la aplicación";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"App encrypts new local files (except videos)." = "Cifrado de los nuevos archivos locales (excepto vídeos).";
|
||||
|
||||
@@ -512,6 +539,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Appearance" = "Apariencia";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Apply" = "Aplicar";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Archive and upload" = "Archivar y transferir";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Archiving database" = "Archivando base de datos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Attach" = "Adjuntar";
|
||||
|
||||
@@ -581,6 +617,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Block" = "Bloquear";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block for all" = "Bloquear para todos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block group members" = "Bloquear miembros del grupo";
|
||||
|
||||
@@ -588,11 +627,23 @@
|
||||
"Block member" = "Bloquear miembro";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block member?" = "¿Bloquear miembro?";
|
||||
"Block member for all?" = "¿Bloqear miembro para todos?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block member?" = "¿Bloquear miembro?";
|
||||
|
||||
/* marked deleted chat item preview text */
|
||||
"blocked" = "bloqueado";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"blocked %@" = "%@ bloqueado";
|
||||
|
||||
/* marked deleted chat item preview text */
|
||||
"blocked by admin" = "bloqueado por el administrador";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Blocked by admin" = "Bloqueado por el administrador";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"bold" = "negrita";
|
||||
|
||||
@@ -644,6 +695,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Cancel" = "Cancelar";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Cancel migration" = "Cancelar migración";
|
||||
|
||||
/* feature offered item */
|
||||
"cancelled %@" = "cancelado %@";
|
||||
|
||||
@@ -723,6 +777,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat." = "Chat está detenido. Si estás usando esta base de datos en otro dispositivo, deberías transferirla de vuelta antes de iniciarlo.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Chat migrated!" = "Chat transferido !";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Chat preferences" = "Preferencias de Chat";
|
||||
|
||||
@@ -735,6 +792,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Chinese and Spanish interface" = "Interfaz en chino y español";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Choose _Migrate from another device_ on the new device and scan QR code." = "Elija _Migrar desde otro dispositivo_ en el nuevo dispositivo y escanee el código QR.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Choose file" = "Elije archivo";
|
||||
|
||||
@@ -750,6 +810,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Clear conversation?" = "¿Vaciar conversación?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Clear private notes?" = "¿Borrar notas privadas?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Clear verification" = "Eliminar verificación";
|
||||
|
||||
@@ -777,6 +840,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm database upgrades" = "Confirmar actualizaciones de la bases de datos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm network settings" = "Confirmar los ajustes de red";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm new passphrase…" = "Confirme nueva contraseña…";
|
||||
|
||||
@@ -786,6 +852,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm password" = "Confirmar contraseña";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm that you remember database passphrase to migrate it." = "Confirme que recuerda la frase secreta de la base de datos para migrarla.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm upload" = "Confirmar subida";
|
||||
|
||||
/* server test step */
|
||||
"Connect" = "Conectar";
|
||||
|
||||
@@ -888,6 +960,9 @@
|
||||
/* connection information */
|
||||
"connection:%@" = "conexión: % @";
|
||||
|
||||
/* profile update event chat item */
|
||||
"contact %@ changed to %@" = "el contacto %1$@ ha cambiado a %2$@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Contact allows" = "El contacto permite";
|
||||
|
||||
@@ -972,9 +1047,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Create your profile" = "Crea tu perfil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Created at" = "Creado";
|
||||
|
||||
/* copied message info */
|
||||
"Created at: %@" = "Creado: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Created on %@" = "Creado en %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Creating archive link" = "Creando enlace de archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Creating link…" = "Creando enlace…";
|
||||
|
||||
@@ -1122,6 +1206,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Delete database" = "Eliminar base de datos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Delete database from this device" = "Eliminar base de datos de este dispositivo";
|
||||
|
||||
/* server test step */
|
||||
"Delete file" = "Eliminar archivo";
|
||||
|
||||
@@ -1296,6 +1383,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Do it later" = "Hacer más tarde";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Do not send history to new members." = "No enviar historial a miembros nuevos.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Do NOT use SimpleX for emergency calls." = "NO uses SimpleX para llamadas de emergencia.";
|
||||
|
||||
@@ -1311,9 +1401,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Downgrade and open chat" = "Degradar y abrir Chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Download failed" = "Error en la descarga";
|
||||
|
||||
/* server test step */
|
||||
"Download file" = "Descargar archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Downloading archive" = "Descargando archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Downloading link details" = "Descargando detalles del enlace";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Duplicate display name!" = "¡Nombre mostrado duplicado!";
|
||||
|
||||
@@ -1347,6 +1446,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Enable for all" = "Activar para todos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enable in direct chats (BETA)!" = "Activar en chats directos (BETA)!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enable instant notifications?" = "¿Activar notificación instantánea?";
|
||||
|
||||
@@ -1461,6 +1563,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Enter Passcode" = "Introduce Código";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enter passphrase" = "Introducir frase de contraseña";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enter passphrase…" = "Introduce la contraseña…";
|
||||
|
||||
@@ -1500,6 +1605,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error adding member(s)" = "Error al añadir miembro(s)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error allowing contact PQ encryption" = "Error al permitir cifrado PQ al contacto";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error changing address" = "Error al cambiar servidor";
|
||||
|
||||
@@ -1521,6 +1629,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error creating member contact" = "Error al establecer contacto con el miembro";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error creating message" = "Error al crear mensaje";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error creating profile!" = "¡Error al crear perfil!";
|
||||
|
||||
@@ -1551,6 +1662,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error deleting user profile" = "Error al eliminar perfil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error downloading the archive" = "Error al descargar el archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error enabling delivery receipts!" = "¡Error al activar confirmaciones de entrega!";
|
||||
|
||||
@@ -1596,6 +1710,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error saving passphrase to keychain" = "Error al guardar contraseña en Keychain";
|
||||
|
||||
/* when migrating */
|
||||
"Error saving settings" = "Error al guardar ajustes";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error saving user password" = "Error al guardar contraseña de usuario";
|
||||
|
||||
@@ -1638,6 +1755,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error updating user privacy" = "Error al actualizar privacidad de usuario";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error uploading the archive" = "Error al subir el archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error verifying passphrase:" = "Error al verificar la frase de contraseña:";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error: " = "Error: ";
|
||||
|
||||
@@ -1671,6 +1794,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Exported database archive." = "Archivo de base de datos exportado.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Exported file doesn't exist" = "El archivo exportado no existe";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Exporting database archive…" = "Exportando base de datos…";
|
||||
|
||||
@@ -1713,6 +1839,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Filter unread and favorite chats." = "Filtra chats no leídos y favoritos.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finalize migration" = "Finalizar la migración";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finalize migration on another device." = "Finalizar la migración en otro dispositivo.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finally, we have them! 🚀" = "¡Por fin los tenemos! 🚀";
|
||||
|
||||
@@ -1875,6 +2007,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"History" = "Historial";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"History is not sent to new members." = "El historial no se envía a miembros nuevos.";
|
||||
|
||||
/* time unit */
|
||||
"hours" = "horas";
|
||||
|
||||
@@ -1893,6 +2028,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"How to use your servers" = "Cómo usar los servidores";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Hungarian interface" = "Interfaz húngara";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"ICE servers (one per line)" = "Servidores ICE (uno por línea)";
|
||||
|
||||
@@ -1932,12 +2070,24 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Import database" = "Importar base de datos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Import failed" = "Error de importación";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Importing archive" = "Importando archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved message delivery" = "Entrega de mensajes mejorada";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved privacy and security" = "Seguridad y privacidad mejoradas";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved server configuration" = "Configuración del servidor mejorada";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In order to continue, chat should be stopped." = "Para continuar, el chat debe ser interrumpido.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In reply to" = "En respuesta a";
|
||||
|
||||
@@ -2016,9 +2166,15 @@
|
||||
/* invalid chat item */
|
||||
"invalid data" = "datos no válidos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid display name!" = "¡Nombre mostrado no válido!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid link" = "Enlace no válido";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid migration confirmation" = "Confirmación de migración inválida";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid name!" = "¡Nombre no válido!";
|
||||
|
||||
@@ -2106,6 +2262,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Join group" = "Unirte al grupo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Join group conversations" = "Unirse a la conversación del grupo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Join group?" = "¿Unirte al grupo?";
|
||||
|
||||
@@ -2241,6 +2400,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Member" = "Miembro";
|
||||
|
||||
/* profile update event chat item */
|
||||
"member %@ changed to %@" = "el miembro %1$@ ha cambiado a %2$@";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"member connected" = "conectado";
|
||||
|
||||
@@ -2277,6 +2439,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Message text" = "Contacto y texto";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Message too large" = "Mensaje demasiado grande";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Messages" = "Mensajes";
|
||||
|
||||
@@ -2286,9 +2451,36 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Messages from %@ will be shown!" = "¡Los mensajes de %@ serán mostrados!";
|
||||
|
||||
/* 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." = "Los mensajes, archivos y llamadas están protegidos por **cifrado de extremo a extremo** con perfecta confidencialidad, repudio y recuperación tras ataques.";
|
||||
|
||||
/* 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." = "Los mensajes, archivos y llamadas están protegidos por **cifrado de extremo a extremo resistente a la computación cuántica** con perfecta confidencialidad, repudio y recuperación tras ataques.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate device" = "Migrar dispositivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate from another device" = "Migrar desde otro dispositivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate here" = "Migrar aquí";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate to another device" = "Migrar hacia otro dispositivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate to another device via QR code." = "Migrar hacia otro dispositivo mediante código QR.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrating" = "Migrando";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrating database archive…" = "Migrando base de datos…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migration complete" = "Migración completada";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migration error:" = "Error de migración:";
|
||||
|
||||
@@ -2319,7 +2511,7 @@
|
||||
/* copied message info */
|
||||
"Moderated at: %@" = "Moderado: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
/* marked deleted chat item preview text */
|
||||
"moderated by %@" = "moderado por %@";
|
||||
|
||||
/* time unit */
|
||||
@@ -2546,6 +2738,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Open group" = "Grupo abierto";
|
||||
|
||||
/* authentication reason */
|
||||
"Open migration to another device" = "Abrir la migración hacia otro dispositivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Open Settings" = "Abrir Configuración";
|
||||
|
||||
@@ -2558,9 +2753,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Opening app…" = "Iniciando aplicación…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or paste archive link" = "O pegar enlace del archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or scan QR code" = "O escanear código QR";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or securely share this file link" = "O comparta de forma segura el enlace de este archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or show this code" = "O mostrar este código";
|
||||
|
||||
@@ -2585,12 +2786,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Password to show" = "Contraseña para hacerlo visible";
|
||||
|
||||
/* past/unknown group member */
|
||||
"Past member %@" = "Miembro pasado %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Paste desktop address" = "Pegar dirección de ordenador";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Paste image" = "Pegar imagen";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Paste link to connect!" = "Pegar enlace para conectar!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Paste the link you received" = "Pegar el enlace recibido";
|
||||
|
||||
@@ -2606,6 +2813,9 @@
|
||||
/* message decrypt error item */
|
||||
"Permanent decryption error" = "Error permanente descifrado";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Picture-in-picture calls" = "Llamadas picture-in-picture";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"PING count" = "Contador PING";
|
||||
|
||||
@@ -2624,6 +2834,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Please check yours and your contact preferences." = "Comprueba tus preferencias y las de tu contacto.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please confirm that network settings are correct for this device." = "Por favor confirme que la configuración de red es correcta para este dispositivo.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please contact developers.\nError: %@" = "Por favor, contacta con los desarrolladores.\nError: %@";
|
||||
|
||||
@@ -2657,6 +2870,9 @@
|
||||
/* server test error */
|
||||
"Possibly, certificate fingerprint in server address is incorrect" = "Posiblemente la huella digital del certificado en la dirección del servidor es incorrecta";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Post-quantum E2EE" = "E2EE postcuántica";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Preserve the last message draft, with attachments." = "Conserva el último borrador del mensaje con los datos adjuntos.";
|
||||
|
||||
@@ -2678,6 +2894,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Private filenames" = "Nombres de archivos privados";
|
||||
|
||||
/* name of notes to self */
|
||||
"Private notes" = "Notas privadas";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Profile and server connections" = "Perfil y conexiones de servidor";
|
||||
|
||||
@@ -2735,6 +2954,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Push notifications" = "Notificaciones automáticas";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Push server" = "Servidor push";
|
||||
|
||||
/* chat item text */
|
||||
"quantum resistant e2e encryption" = "cifrado e2e resistente a la cuántica";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Quantum resistant encryption" = "Cifrado resistente a la tecnología cuántica";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Rate the app" = "Valora la aplicación";
|
||||
|
||||
@@ -2792,6 +3020,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Receiving via" = "Recibiendo vía";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Recent history and improved [directory bot](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion)." = "Historial reciente y [bot del directorio](simplex:/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion) mejorados.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Recipients see updates as you type them." = "Los destinatarios ven actualizarse mientras escribes.";
|
||||
|
||||
@@ -2846,6 +3077,12 @@
|
||||
/* rcv group event chat item */
|
||||
"removed %@" = "ha expulsado a %@";
|
||||
|
||||
/* profile update event chat item */
|
||||
"removed contact address" = "dirección de contacto eliminada";
|
||||
|
||||
/* profile update event chat item */
|
||||
"removed profile picture" = "imagen de perfil eliminada";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"removed you" = "te ha expulsado";
|
||||
|
||||
@@ -2861,9 +3098,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat connection request?" = "¿Repetir solicitud de conexión?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat download" = "Repetir descarga";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat import" = "Repetir importación";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat join request?" = "¿Repetir solicitud de admisión?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat upload" = "Repetir la carga";
|
||||
|
||||
/* chat item action */
|
||||
"Reply" = "Responder";
|
||||
|
||||
@@ -2921,6 +3167,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Run chat" = "Ejecutar chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Safer groups" = "Grupos más seguros";
|
||||
|
||||
/* chat item action */
|
||||
"Save" = "Guardar";
|
||||
|
||||
@@ -2969,6 +3218,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Save welcome message?" = "¿Guardar mensaje de bienvenida?";
|
||||
|
||||
/* message info title */
|
||||
"Saved message" = "Mensaje guardado";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Saved WebRTC ICE servers will be removed" = "Los servidores WebRTC ICE guardados serán eliminados";
|
||||
|
||||
@@ -2990,6 +3242,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Search" = "Buscar";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Search bar accepts invitation links." = "La barra de búsqueda acepta enlaces de invitación.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Search or paste SimpleX link" = "Buscar o pegar enlace SimpleX";
|
||||
|
||||
@@ -3071,6 +3326,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Send them from gallery or custom keyboards." = "Envíalos desde la galería o desde teclados personalizados.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Send up to 100 last messages to new members." = "Enviar hasta 100 últimos mensajes a los miembros nuevos.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Sender cancelled file transfer." = "El remitente ha cancelado la transferencia de archivos.";
|
||||
|
||||
@@ -3143,9 +3401,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Set it instead of system authentication." = "Úsalo en lugar de la autenticación del sistema.";
|
||||
|
||||
/* profile update event chat item */
|
||||
"set new contact address" = "nueva dirección de contacto";
|
||||
|
||||
/* profile update event chat item */
|
||||
"set new profile picture" = "nueva imagen de perfil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passcode" = "Código autodestrucción";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passphrase" = "Definir frase de contraseña";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passphrase to export" = "Escribe la contraseña para exportar";
|
||||
|
||||
@@ -3191,6 +3458,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Show preview" = "Mostrar vista previa";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show QR code" = "Mostrar código QR";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show:" = "Mostrar:";
|
||||
|
||||
@@ -3251,6 +3521,9 @@
|
||||
/* notification title */
|
||||
"Somebody" = "Alguien";
|
||||
|
||||
/* chat item text */
|
||||
"standard end-to-end encryption" = "cifrado estándar de extremo a extremo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Start chat" = "Iniciar chat";
|
||||
|
||||
@@ -3266,6 +3539,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Stop" = "Detener";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stop chat" = "Detener el chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stop chat to enable database actions" = "Detén SimpleX para habilitar las acciones sobre la base de datos";
|
||||
|
||||
@@ -3293,6 +3569,9 @@
|
||||
/* authentication reason */
|
||||
"Stop SimpleX" = "Detener SimpleX";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stopping chat" = "Detención del chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"strike" = "tachado";
|
||||
|
||||
@@ -3435,13 +3714,19 @@
|
||||
"They can be overridden in contact and group settings." = "Se pueden anular en la configuración de contactos.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This action cannot be undone - all received and sent files and media will be deleted. Low resolution pictures will remain." = "Esta acción no se puede deshacer. Se eliminarán todos los archivos y multimedia recibidos y enviados. Las imágenes de baja resolución permanecerán.";
|
||||
"This action cannot be undone - all received and sent files and media will be deleted. Low resolution pictures will remain." = "Esta acción es irreversible. Se eliminarán todos los archivos y multimedia recibidos y enviados. Las imágenes de baja resolución permanecerán.";
|
||||
|
||||
/* 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." = "Esta acción no se puede deshacer. Se eliminarán los mensajes enviados y recibidos anteriores a la selección. Puede tardar varios minutos.";
|
||||
"This action cannot be undone - the messages sent and received earlier than selected will be deleted. It may take several minutes." = "Esta acción es irreversible. Se eliminarán los mensajes enviados y recibidos anteriores a la selección. Puede tardar varios minutos.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost." = "Esta acción no se puede deshacer. Tu perfil, contactos, mensajes y archivos se perderán irreversiblemente.";
|
||||
"This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost." = "Esta acción es irreversible. Tu perfil, contactos, mensajes y archivos se perderán irreversiblemente.";
|
||||
|
||||
/* E2EE info chat item */
|
||||
"This chat is protected by end-to-end encryption." = "Este chat está protegido por cifrado de extremo a extremo.";
|
||||
|
||||
/* E2EE info chat item */
|
||||
"This chat is protected by quantum resistant end-to-end encryption." = "Este chat está protegido por un cifrado de extremo a extremo resistente a tecnologías cuánticas.";
|
||||
|
||||
/* notification title */
|
||||
"this contact" = "este contacto";
|
||||
@@ -3449,6 +3734,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"This device name" = "Nombre del dispositivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This display name is invalid. Please choose another name." = "Éste nombre mostrado no es válido. Por favor, elije otro nombre.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"This group has over %lld members, delivery receipts are not sent." = "Este grupo tiene más de %lld miembros, no se enviarán confirmaciones de entrega.";
|
||||
|
||||
@@ -3509,6 +3797,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Trying to connect to the server used to receive messages from this contact." = "Intentando conectar con el servidor usado para recibir mensajes de este contacto.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Turkish interface" = "Interfaz en turco";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Turn off" = "Desactivar";
|
||||
|
||||
@@ -3521,12 +3812,21 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock" = "Desbloquear";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock for all" = "Desbloquear para todos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member" = "Desbloquear miembro";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member for all?" = "¿Desbloquear miembro para todos?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member?" = "¿Desbloquear miembro?";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"unblocked %@" = "%@ desbloqueado";
|
||||
|
||||
/* item status description */
|
||||
"Unexpected error: %@" = "Error inesperado: %@";
|
||||
|
||||
@@ -3560,6 +3860,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Unknown error" = "Error desconocido";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"unknown status" = "estado desconocido";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions." = "A menos que utilices la interfaz de llamadas de iOS, activa el modo No molestar para evitar interrupciones.";
|
||||
|
||||
@@ -3584,6 +3887,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Unread" = "No leído";
|
||||
|
||||
/* 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.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Update" = "Actualizar";
|
||||
|
||||
@@ -3602,6 +3908,9 @@
|
||||
/* rcv group event chat item */
|
||||
"updated group profile" = "ha actualizado el perfil del grupo";
|
||||
|
||||
/* profile update event chat item */
|
||||
"updated profile" = "perfil actualizado";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Updating settings will re-connect the client to all servers." = "Al actualizar la configuración el cliente se reconectará a todos los servidores.";
|
||||
|
||||
@@ -3611,9 +3920,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Upgrade and open chat" = "Actualizar y abrir Chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Upload failed" = "Error de carga";
|
||||
|
||||
/* server test step */
|
||||
"Upload file" = "Subir archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Uploading archive" = "Subiendo el archivo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use .onion hosts" = "Usar hosts .onion";
|
||||
|
||||
@@ -3644,6 +3959,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Use SimpleX Chat servers?" = "¿Usar servidores SimpleX Chat?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use the app while in the call." = "Usar la app durante la llamada.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"User profile" = "Perfil de usuario";
|
||||
|
||||
@@ -3671,6 +3989,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Verify connections" = "Verificar conexiones";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify database passphrase" = "Verificar la contraseña de la base de datos";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify passphrase" = "Verificar frase de contraseña";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify security code" = "Comprobar código de seguridad";
|
||||
|
||||
@@ -3710,6 +4034,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"View security code" = "Mostrar código de seguridad";
|
||||
|
||||
/* chat feature */
|
||||
"Visible history" = "Historial visible";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Voice message…" = "Mensaje de voz…";
|
||||
|
||||
@@ -3746,6 +4073,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"wants to connect to you!" = "¡quiere contactar contigo!";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Warning: starting chat on multiple devices is not supported and will cause message delivery failures" = "Advertencia: el inicio del chat en varios dispositivos no es compatible y provocará fallos en la entrega de mensajes";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Warning: you may lose some data!" = "Atención: ¡puedes perder algunos datos!";
|
||||
|
||||
@@ -3761,6 +4091,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Welcome message" = "Mensaje de bienvenida";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Welcome message is too long" = "El mensaje de bienvenida es demasiado largo";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"What's new" = "Novedades";
|
||||
|
||||
@@ -3773,9 +4106,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." = "Cuando compartes un perfil incógnito con alguien, este perfil también se usará para los grupos a los que te inviten.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"With encrypted files and media." = "Con cifrado de archivos y multimedia.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"With optional welcome message." = "Con mensaje de bienvenida opcional.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"With reduced battery usage." = "Con uso reducido de batería.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Wrong database passphrase" = "Contraseña de base de datos incorrecta";
|
||||
|
||||
@@ -3791,6 +4130,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"You" = "Tú";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You **must not** use the same database on two devices." = "**No debe** usar la misma base de datos en dos dispositivos.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You accepted connection" = "Has aceptado la conexión";
|
||||
|
||||
@@ -3836,6 +4178,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"you are observer" = "Tu rol es observador";
|
||||
|
||||
/* snd group event chat item */
|
||||
"you blocked %@" = "has bloqueado a %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can accept calls from lock screen, without device and app authentication." = "Puede aceptar llamadas desde la pantalla de bloqueo, sin autenticación de dispositivos y aplicaciones.";
|
||||
|
||||
@@ -3848,6 +4193,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"You can enable them later via app Privacy & Security settings." = "Puedes activarlos más tarde en la configuración de Privacidad y Seguridad.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can give another try." = "Puede intentarlo de nuevo.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can hide or mute a user profile - swipe it to the right." = "Puedes ocultar o silenciar un perfil deslizándolo a la derecha.";
|
||||
|
||||
@@ -3947,6 +4295,9 @@
|
||||
/* chat list item description */
|
||||
"you shared one-time link incognito" = "has compartido enlace de un solo uso en modo incógnito";
|
||||
|
||||
/* snd group event chat item */
|
||||
"you unblocked %@" = "has desbloqueado a %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You will be connected to group when the group host's device is online, please wait or check later!" = "Te conectarás al grupo cuando el dispositivo del anfitrión esté en línea, por favor espera o compruébalo más tarde.";
|
||||
|
||||
|
||||
@@ -2046,7 +2046,7 @@
|
||||
/* copied message info */
|
||||
"Moderated at: %@" = "Moderoitu klo: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
/* marked deleted chat item preview text */
|
||||
"moderated by %@" = "%@ moderoi";
|
||||
|
||||
/* time unit */
|
||||
|
||||
@@ -85,6 +85,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." = "**Confidentiel** : ne pas utiliser le serveur de notifications SimpleX, vérification de nouveaux messages periodiquement en arrière plan (dépend de l'utilisation de l'app).";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Please note**: using the same database on two devices will break the decryption of messages from your connections, as a security protection." = "**Remarque** : l'utilisation de la même base de données sur deux appareils interrompt le déchiffrement des messages provenant de vos connexions, par mesure de sécurité.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Please note**: you will NOT be able to recover or change passphrase if you lose it." = "**Veuillez noter** : vous NE pourrez PAS récupérer ou modifier votre phrase secrète si vous la perdez.";
|
||||
|
||||
@@ -94,6 +97,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"**Warning**: Instant push notifications require passphrase saved in Keychain." = "**Avertissement** : les notifications push instantanées nécessitent une phrase secrète enregistrée dans la keychain.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"**Warning**: the archive will be removed." = "**Avertissement** : l'archive sera supprimée.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"*bold*" = "\\*gras*";
|
||||
|
||||
@@ -136,6 +142,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%@ connected" = "%@ connecté(e)";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%@ downloaded" = "%@ téléchargé";
|
||||
|
||||
/* notification title */
|
||||
"%@ is connected!" = "%@ est connecté·e !";
|
||||
|
||||
@@ -148,6 +157,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%@ servers" = "Serveurs %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%@ uploaded" = "%@ envoyé";
|
||||
|
||||
/* notification title */
|
||||
"%@ wants to connect!" = "%@ veut se connecter !";
|
||||
|
||||
@@ -202,6 +214,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages blocked" = "%lld messages bloqués";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages blocked by admin" = "%lld messages bloqués par l'administrateur";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"%lld messages marked deleted" = "%lld messages marqués comme supprimés";
|
||||
|
||||
@@ -374,6 +389,9 @@
|
||||
/* member role */
|
||||
"admin" = "admin";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Admins can block a member for all." = "Les admins peuvent bloquer un membre pour tous.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Admins can create the links to join groups." = "Les admins peuvent créer les liens qui permettent de rejoindre les groupes.";
|
||||
|
||||
@@ -381,10 +399,10 @@
|
||||
"Advanced network settings" = "Paramètres réseau avancés";
|
||||
|
||||
/* chat item text */
|
||||
"agreeing encryption for %@…" = "accord sur le chiffrement pour %@…";
|
||||
"agreeing encryption for %@…" = "négociation du chiffrement avec %@…";
|
||||
|
||||
/* chat item text */
|
||||
"agreeing encryption…" = "accord sur le chiffrement…";
|
||||
"agreeing encryption…" = "négociation du chiffrement…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All app data is deleted." = "Toutes les données de l'application sont supprimées.";
|
||||
@@ -413,6 +431,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"All your contacts will remain connected. Profile update will be sent to your contacts." = "Tous vos contacts resteront connectés. La mise à jour du profil sera envoyée à vos contacts.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"All your contacts, conversations and files will be securely encrypted and uploaded in chunks to configured XFTP relays." = "Tous vos contacts, conversations et fichiers seront chiffrés en toute sécurité et transférés par morceaux vers les relais XFTP configurés.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Allow" = "Autoriser";
|
||||
|
||||
@@ -494,6 +515,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"App build: %@" = "Build de l'app : %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"App data migration" = "Transfert des données de l'application";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"App encrypts new local files (except videos)." = "L'application chiffre les nouveaux fichiers locaux (sauf les vidéos).";
|
||||
|
||||
@@ -515,6 +539,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Appearance" = "Apparence";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Apply" = "Appliquer";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Archive and upload" = "Archiver et transférer";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Archiving database" = "Archivage de la base de données";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Attach" = "Attacher";
|
||||
|
||||
@@ -584,6 +617,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Block" = "Bloquer";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block for all" = "Bloqué pour tous";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block group members" = "Bloquer des membres d'un groupe";
|
||||
|
||||
@@ -591,11 +627,23 @@
|
||||
"Block member" = "Bloquer ce membre";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block member?" = "Bloquer ce membre ?";
|
||||
"Block member for all?" = "Bloquer le membre pour tous ?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Block member?" = "Bloquer ce membre ?";
|
||||
|
||||
/* marked deleted chat item preview text */
|
||||
"blocked" = "blocké";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"blocked %@" = "%@ bloqué";
|
||||
|
||||
/* marked deleted chat item preview text */
|
||||
"blocked by admin" = "bloqué par l'administrateur";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Blocked by admin" = "Bloqué par l'administrateur";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"bold" = "gras";
|
||||
|
||||
@@ -647,6 +695,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Cancel" = "Annuler";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Cancel migration" = "Annuler le transfert";
|
||||
|
||||
/* feature offered item */
|
||||
"cancelled %@" = "annulé %@";
|
||||
|
||||
@@ -688,7 +739,7 @@
|
||||
"Change self-destruct passcode" = "Modifier le code d'autodestruction";
|
||||
|
||||
/* chat item text */
|
||||
"changed address for you" = "adresse modifiée pour vous";
|
||||
"changed address for you" = "changement de l'adresse du contact";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"changed role of %@ to %@" = "a modifié le rôle de %1$@ pour %2$@";
|
||||
@@ -726,6 +777,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Chat is stopped. If you already used this database on another device, you should transfer it back before starting chat." = "Le chat est arrêté. Si vous avez déjà utilisé cette base de données sur un autre appareil, vous devez la transférer à nouveau avant de démarrer le chat.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Chat migrated!" = "Messagerie transférée !";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Chat preferences" = "Préférences de chat";
|
||||
|
||||
@@ -738,6 +792,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Chinese and Spanish interface" = "Interface en chinois et en espagnol";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Choose _Migrate from another device_ on the new device and scan QR code." = "Choisissez _Transferer depuis un autre appareil_ sur le nouvel appareil et scannez le code QR.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Choose file" = "Choisir le fichier";
|
||||
|
||||
@@ -783,6 +840,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm database upgrades" = "Confirmer la mise à niveau de la base de données";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm network settings" = "Confirmer les paramètres réseau";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm new passphrase…" = "Confirmer la nouvelle phrase secrète…";
|
||||
|
||||
@@ -792,6 +852,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm password" = "Confirmer le mot de passe";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm that you remember database passphrase to migrate it." = "Confirmer que vous vous souvenez de la phrase secrète de la base de données pour la transférer.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Confirm upload" = "Confirmer la transmission";
|
||||
|
||||
/* server test step */
|
||||
"Connect" = "Se connecter";
|
||||
|
||||
@@ -949,7 +1015,7 @@
|
||||
"Create a group using a random profile." = "Création de groupes via un profil aléatoire.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Create an address to let people connect with you." = "Créez une adresse pour permettre aux gens de vous contacter.";
|
||||
"Create an address to let people connect with you." = "Vous pouvez créer une adresse pour permettre aux autres utilisateurs de vous contacter.";
|
||||
|
||||
/* server test step */
|
||||
"Create file" = "Créer un fichier";
|
||||
@@ -990,6 +1056,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Created on %@" = "Créé le %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Creating archive link" = "Création d'un lien d'archive";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Creating link…" = "Création d'un lien…";
|
||||
|
||||
@@ -1137,6 +1206,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Delete database" = "Supprimer la base de données";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Delete database from this device" = "Supprimer la base de données de cet appareil";
|
||||
|
||||
/* server test step */
|
||||
"Delete file" = "Supprimer le fichier";
|
||||
|
||||
@@ -1329,9 +1401,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Downgrade and open chat" = "Rétrograder et ouvrir le chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Download failed" = "Échec du téléchargement";
|
||||
|
||||
/* server test step */
|
||||
"Download file" = "Télécharger le fichier";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Downloading archive" = "Téléchargement de l'archive";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Downloading link details" = "Téléchargement des détails du lien";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Duplicate display name!" = "Nom d'affichage en double !";
|
||||
|
||||
@@ -1365,6 +1446,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Enable for all" = "Activer pour tous";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enable in direct chats (BETA)!" = "Activer dans les conversations directes (BETA) !";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enable instant notifications?" = "Activer les notifications instantanées ?";
|
||||
|
||||
@@ -1479,6 +1563,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Enter Passcode" = "Entrer le code d'accès";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enter passphrase" = "Entrer la phrase secrète";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Enter passphrase…" = "Entrez la phrase secrète…";
|
||||
|
||||
@@ -1518,6 +1605,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error adding member(s)" = "Erreur lors de l'ajout de membre·s";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error allowing contact PQ encryption" = "Erreur lors de la négociation du chiffrement PQ";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error changing address" = "Erreur de changement d'adresse";
|
||||
|
||||
@@ -1572,6 +1662,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error deleting user profile" = "Erreur lors de la suppression du profil utilisateur";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error downloading the archive" = "Erreur lors du téléchargement de l'archive";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error enabling delivery receipts!" = "Erreur lors de l'activation des accusés de réception !";
|
||||
|
||||
@@ -1617,6 +1710,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error saving passphrase to keychain" = "Erreur lors de l'enregistrement de la phrase de passe dans la keychain";
|
||||
|
||||
/* when migrating */
|
||||
"Error saving settings" = "Erreur lors de l'enregistrement des paramètres";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error saving user password" = "Erreur d'enregistrement du mot de passe de l'utilisateur";
|
||||
|
||||
@@ -1659,6 +1755,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Error updating user privacy" = "Erreur de mise à jour de la confidentialité de l'utilisateur";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error uploading the archive" = "Erreur lors de l'envoi de l'archive";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error verifying passphrase:" = "Erreur lors de la vérification de la phrase secrète :";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Error: " = "Erreur : ";
|
||||
|
||||
@@ -1681,7 +1783,7 @@
|
||||
"Exit without saving" = "Quitter sans enregistrer";
|
||||
|
||||
/* chat item action */
|
||||
"Expand" = "Développer";
|
||||
"Expand" = "Étendre";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Export database" = "Exporter la base de données";
|
||||
@@ -1692,6 +1794,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Exported database archive." = "Archive de la base de données exportée.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Exported file doesn't exist" = "Le fichier exporté n'existe pas";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Exporting database archive…" = "Exportation de l'archive de la base de données…";
|
||||
|
||||
@@ -1734,6 +1839,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Filter unread and favorite chats." = "Filtrer les messages non lus et favoris.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finalize migration" = "Finaliser le transfert";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finalize migration on another device." = "Finalisez le transfert sur l'autre appareil.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Finally, we have them! 🚀" = "Enfin, les voilà ! 🚀";
|
||||
|
||||
@@ -1917,6 +2028,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"How to use your servers" = "Comment utiliser vos serveurs";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Hungarian interface" = "Interface en hongrois";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"ICE servers (one per line)" = "Serveurs ICE (un par ligne)";
|
||||
|
||||
@@ -1956,6 +2070,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Import database" = "Importer la base de données";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Import failed" = "Échec de l'importation";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Importing archive" = "Importation de l'archive";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Improved message delivery" = "Amélioration de la transmission des messages";
|
||||
|
||||
@@ -1965,6 +2085,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Improved server configuration" = "Configuration de serveur améliorée";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In order to continue, chat should be stopped." = "Pour continuer, le chat doit être interrompu.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"In reply to" = "En réponse à";
|
||||
|
||||
@@ -2049,6 +2172,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid link" = "Lien invalide";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid migration confirmation" = "Confirmation de migration invalide";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Invalid name!" = "Nom invalide !";
|
||||
|
||||
@@ -2313,6 +2439,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Message text" = "Texte du message";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Message too large" = "Message trop volumineux";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Messages" = "Messages";
|
||||
|
||||
@@ -2322,9 +2451,36 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Messages from %@ will be shown!" = "Les messages de %@ seront affichés !";
|
||||
|
||||
/* 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." = "Les messages, fichiers et appels sont protégés par un chiffrement **de bout en bout** avec une confidentialité persistante, une répudiation et une récupération en cas d'effraction.";
|
||||
|
||||
/* 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." = "Les messages, fichiers et appels sont protégés par un chiffrement **e2e résistant post-quantique** avec une confidentialité persistante, une répudiation et une récupération en cas d'effraction.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate device" = "Transférer l'appareil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate from another device" = "Transférer depuis un autre appareil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate here" = "Transférer ici";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate to another device" = "Transférer vers un autre appareil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrate to another device via QR code." = "Transférer vers un autre appareil via un code QR.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrating" = "Transfert";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migrating database archive…" = "Migration de l'archive de la base de données…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migration complete" = "Transfert terminé";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Migration error:" = "Erreur de migration :";
|
||||
|
||||
@@ -2355,7 +2511,7 @@
|
||||
/* copied message info */
|
||||
"Moderated at: %@" = "Modéré à : %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
/* marked deleted chat item preview text */
|
||||
"moderated by %@" = "modéré par %@";
|
||||
|
||||
/* time unit */
|
||||
@@ -2582,6 +2738,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Open group" = "Ouvrir le groupe";
|
||||
|
||||
/* authentication reason */
|
||||
"Open migration to another device" = "Ouvrir le transfert vers un autre appareil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Open Settings" = "Ouvrir les Paramètres";
|
||||
|
||||
@@ -2594,9 +2753,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Opening app…" = "Ouverture de l'app…";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or paste archive link" = "Ou coller le lien de l'archive";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or scan QR code" = "Ou scanner le code QR";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or securely share this file link" = "Ou partagez en toute sécurité le lien de ce fichier";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Or show this code" = "Ou présenter ce code";
|
||||
|
||||
@@ -2648,6 +2813,9 @@
|
||||
/* message decrypt error item */
|
||||
"Permanent decryption error" = "Erreur de déchiffrement";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Picture-in-picture calls" = "Appels picture-in-picture";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"PING count" = "Nombre de PING";
|
||||
|
||||
@@ -2666,6 +2834,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Please check yours and your contact preferences." = "Veuillez vérifier vos préférences ainsi que celles de votre contact.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please confirm that network settings are correct for this device." = "Veuillez confirmer que les paramètres réseau de cet appareil sont corrects.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Please contact developers.\nError: %@" = "Veuillez contacter les développeurs.\nErreur : %@";
|
||||
|
||||
@@ -2699,6 +2870,9 @@
|
||||
/* server test error */
|
||||
"Possibly, certificate fingerprint in server address is incorrect" = "Il est possible que l'empreinte du certificat dans l'adresse du serveur soit incorrecte";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Post-quantum E2EE" = "E2EE post-quantique";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Preserve the last message draft, with attachments." = "Conserver le brouillon du dernier message, avec les pièces jointes.";
|
||||
|
||||
@@ -2780,6 +2954,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Push notifications" = "Notifications push";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Push server" = "Serveur Push";
|
||||
|
||||
/* chat item text */
|
||||
"quantum resistant e2e encryption" = "chiffrement e2e résistant post-quantique";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Quantum resistant encryption" = "Chiffrement résistant post-quantique";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Rate the app" = "Évaluer l'app";
|
||||
|
||||
@@ -2915,9 +3098,18 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat connection request?" = "Répéter la demande de connexion ?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat download" = "Répéter le téléchargement";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat import" = "Répéter l'importation";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat join request?" = "Répéter la requête d'adhésion ?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Repeat upload" = "Répéter l'envoi";
|
||||
|
||||
/* chat item action */
|
||||
"Reply" = "Répondre";
|
||||
|
||||
@@ -2975,6 +3167,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Run chat" = "Exécuter le chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Safer groups" = "Groupes plus sûrs";
|
||||
|
||||
/* chat item action */
|
||||
"Save" = "Enregistrer";
|
||||
|
||||
@@ -3207,14 +3402,17 @@
|
||||
"Set it instead of system authentication." = "Il permet de remplacer l'authentification du système.";
|
||||
|
||||
/* profile update event chat item */
|
||||
"set new contact address" = "définir une nouvelle adresse de contact";
|
||||
"set new contact address" = "a changé d'adresse de contact";
|
||||
|
||||
/* profile update event chat item */
|
||||
"set new profile picture" = "définir une nouvelle image de profil";
|
||||
"set new profile picture" = "a changé d'image de profil";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passcode" = "Définir le code d'accès";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passphrase" = "Définir une phrase secrète";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Set passphrase to export" = "Définir la phrase secrète pour l'export";
|
||||
|
||||
@@ -3258,7 +3456,10 @@
|
||||
"Show last messages" = "Voir les derniers messages";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show preview" = "Montrer l'aperçu";
|
||||
"Show preview" = "Afficher l'aperçu";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show QR code" = "Afficher le code QR";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Show:" = "Afficher :";
|
||||
@@ -3320,6 +3521,9 @@
|
||||
/* notification title */
|
||||
"Somebody" = "Quelqu'un";
|
||||
|
||||
/* chat item text */
|
||||
"standard end-to-end encryption" = "chiffrement de bout en bout standard";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Start chat" = "Démarrer le chat";
|
||||
|
||||
@@ -3335,6 +3539,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Stop" = "Arrêter";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stop chat" = "Arrêter le chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stop chat to enable database actions" = "Arrêter le chat pour permettre des actions sur la base de données";
|
||||
|
||||
@@ -3362,6 +3569,9 @@
|
||||
/* authentication reason */
|
||||
"Stop SimpleX" = "Arrêter SimpleX";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Stopping chat" = "Arrêt du chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"strike" = "barré";
|
||||
|
||||
@@ -3512,6 +3722,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost." = "Cette action ne peut être annulée - votre profil, vos contacts, vos messages et vos fichiers seront irréversiblement perdus.";
|
||||
|
||||
/* E2EE info chat item */
|
||||
"This chat is protected by end-to-end encryption." = "Cette discussion est protégée par un chiffrement de bout en bout.";
|
||||
|
||||
/* E2EE info chat item */
|
||||
"This chat is protected by quantum resistant end-to-end encryption." = "Cette discussion est protégée par un chiffrement de bout en bout résistant aux technologies quantiques.";
|
||||
|
||||
/* notification title */
|
||||
"this contact" = "ce contact";
|
||||
|
||||
@@ -3596,12 +3812,21 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock" = "Débloquer";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock for all" = "Débloquer pour tous";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member" = "Débloquer ce membre";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member for all?" = "Débloquer le membre pour tous ?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Unblock member?" = "Débloquer ce membre ?";
|
||||
|
||||
/* rcv group event chat item */
|
||||
"unblocked %@" = "%@ débloqué";
|
||||
|
||||
/* item status description */
|
||||
"Unexpected error: %@" = "Erreur inattendue : %@";
|
||||
|
||||
@@ -3695,9 +3920,15 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Upgrade and open chat" = "Mettre à niveau et ouvrir le chat";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Upload failed" = "Échec de l'envoi";
|
||||
|
||||
/* server test step */
|
||||
"Upload file" = "Transférer le fichier";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Uploading archive" = "Envoi de l'archive";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use .onion hosts" = "Utiliser les hôtes .onions";
|
||||
|
||||
@@ -3728,6 +3959,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Use SimpleX Chat servers?" = "Utiliser les serveurs SimpleX Chat ?";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Use the app while in the call." = "Utiliser l'application pendant l'appel.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"User profile" = "Profil d'utilisateur";
|
||||
|
||||
@@ -3735,7 +3969,7 @@
|
||||
"Using .onion hosts requires compatible VPN provider." = "L'utilisation des hôtes .onion nécessite un fournisseur VPN compatible.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Using SimpleX Chat servers." = "Utilisation des serveurs SimpleX Chat.";
|
||||
"Using SimpleX Chat servers." = "Vous utilisez les serveurs SimpleX.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"v%@" = "v%@";
|
||||
@@ -3755,6 +3989,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Verify connections" = "Vérifier les connexions";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify database passphrase" = "Vérifier la phrase secrète de la base de données";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify passphrase" = "Vérifier la phrase secrète";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Verify security code" = "Vérifier le code de sécurité";
|
||||
|
||||
@@ -3833,6 +4073,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"wants to connect to you!" = "veut établir une connexion !";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Warning: starting chat on multiple devices is not supported and will cause message delivery failures" = "Attention: démarrer une session de chat sur plusieurs appareils n'est pas pris en charge et entraînera des dysfonctionnements au niveau de la transmission des messages";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Warning: you may lose some data!" = "Attention : vous risquez de perdre des données !";
|
||||
|
||||
@@ -3848,6 +4091,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Welcome message" = "Message de bienvenue";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Welcome message is too long" = "Le message de bienvenue est trop long";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"What's new" = "Quoi de neuf ?";
|
||||
|
||||
@@ -3855,7 +4101,7 @@
|
||||
"When available" = "Quand disponible";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"When people request to connect, you can accept or reject it." = "Lorsque des personnes demandent à se connecter, vous pouvez les accepter ou les refuser.";
|
||||
"When people request to connect, you can accept or reject it." = "Vous pouvez accepter ou refuser les demandes de contacts.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"When you share an incognito profile with somebody, this profile will be used for the groups they invite you to." = "Lorsque vous partagez un profil incognito avec quelqu'un, ce profil sera utilisé pour les groupes auxquels il vous invite.";
|
||||
@@ -3884,6 +4130,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"You" = "Vous";
|
||||
|
||||
/* 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.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You accepted connection" = "Vous avez accepté la connexion";
|
||||
|
||||
@@ -3929,6 +4178,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"you are observer" = "vous êtes observateur";
|
||||
|
||||
/* snd group event chat item */
|
||||
"you blocked %@" = "vous avez bloqué %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can accept calls from lock screen, without device and app authentication." = "Vous pouvez accepter des appels à partir de l'écran de verrouillage, sans authentification de l'appareil ou de l'application.";
|
||||
|
||||
@@ -3941,6 +4193,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"You can enable them later via app Privacy & Security settings." = "Vous pouvez les activer ultérieurement via les paramètres de Confidentialité et Sécurité de l'application.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can give another try." = "Vous pouvez faire un nouvel essai.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can hide or mute a user profile - swipe it to the right." = "Vous pouvez masquer ou mettre en sourdine un profil d'utilisateur - faites-le glisser vers la droite.";
|
||||
|
||||
@@ -3960,7 +4215,7 @@
|
||||
"You can share this address with your contacts to let them connect with **%@**." = "Vous pouvez partager cette adresse avec vos contacts pour leur permettre de se connecter avec **%@**.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can share your address as a link or QR code - anybody can connect to you." = "Vous pouvez partager votre adresse sous forme de lien ou de code QR - n'importe qui pourra se connecter à vous.";
|
||||
"You can share your address as a link or QR code - anybody can connect to you." = "Vous pouvez partager votre adresse sous la forme d'un lien ou d'un code QR - tout le monde peut l'utiliser pour vous contacter.";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You can start chat via app Settings / Database or by restarting the app" = "Vous pouvez lancer le chat via Paramètres / Base de données ou en redémarrant l'app";
|
||||
@@ -4040,6 +4295,9 @@
|
||||
/* chat list item description */
|
||||
"you shared one-time link incognito" = "vous avez partagé un lien unique en incognito";
|
||||
|
||||
/* snd group event chat item */
|
||||
"you unblocked %@" = "vous avez débloqué %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"You will be connected to group when the group host's device is online, please wait or check later!" = "Vous serez connecté·e au groupe lorsque l'appareil de l'hôte sera en ligne, veuillez attendre ou vérifier plus tard !";
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user