diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 3fb4833d66..10073fa8a6 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -464,6 +464,10 @@ func setNetworkConfig(_ cfg: NetCfg) throws { throw r } +func reconnectAllServers() async throws { + try await sendCommandOkResp(.reconnectAllServers) +} + func apiSetChatSettings(type: ChatType, id: Int64, chatSettings: ChatSettings) async throws { try await sendCommandOkResp(.apiSetChatSettings(type: type, id: id, chatSettings: chatSettings)) } diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 6de638257c..9e85f0d467 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -55,6 +55,22 @@ struct ChatListView: View { .onChange(of: chatModel.appOpenUrl) { _ in connectViaUrl() } .onAppear() { connectViaUrl() } .onDisappear() { withAnimation { userPickerVisible = false } } + .refreshable { + AlertManager.shared.showAlert(Alert( + title: Text("Reconnect servers?"), + message: Text("Reconnect all connected servers to force message delivery. It uses additional traffic."), + primaryButton: .default(Text("Ok")) { + Task { + do { + try await reconnectAllServers() + } catch let error { + AlertManager.shared.showAlertMsg(title: "Error", message: "\(responseError(error))") + } + } + }, + secondaryButton: .cancel() + )) + } .offset(x: -8) .listStyle(.plain) .navigationBarTitleDisplayMode(.inline) diff --git a/apps/ios/Shared/Views/UserSettings/AdvancedNetworkSettings.swift b/apps/ios/Shared/Views/UserSettings/AdvancedNetworkSettings.swift index 6d77eeb998..821464be0f 100644 --- a/apps/ios/Shared/Views/UserSettings/AdvancedNetworkSettings.swift +++ b/apps/ios/Shared/Views/UserSettings/AdvancedNetworkSettings.swift @@ -53,6 +53,7 @@ struct AdvancedNetworkSettings: View { timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [2_500000, 5_000000, 7_500000, 10_000000, 15_000000, 20_000000], label: secondsLabel) timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [1_500000, 3_000000, 5_000000, 7_000000, 10_000000, 15_000000], label: secondsLabel) + timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [5_000, 10_000, 20_000, 40_000], label: secondsLabel) 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) diff --git a/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff b/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff new file mode 100644 index 0000000000..f599f9c300 --- /dev/null +++ b/apps/ios/SimpleX Localizations/bn.xcloc/Localized Contents/bn.xliff @@ -0,0 +1,4655 @@ + + + +
+ +
+ + + + + + + No comment provided by engineer. + + + + + No comment provided by engineer. + + + + + No comment provided by engineer. + + + + + No comment provided by engineer. + + + ( + ( + No comment provided by engineer. + + + (can be copied) + No comment provided by engineer. + + + !1 colored! + !1 রঙিন! + No comment provided by engineer. + + + #secret# + No comment provided by engineer. + + + %@ + No comment provided by engineer. + + + %@ %@ + No comment provided by engineer. + + + %@ (current) + No comment provided by engineer. + + + %@ (current): + copied message info + + + %@ / %@ + No comment provided by engineer. + + + %@ is connected! + notification title + + + %@ is not verified + No comment provided by engineer. + + + %@ is verified + No comment provided by engineer. + + + %@ servers + No comment provided by engineer. + + + %@ wants to connect! + notification title + + + %@: + copied message info + + + %d days + time interval + + + %d hours + time interval + + + %d min + time interval + + + %d months + time interval + + + %d sec + time interval + + + %d skipped message(s) + integrity error chat item + + + %d weeks + time interval + + + %lld + No comment provided by engineer. + + + %lld %@ + No comment provided by engineer. + + + %lld contact(s) selected + No comment provided by engineer. + + + %lld file(s) with total size of %@ + No comment provided by engineer. + + + %lld members + No comment provided by engineer. + + + %lld minutes + No comment provided by engineer. + + + %lld second(s) + No comment provided by engineer. + + + %lld seconds + No comment provided by engineer. + + + %lldd + No comment provided by engineer. + + + %lldh + No comment provided by engineer. + + + %lldk + No comment provided by engineer. + + + %lldm + No comment provided by engineer. + + + %lldmth + No comment provided by engineer. + + + %llds + No comment provided by engineer. + + + %lldw + No comment provided by engineer. + + + %u messages failed to decrypt. + No comment provided by engineer. + + + %u messages skipped. + No comment provided by engineer. + + + ( + No comment provided by engineer. + + + ) + No comment provided by engineer. + + + **Add new contact**: to create your one-time QR Code or link for your contact. + No comment provided by engineer. + + + **Create link / QR code** for your contact to use. + No comment provided by engineer. + + + **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. + 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). + No comment provided by engineer. + + + **Paste received link** or open it in the browser and tap **Open in mobile app**. + No comment provided by engineer. + + + **Please note**: you will NOT be able to recover or change passphrase if you lose it. + No comment provided by engineer. + + + **Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from. + No comment provided by engineer. + + + **Scan QR code**: to connect to your contact in person or via video call. + No comment provided by engineer. + + + **Warning**: Instant push notifications require passphrase saved in Keychain. + No comment provided by engineer. + + + **e2e encrypted** audio call + No comment provided by engineer. + + + **e2e encrypted** video call + No comment provided by engineer. + + + \*bold* + No comment provided by engineer. + + + , + No comment provided by engineer. + + + - voice messages up to 5 minutes. +- custom time to disappear. +- editing history. + No comment provided by engineer. + + + . + No comment provided by engineer. + + + 0s + No comment provided by engineer. + + + 1 day + time interval + + + 1 hour + time interval + + + 1 minute + No comment provided by engineer. + + + 1 month + time interval + + + 1 week + time interval + + + 1-time link + No comment provided by engineer. + + + 5 minutes + No comment provided by engineer. + + + 6 + No comment provided by engineer. + + + 30 seconds + No comment provided by engineer. + + + : + No comment provided by engineer. + + + <p>Hi!</p> +<p><a href="%@">Connect to me via SimpleX Chat</a></p> + email text + + + A new contact + notification title + + + A random profile will be sent to the contact that you received this link from + No comment provided by engineer. + + + A random profile will be sent to your contact + No comment provided by engineer. + + + A separate TCP connection will be used **for each chat profile you have in the app**. + No comment provided by engineer. + + + A separate TCP connection will be used **for each contact and group member**. +**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail. + No comment provided by engineer. + + + Abort + No comment provided by engineer. + + + Abort changing address + No comment provided by engineer. + + + Abort changing address? + No comment provided by engineer. + + + About SimpleX + No comment provided by engineer. + + + About SimpleX Chat + No comment provided by engineer. + + + About SimpleX address + No comment provided by engineer. + + + Accent color + No comment provided by engineer. + + + Accept + accept contact request via notification + accept incoming call via notification + + + Accept contact + No comment provided by engineer. + + + Accept contact request from %@? + notification body + + + Accept incognito + No comment provided by engineer. + + + Add address to your profile, so that your contacts can share it with other people. Profile update will be sent to your contacts. + No comment provided by engineer. + + + Add preset servers + No comment provided by engineer. + + + Add profile + No comment provided by engineer. + + + Add servers by scanning QR codes. + No comment provided by engineer. + + + Add server… + No comment provided by engineer. + + + Add to another device + No comment provided by engineer. + + + Add welcome message + No comment provided by engineer. + + + Address + No comment provided by engineer. + + + Address change will be aborted. Old receiving address will be used. + No comment provided by engineer. + + + Admins can create the links to join groups. + No comment provided by engineer. + + + Advanced network settings + No comment provided by engineer. + + + All app data is deleted. + No comment provided by engineer. + + + All chats and messages will be deleted - this cannot be undone! + No comment provided by engineer. + + + All data is erased when it is entered. + 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! The messages will be deleted ONLY for you. + No comment provided by engineer. + + + All your contacts will remain connected. + No comment provided by engineer. + + + All your contacts will remain connected. Profile update will be sent to your contacts. + No comment provided by engineer. + + + Allow + No comment provided by engineer. + + + Allow calls only if your contact allows them. + No comment provided by engineer. + + + Allow disappearing messages only if your contact allows it to you. + No comment provided by engineer. + + + Allow irreversible message deletion only if your contact allows it to you. + No comment provided by engineer. + + + Allow message reactions only if your contact allows them. + No comment provided by engineer. + + + Allow message reactions. + No comment provided by engineer. + + + Allow sending direct messages to members. + No comment provided by engineer. + + + Allow sending disappearing messages. + No comment provided by engineer. + + + Allow to irreversibly delete sent messages. + No comment provided by engineer. + + + Allow to send voice messages. + No comment provided by engineer. + + + Allow voice messages only if your contact allows them. + No comment provided by engineer. + + + Allow voice messages? + No comment provided by engineer. + + + Allow your contacts adding message reactions. + No comment provided by engineer. + + + Allow your contacts to call you. + No comment provided by engineer. + + + Allow your contacts to irreversibly delete sent messages. + No comment provided by engineer. + + + Allow your contacts to send disappearing messages. + No comment provided by engineer. + + + Allow your contacts to send voice messages. + No comment provided by engineer. + + + Already connected? + No comment provided by engineer. + + + Always use relay + No comment provided by engineer. + + + An empty chat profile with the provided name is created, and the app opens as usual. + No comment provided by engineer. + + + Answer call + No comment provided by engineer. + + + App build: %@ + No comment provided by engineer. + + + App icon + No comment provided by engineer. + + + App passcode + No comment provided by engineer. + + + App passcode is replaced with self-destruct passcode. + No comment provided by engineer. + + + App version + No comment provided by engineer. + + + App version: v%@ + No comment provided by engineer. + + + Appearance + No comment provided by engineer. + + + Attach + No comment provided by engineer. + + + Audio & video calls + No comment provided by engineer. + + + Audio and video calls + No comment provided by engineer. + + + Audio/video calls + chat feature + + + Audio/video calls are prohibited. + No comment provided by engineer. + + + Authentication cancelled + PIN entry + + + Authentication failed + No comment provided by engineer. + + + Authentication is required before the call is connected, but you may miss calls. + No comment provided by engineer. + + + Authentication unavailable + No comment provided by engineer. + + + Auto-accept + No comment provided by engineer. + + + Auto-accept contact requests + No comment provided by engineer. + + + Auto-accept images + No comment provided by engineer. + + + Back + No comment provided by engineer. + + + Bad message ID + No comment provided by engineer. + + + Bad message hash + No comment provided by engineer. + + + Better messages + No comment provided by engineer. + + + Both you and your contact can add message reactions. + No comment provided by engineer. + + + Both you and your contact can irreversibly delete sent messages. + No comment provided by engineer. + + + Both you and your contact can make calls. + No comment provided by engineer. + + + Both you and your contact can send disappearing messages. + No comment provided by engineer. + + + Both you and your contact can send voice messages. + No comment provided by engineer. + + + By chat profile (default) or [by connection](https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation) (BETA). + No comment provided by engineer. + + + Call already ended! + No comment provided by engineer. + + + Calls + No comment provided by engineer. + + + Can't delete user profile! + No comment provided by engineer. + + + Can't invite contact! + No comment provided by engineer. + + + Can't invite contacts! + No comment provided by engineer. + + + Cancel + No comment provided by engineer. + + + Cannot access keychain to save database password + No comment provided by engineer. + + + Cannot receive file + No comment provided by engineer. + + + Change + No comment provided by engineer. + + + Change database passphrase? + No comment provided by engineer. + + + Change lock mode + authentication reason + + + Change member role? + No comment provided by engineer. + + + Change passcode + authentication reason + + + Change receiving address + No comment provided by engineer. + + + Change receiving address? + No comment provided by engineer. + + + Change role + No comment provided by engineer. + + + Change self-destruct mode + authentication reason + + + Change self-destruct passcode + authentication reason + set passcode view + + + Chat archive + No comment provided by engineer. + + + Chat console + No comment provided by engineer. + + + Chat database + No comment provided by engineer. + + + Chat database deleted + No comment provided by engineer. + + + Chat database imported + No comment provided by engineer. + + + Chat is running + No comment provided by engineer. + + + Chat is stopped + No comment provided by engineer. + + + Chat preferences + No comment provided by engineer. + + + Chats + No comment provided by engineer. + + + Check server address and try again. + No comment provided by engineer. + + + Chinese and Spanish interface + No comment provided by engineer. + + + Choose file + No comment provided by engineer. + + + Choose from library + No comment provided by engineer. + + + Clear + No comment provided by engineer. + + + Clear conversation + No comment provided by engineer. + + + Clear conversation? + No comment provided by engineer. + + + Clear verification + No comment provided by engineer. + + + Colors + No comment provided by engineer. + + + Compare file + server test step + + + Compare security codes with your contacts. + No comment provided by engineer. + + + Configure ICE servers + No comment provided by engineer. + + + Confirm + No comment provided by engineer. + + + Confirm Passcode + No comment provided by engineer. + + + Confirm database upgrades + No comment provided by engineer. + + + Confirm new passphrase… + No comment provided by engineer. + + + Confirm password + No comment provided by engineer. + + + Connect + server test step + + + Connect via contact link? + No comment provided by engineer. + + + Connect via group link? + No comment provided by engineer. + + + Connect via link + No comment provided by engineer. + + + Connect via link / QR code + No comment provided by engineer. + + + Connect via one-time link? + No comment provided by engineer. + + + Connecting to server… + No comment provided by engineer. + + + Connecting to server… (error: %@) + No comment provided by engineer. + + + Connection + No comment provided by engineer. + + + Connection error + No comment provided by engineer. + + + Connection error (AUTH) + No comment provided by engineer. + + + Connection request + No comment provided by engineer. + + + Connection request sent! + No comment provided by engineer. + + + Connection timeout + No comment provided by engineer. + + + Contact allows + No comment provided by engineer. + + + Contact already exists + No comment provided by engineer. + + + Contact and all messages will be deleted - this cannot be undone! + No comment provided by engineer. + + + Contact hidden: + notification + + + Contact is connected + notification + + + Contact is not connected yet! + No comment provided by engineer. + + + Contact name + No comment provided by engineer. + + + Contact preferences + No comment provided by engineer. + + + Contacts can mark messages for deletion; you will be able to view them. + No comment provided by engineer. + + + Continue + No comment provided by engineer. + + + Copy + chat item action + + + Core version: v%@ + No comment provided by engineer. + + + Create + No comment provided by engineer. + + + Create SimpleX address + No comment provided by engineer. + + + Create an address to let people connect with you. + No comment provided by engineer. + + + Create file + server test step + + + Create group link + No comment provided by engineer. + + + Create link + No comment provided by engineer. + + + Create one-time invitation link + No comment provided by engineer. + + + Create queue + server test step + + + Create secret group + No comment provided by engineer. + + + Create your profile + No comment provided by engineer. + + + Created on %@ + No comment provided by engineer. + + + Current Passcode + No comment provided by engineer. + + + Current passphrase… + No comment provided by engineer. + + + Currently maximum supported file size is %@. + No comment provided by engineer. + + + Custom time + No comment provided by engineer. + + + Dark + No comment provided by engineer. + + + Database ID + No comment provided by engineer. + + + Database ID: %d + copied message info + + + Database IDs and Transport isolation option. + No comment provided by engineer. + + + Database downgrade + No comment provided by engineer. + + + Database encrypted! + No comment provided by engineer. + + + Database encryption passphrase will be updated and stored in the keychain. + + No comment provided by engineer. + + + Database encryption passphrase will be updated. + + No comment provided by engineer. + + + Database error + No comment provided by engineer. + + + Database is encrypted using a random passphrase, you can change it. + No comment provided by engineer. + + + Database is encrypted using a random passphrase. Please change it before exporting. + No comment provided by engineer. + + + Database passphrase + No comment provided by engineer. + + + Database passphrase & export + No comment provided by engineer. + + + Database passphrase is different from saved in the keychain. + No comment provided by engineer. + + + Database passphrase is required to open chat. + No comment provided by engineer. + + + Database upgrade + No comment provided by engineer. + + + Database will be encrypted and the passphrase stored in the keychain. + + No comment provided by engineer. + + + Database will be encrypted. + + No comment provided by engineer. + + + Database will be migrated when the app restarts + No comment provided by engineer. + + + Decentralized + No comment provided by engineer. + + + Decryption error + No comment provided by engineer. + + + Delete + chat item action + + + Delete Contact + No comment provided by engineer. + + + Delete address + No comment provided by engineer. + + + Delete address? + No comment provided by engineer. + + + Delete after + No comment provided by engineer. + + + Delete all files + No comment provided by engineer. + + + Delete archive + No comment provided by engineer. + + + Delete chat archive? + No comment provided by engineer. + + + Delete chat profile + No comment provided by engineer. + + + Delete chat profile? + No comment provided by engineer. + + + Delete connection + No comment provided by engineer. + + + Delete contact + No comment provided by engineer. + + + Delete contact? + No comment provided by engineer. + + + Delete database + No comment provided by engineer. + + + Delete file + server test step + + + Delete files and media? + No comment provided by engineer. + + + Delete files for all chat profiles + No comment provided by engineer. + + + Delete for everyone + chat feature + + + Delete for me + No comment provided by engineer. + + + Delete group + No comment provided by engineer. + + + Delete group? + No comment provided by engineer. + + + Delete invitation + No comment provided by engineer. + + + Delete link + No comment provided by engineer. + + + Delete link? + No comment provided by engineer. + + + Delete member message? + No comment provided by engineer. + + + Delete message? + No comment provided by engineer. + + + Delete messages + No comment provided by engineer. + + + Delete messages after + No comment provided by engineer. + + + Delete old database + No comment provided by engineer. + + + Delete old database? + No comment provided by engineer. + + + Delete pending connection + No comment provided by engineer. + + + Delete pending connection? + No comment provided by engineer. + + + Delete profile + No comment provided by engineer. + + + Delete queue + server test step + + + Delete user profile? + No comment provided by engineer. + + + Deleted at + No comment provided by engineer. + + + Deleted at: %@ + copied message info + + + Description + No comment provided by engineer. + + + Develop + No comment provided by engineer. + + + Developer tools + No comment provided by engineer. + + + Device + No comment provided by engineer. + + + Device authentication is disabled. Turning off SimpleX Lock. + No comment provided by engineer. + + + Device authentication is not enabled. You can turn on SimpleX Lock via Settings, once you enable device authentication. + No comment provided by engineer. + + + Different names, avatars and transport isolation. + No comment provided by engineer. + + + Direct messages + chat feature + + + Direct messages between members are prohibited in this group. + No comment provided by engineer. + + + Disable SimpleX Lock + authentication reason + + + Disappearing message + No comment provided by engineer. + + + Disappearing messages + chat feature + + + Disappearing messages are prohibited in this chat. + No comment provided by engineer. + + + Disappearing messages are prohibited in this group. + No comment provided by engineer. + + + Disappears at + No comment provided by engineer. + + + Disappears at: %@ + copied message info + + + Disconnect + server test step + + + Display name + No comment provided by engineer. + + + Display name: + No comment provided by engineer. + + + Do NOT use SimpleX for emergency calls. + No comment provided by engineer. + + + Do it later + No comment provided by engineer. + + + Don't create address + No comment provided by engineer. + + + Don't show again + No comment provided by engineer. + + + Downgrade and open chat + No comment provided by engineer. + + + Download file + server test step + + + Duplicate display name! + No comment provided by engineer. + + + Duration + No comment provided by engineer. + + + Edit + chat item action + + + Edit group profile + No comment provided by engineer. + + + Enable + No comment provided by engineer. + + + Enable SimpleX Lock + authentication reason + + + Enable TCP keep-alive + No comment provided by engineer. + + + Enable automatic message deletion? + No comment provided by engineer. + + + Enable instant notifications? + No comment provided by engineer. + + + Enable lock + No comment provided by engineer. + + + Enable notifications + No comment provided by engineer. + + + Enable periodic notifications? + No comment provided by engineer. + + + Enable self-destruct + No comment provided by engineer. + + + Enable self-destruct passcode + set passcode view + + + Encrypt + No comment provided by engineer. + + + Encrypt database? + No comment provided by engineer. + + + Encrypted database + No comment provided by engineer. + + + Encrypted message or another event + notification + + + Encrypted message: database error + notification + + + Encrypted message: database migration error + notification + + + Encrypted message: keychain error + notification + + + Encrypted message: no passphrase + notification + + + Encrypted message: unexpected error + notification + + + Enter Passcode + No comment provided by engineer. + + + Enter correct passphrase. + No comment provided by engineer. + + + Enter passphrase… + No comment provided by engineer. + + + Enter password above to show! + No comment provided by engineer. + + + Enter server manually + No comment provided by engineer. + + + Enter welcome message… + placeholder + + + Enter welcome message… (optional) + placeholder + + + Error + No comment provided by engineer. + + + Error aborting address change + No comment provided by engineer. + + + Error accepting contact request + No comment provided by engineer. + + + Error accessing database file + No comment provided by engineer. + + + Error adding member(s) + No comment provided by engineer. + + + Error changing address + No comment provided by engineer. + + + Error changing role + No comment provided by engineer. + + + Error changing setting + No comment provided by engineer. + + + Error creating address + No comment provided by engineer. + + + Error creating group + No comment provided by engineer. + + + Error creating group link + No comment provided by engineer. + + + Error creating profile! + No comment provided by engineer. + + + Error deleting chat database + No comment provided by engineer. + + + Error deleting chat! + No comment provided by engineer. + + + Error deleting connection + No comment provided by engineer. + + + Error deleting contact + No comment provided by engineer. + + + Error deleting database + No comment provided by engineer. + + + Error deleting old database + No comment provided by engineer. + + + Error deleting token + No comment provided by engineer. + + + Error deleting user profile + No comment provided by engineer. + + + Error enabling notifications + No comment provided by engineer. + + + Error encrypting database + No comment provided by engineer. + + + Error exporting chat database + No comment provided by engineer. + + + Error importing chat database + No comment provided by engineer. + + + Error joining group + No comment provided by engineer. + + + Error loading %@ servers + No comment provided by engineer. + + + Error receiving file + No comment provided by engineer. + + + Error removing member + No comment provided by engineer. + + + Error saving %@ servers + No comment provided by engineer. + + + Error saving ICE servers + No comment provided by engineer. + + + Error saving group profile + No comment provided by engineer. + + + Error saving passcode + No comment provided by engineer. + + + Error saving passphrase to keychain + No comment provided by engineer. + + + Error saving user password + No comment provided by engineer. + + + Error sending email + No comment provided by engineer. + + + Error sending message + No comment provided by engineer. + + + Error starting chat + No comment provided by engineer. + + + Error stopping chat + No comment provided by engineer. + + + Error switching profile! + No comment provided by engineer. + + + Error updating group link + No comment provided by engineer. + + + Error updating message + No comment provided by engineer. + + + Error updating settings + No comment provided by engineer. + + + Error updating user privacy + No comment provided by engineer. + + + Error: + No comment provided by engineer. + + + Error: %@ + No comment provided by engineer. + + + Error: URL is invalid + No comment provided by engineer. + + + Error: no database file + No comment provided by engineer. + + + Exit without saving + No comment provided by engineer. + + + Export database + No comment provided by engineer. + + + Export error: + No comment provided by engineer. + + + Exported database archive. + No comment provided by engineer. + + + Exporting database archive... + No comment provided by engineer. + + + Failed to remove passphrase + No comment provided by engineer. + + + Fast and no wait until the sender is online! + No comment provided by engineer. + + + Favorite + No comment provided by engineer. + + + File will be deleted from servers. + No comment provided by engineer. + + + File will be received when your contact completes uploading it. + No comment provided by engineer. + + + File will be received when your contact is online, please wait or check later! + No comment provided by engineer. + + + File: %@ + No comment provided by engineer. + + + Files & media + No comment provided by engineer. + + + Finally, we have them! 🚀 + No comment provided by engineer. + + + For console + No comment provided by engineer. + + + French interface + No comment provided by engineer. + + + Full link + No comment provided by engineer. + + + Full name (optional) + No comment provided by engineer. + + + Full name: + No comment provided by engineer. + + + Fully re-implemented - work in background! + No comment provided by engineer. + + + Further reduced battery usage + No comment provided by engineer. + + + GIFs and stickers + No comment provided by engineer. + + + Group + No comment provided by engineer. + + + Group display name + No comment provided by engineer. + + + Group full name (optional) + No comment provided by engineer. + + + Group image + No comment provided by engineer. + + + Group invitation + No comment provided by engineer. + + + Group invitation expired + No comment provided by engineer. + + + Group invitation is no longer valid, it was removed by sender. + No comment provided by engineer. + + + Group link + No comment provided by engineer. + + + Group links + No comment provided by engineer. + + + Group members can add message reactions. + No comment provided by engineer. + + + Group members can irreversibly delete sent messages. + No comment provided by engineer. + + + Group members can send direct messages. + No comment provided by engineer. + + + Group members can send disappearing messages. + No comment provided by engineer. + + + Group members can send voice messages. + No comment provided by engineer. + + + Group message: + notification + + + Group moderation + No comment provided by engineer. + + + Group preferences + No comment provided by engineer. + + + Group profile + No comment provided by engineer. + + + Group profile is stored on members' devices, not on the servers. + No comment provided by engineer. + + + Group welcome message + No comment provided by engineer. + + + Group will be deleted for all members - this cannot be undone! + No comment provided by engineer. + + + Group will be deleted for you - this cannot be undone! + No comment provided by engineer. + + + Help + No comment provided by engineer. + + + Hidden + No comment provided by engineer. + + + Hidden chat profiles + No comment provided by engineer. + + + Hidden profile password + No comment provided by engineer. + + + Hide + chat item action + + + Hide app screen in the recent apps. + No comment provided by engineer. + + + Hide profile + No comment provided by engineer. + + + Hide: + No comment provided by engineer. + + + History + copied message info + + + How SimpleX works + No comment provided by engineer. + + + How it works + No comment provided by engineer. + + + How to + No comment provided by engineer. + + + How to use it + No comment provided by engineer. + + + How to use your servers + No comment provided by engineer. + + + ICE servers (one per line) + No comment provided by engineer. + + + If you can't meet in person, show QR code in a video call, or share the link. + No comment provided by engineer. + + + If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. + No comment provided by engineer. + + + If you enter this passcode when opening the app, all app data will be irreversibly removed! + No comment provided by engineer. + + + If you enter your self-destruct passcode while opening the app: + No comment provided by engineer. + + + If you need to use the chat now tap **Do it later** below (you will be offered to migrate the database when you restart the app). + No comment provided by engineer. + + + Ignore + No comment provided by engineer. + + + Image will be received when your contact completes uploading it. + No comment provided by engineer. + + + Image will be received when your contact is online, please wait or check later! + No comment provided by engineer. + + + Immediately + No comment provided by engineer. + + + Immune to spam and abuse + No comment provided by engineer. + + + Import + No comment provided by engineer. + + + Import chat database? + No comment provided by engineer. + + + Import database + No comment provided by engineer. + + + Improved privacy and security + No comment provided by engineer. + + + Improved server configuration + No comment provided by engineer. + + + Incognito + No comment provided by engineer. + + + Incognito mode + No comment provided by engineer. + + + Incognito mode is not supported here - your main profile will be sent to group members + No comment provided by engineer. + + + Incognito mode protects the privacy of your main profile name and image — for each new contact a new random profile is created. + No comment provided by engineer. + + + Incoming audio call + notification + + + Incoming call + notification + + + Incoming video call + notification + + + Incompatible database version + No comment provided by engineer. + + + Incorrect passcode + PIN entry + + + Incorrect security code! + No comment provided by engineer. + + + Info + chat item action + + + Initial role + No comment provided by engineer. + + + Install [SimpleX Chat for terminal](https://github.com/simplex-chat/simplex-chat) + No comment provided by engineer. + + + Instant push notifications will be hidden! + + No comment provided by engineer. + + + Instantly + No comment provided by engineer. + + + Interface + No comment provided by engineer. + + + Invalid connection link + No comment provided by engineer. + + + Invalid server address! + No comment provided by engineer. + + + Invitation expired! + No comment provided by engineer. + + + Invite friends + No comment provided by engineer. + + + Invite members + No comment provided by engineer. + + + Invite to group + No comment provided by engineer. + + + Irreversible message deletion + No comment provided by engineer. + + + Irreversible message deletion is prohibited in this chat. + No comment provided by engineer. + + + Irreversible message deletion is prohibited in this group. + No comment provided by engineer. + + + It allows having many anonymous connections without any shared data between them in a single chat profile. + No comment provided by engineer. + + + It can happen when you or your connection used the old database backup. + No comment provided by engineer. + + + It can happen when: +1. The messages expired in the sending client after 2 days or on the server after 30 days. +2. Message decryption failed, because you or your contact used old database backup. +3. The connection was compromised. + No comment provided by engineer. + + + It seems like you are already connected via this link. If it is not the case, there was an error (%@). + No comment provided by engineer. + + + Italian interface + No comment provided by engineer. + + + Japanese interface + No comment provided by engineer. + + + Join + No comment provided by engineer. + + + Join group + No comment provided by engineer. + + + Join incognito + No comment provided by engineer. + + + Joining group + No comment provided by engineer. + + + KeyChain error + No comment provided by engineer. + + + Keychain error + No comment provided by engineer. + + + LIVE + No comment provided by engineer. + + + Large file! + No comment provided by engineer. + + + Learn more + No comment provided by engineer. + + + Leave + No comment provided by engineer. + + + Leave group + No comment provided by engineer. + + + Leave group? + No comment provided by engineer. + + + Let's talk in SimpleX Chat + email subject + + + Light + No comment provided by engineer. + + + Limitations + No comment provided by engineer. + + + Live message! + No comment provided by engineer. + + + Live messages + No comment provided by engineer. + + + Local name + No comment provided by engineer. + + + Local profile data only + No comment provided by engineer. + + + Lock after + No comment provided by engineer. + + + Lock mode + No comment provided by engineer. + + + Make a private connection + No comment provided by engineer. + + + Make profile private! + No comment provided by engineer. + + + Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@). + No comment provided by engineer. + + + Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated. + No comment provided by engineer. + + + Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?* + No comment provided by engineer. + + + Mark deleted for everyone + No comment provided by engineer. + + + Mark read + No comment provided by engineer. + + + Mark verified + No comment provided by engineer. + + + Markdown in messages + No comment provided by engineer. + + + Max 30 seconds, received instantly. + No comment provided by engineer. + + + Member + No comment provided by engineer. + + + Member role will be changed to "%@". All group members will be notified. + No comment provided by engineer. + + + Member role will be changed to "%@". The member will receive a new invitation. + No comment provided by engineer. + + + Member will be removed from group - this cannot be undone! + No comment provided by engineer. + + + Message delivery error + No comment provided by engineer. + + + Message draft + No comment provided by engineer. + + + Message reactions + chat feature + + + Message reactions are prohibited in this chat. + No comment provided by engineer. + + + Message reactions are prohibited in this group. + No comment provided by engineer. + + + Message text + No comment provided by engineer. + + + Messages + No comment provided by engineer. + + + Messages & files + No comment provided by engineer. + + + Migrating database archive... + No comment provided by engineer. + + + Migration error: + No comment provided by engineer. + + + Migration failed. Tap **Skip** below to continue using the current database. Please report the issue to the app developers via chat or email [chat@simplex.chat](mailto:chat@simplex.chat). + No comment provided by engineer. + + + Migration is completed + No comment provided by engineer. + + + Migrations: %@ + No comment provided by engineer. + + + Moderate + chat item action + + + Moderated at + No comment provided by engineer. + + + Moderated at: %@ + copied message info + + + More improvements are coming soon! + No comment provided by engineer. + + + Most likely this contact has deleted the connection with you. + No comment provided by engineer. + + + Multiple chat profiles + No comment provided by engineer. + + + Mute + No comment provided by engineer. + + + Muted when inactive! + No comment provided by engineer. + + + Name + No comment provided by engineer. + + + Network & servers + No comment provided by engineer. + + + Network settings + No comment provided by engineer. + + + Network status + No comment provided by engineer. + + + New Passcode + No comment provided by engineer. + + + New contact request + notification + + + New contact: + notification + + + New database archive + No comment provided by engineer. + + + New display name + No comment provided by engineer. + + + New in %@ + No comment provided by engineer. + + + New member role + No comment provided by engineer. + + + New message + notification + + + New passphrase… + No comment provided by engineer. + + + No + No comment provided by engineer. + + + No app password + Authentication unavailable + + + No contacts selected + No comment provided by engineer. + + + No contacts to add + No comment provided by engineer. + + + No device token! + No comment provided by engineer. + + + Group not found! + No comment provided by engineer. + + + No permission to record voice message + No comment provided by engineer. + + + No received or sent files + No comment provided by engineer. + + + Notifications + No comment provided by engineer. + + + Notifications are disabled! + No comment provided by engineer. + + + Now admins can: +- delete members' messages. +- disable members ("observer" role) + No comment provided by engineer. + + + Off + No comment provided by engineer. + + + Off (Local) + No comment provided by engineer. + + + Ok + No comment provided by engineer. + + + Old database + No comment provided by engineer. + + + Old database archive + No comment provided by engineer. + + + One-time invitation link + No comment provided by engineer. + + + Onion hosts will be required for connection. Requires enabling VPN. + No comment provided by engineer. + + + Onion hosts will be used when available. Requires enabling VPN. + No comment provided by engineer. + + + Onion hosts will not be used. + No comment provided by engineer. + + + Only client devices store user profiles, contacts, groups, and messages sent with **2-layer end-to-end encryption**. + No comment provided by engineer. + + + Only group owners can change group preferences. + No comment provided by engineer. + + + Only group owners can enable voice messages. + No comment provided by engineer. + + + Only you can add message reactions. + No comment provided by engineer. + + + Only you can irreversibly delete messages (your contact can mark them for deletion). + No comment provided by engineer. + + + Only you can make calls. + No comment provided by engineer. + + + Only you can send disappearing messages. + No comment provided by engineer. + + + Only you can send voice messages. + No comment provided by engineer. + + + Only your contact can add message reactions. + No comment provided by engineer. + + + Only your contact can irreversibly delete messages (you can mark them for deletion). + No comment provided by engineer. + + + Only your contact can make calls. + No comment provided by engineer. + + + Only your contact can send disappearing messages. + No comment provided by engineer. + + + Only your contact can send voice messages. + No comment provided by engineer. + + + Open Settings + No comment provided by engineer. + + + Open chat + No comment provided by engineer. + + + Open chat console + authentication reason + + + Open user profiles + authentication reason + + + Open-source protocol and code – anybody can run the servers. + No comment provided by engineer. + + + Opening database… + No comment provided by engineer. + + + Opening the link in the browser may reduce connection privacy and security. Untrusted SimpleX links will be red. + No comment provided by engineer. + + + PING count + No comment provided by engineer. + + + PING interval + No comment provided by engineer. + + + Passcode + No comment provided by engineer. + + + Passcode changed! + No comment provided by engineer. + + + Passcode entry + No comment provided by engineer. + + + Passcode not changed! + No comment provided by engineer. + + + Passcode set! + No comment provided by engineer. + + + Password to show + No comment provided by engineer. + + + Paste + No comment provided by engineer. + + + Paste image + No comment provided by engineer. + + + Paste received link + No comment provided by engineer. + + + Paste the link you received into the box below to connect with your contact. + No comment provided by engineer. + + + People can connect to you only via the links you share. + No comment provided by engineer. + + + Periodically + No comment provided by engineer. + + + Permanent decryption error + message decrypt error item + + + Please ask your contact to enable sending voice messages. + No comment provided by engineer. + + + Please check that you used the correct link or ask your contact to send you another one. + No comment provided by engineer. + + + Please check your network connection with %@ and try again. + No comment provided by engineer. + + + Please check yours and your contact preferences. + No comment provided by engineer. + + + Please contact group admin. + No comment provided by engineer. + + + Please enter correct current passphrase. + No comment provided by engineer. + + + Please enter the previous password after restoring database backup. This action can not be undone. + No comment provided by engineer. + + + Please remember or store it securely - there is no way to recover a lost passcode! + No comment provided by engineer. + + + Please report it to the developers. + No comment provided by engineer. + + + Please restart the app and migrate the database to enable push notifications. + No comment provided by engineer. + + + Please store passphrase securely, you will NOT be able to access chat if you lose it. + No comment provided by engineer. + + + Please store passphrase securely, you will NOT be able to change it if you lose it. + No comment provided by engineer. + + + Polish interface + No comment provided by engineer. + + + Possibly, certificate fingerprint in server address is incorrect + server test error + + + Preserve the last message draft, with attachments. + No comment provided by engineer. + + + Preset server + No comment provided by engineer. + + + Preset server address + No comment provided by engineer. + + + Preview + No comment provided by engineer. + + + Privacy & security + No comment provided by engineer. + + + Privacy redefined + No comment provided by engineer. + + + Private filenames + No comment provided by engineer. + + + Profile and server connections + No comment provided by engineer. + + + Profile image + No comment provided by engineer. + + + Profile password + No comment provided by engineer. + + + Profile update will be sent to your contacts. + No comment provided by engineer. + + + Prohibit audio/video calls. + No comment provided by engineer. + + + Prohibit irreversible message deletion. + No comment provided by engineer. + + + Prohibit message reactions. + No comment provided by engineer. + + + Prohibit messages reactions. + No comment provided by engineer. + + + Prohibit sending direct messages to members. + No comment provided by engineer. + + + Prohibit sending disappearing messages. + No comment provided by engineer. + + + Prohibit sending voice messages. + No comment provided by engineer. + + + Protect app screen + No comment provided by engineer. + + + Protect your chat profiles with a password! + No comment provided by engineer. + + + Protocol timeout + No comment provided by engineer. + + + Push notifications + No comment provided by engineer. + + + Rate the app + No comment provided by engineer. + + + React... + chat item menu + + + Read + No comment provided by engineer. + + + Read more + No comment provided by engineer. + + + Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). + No comment provided by engineer. + + + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). + No comment provided by engineer. + + + Read more in our GitHub repository. + No comment provided by engineer. + + + Read more in our [GitHub repository](https://github.com/simplex-chat/simplex-chat#readme). + No comment provided by engineer. + + + Received at + No comment provided by engineer. + + + Received at: %@ + copied message info + + + Received file event + notification + + + Received message + message info title + + + Receiving address will be changed to a different server. Address change will complete after sender comes online. + No comment provided by engineer. + + + Receiving file will be stopped. + No comment provided by engineer. + + + Receiving via + No comment provided by engineer. + + + Recipients see updates as you type them. + No comment provided by engineer. + + + Record updated at + No comment provided by engineer. + + + Record updated at: %@ + copied message info + + + Reduced battery usage + No comment provided by engineer. + + + Reject + reject incoming call via notification + + + Reject contact (sender NOT notified) + No comment provided by engineer. + + + Reject contact request + No comment provided by engineer. + + + Relay server is only used if necessary. Another party can observe your IP address. + No comment provided by engineer. + + + Relay server protects your IP address, but it can observe the duration of the call. + No comment provided by engineer. + + + Remove + No comment provided by engineer. + + + Remove member + No comment provided by engineer. + + + Remove member? + No comment provided by engineer. + + + Remove passphrase from keychain? + No comment provided by engineer. + + + Reply + chat item action + + + Required + No comment provided by engineer. + + + Reset + No comment provided by engineer. + + + Reset colors + No comment provided by engineer. + + + Reset to defaults + No comment provided by engineer. + + + Restart the app to create a new chat profile + No comment provided by engineer. + + + Restart the app to use imported chat database + No comment provided by engineer. + + + Restore + No comment provided by engineer. + + + Restore database backup + No comment provided by engineer. + + + Restore database backup? + No comment provided by engineer. + + + Restore database error + No comment provided by engineer. + + + Reveal + chat item action + + + Revert + No comment provided by engineer. + + + Revoke + No comment provided by engineer. + + + Revoke file + cancel file action + + + Revoke file? + No comment provided by engineer. + + + Role + No comment provided by engineer. + + + Run chat + No comment provided by engineer. + + + SMP servers + No comment provided by engineer. + + + Save + chat item action + + + Save (and notify contacts) + No comment provided by engineer. + + + Save and notify contact + No comment provided by engineer. + + + Save and notify group members + No comment provided by engineer. + + + Save and update group profile + No comment provided by engineer. + + + Save archive + No comment provided by engineer. + + + Save auto-accept settings + No comment provided by engineer. + + + Save group profile + No comment provided by engineer. + + + Save passphrase and open chat + No comment provided by engineer. + + + Save passphrase in Keychain + No comment provided by engineer. + + + Save preferences? + No comment provided by engineer. + + + Save profile password + No comment provided by engineer. + + + Save servers + No comment provided by engineer. + + + Save servers? + No comment provided by engineer. + + + Save settings? + No comment provided by engineer. + + + Save welcome message? + No comment provided by engineer. + + + Saved WebRTC ICE servers will be removed + No comment provided by engineer. + + + Scan QR code + No comment provided by engineer. + + + Scan code + No comment provided by engineer. + + + Scan security code from your contact's app. + No comment provided by engineer. + + + Scan server QR code + No comment provided by engineer. + + + Search + No comment provided by engineer. + + + Secure queue + server test step + + + Security assessment + No comment provided by engineer. + + + Security code + No comment provided by engineer. + + + Select + No comment provided by engineer. + + + Self-destruct + No comment provided by engineer. + + + Self-destruct passcode + No comment provided by engineer. + + + Self-destruct passcode changed! + No comment provided by engineer. + + + Self-destruct passcode enabled! + No comment provided by engineer. + + + Send + No comment provided by engineer. + + + Send a live message - it will update for the recipient(s) as you type it + No comment provided by engineer. + + + Send direct message + No comment provided by engineer. + + + Send disappearing message + No comment provided by engineer. + + + Send link previews + No comment provided by engineer. + + + Send live message + No comment provided by engineer. + + + Send notifications + No comment provided by engineer. + + + Send notifications: + No comment provided by engineer. + + + Send questions and ideas + No comment provided by engineer. + + + Send them from gallery or custom keyboards. + No comment provided by engineer. + + + Sender cancelled file transfer. + No comment provided by engineer. + + + Sender may have deleted the connection request. + No comment provided by engineer. + + + Sending file will be stopped. + No comment provided by engineer. + + + Sending via + No comment provided by engineer. + + + Sent at + No comment provided by engineer. + + + Sent at: %@ + copied message info + + + Sent file event + notification + + + Sent message + message info title + + + Sent messages will be deleted after set time. + No comment provided by engineer. + + + Server requires authorization to create queues, check password + server test error + + + Server requires authorization to upload, check password + server test error + + + Server test failed! + No comment provided by engineer. + + + Servers + No comment provided by engineer. + + + Set 1 day + No comment provided by engineer. + + + Set contact name… + No comment provided by engineer. + + + Set group preferences + No comment provided by engineer. + + + Set it instead of system authentication. + No comment provided by engineer. + + + Set passcode + No comment provided by engineer. + + + Set passphrase to export + No comment provided by engineer. + + + Set the message shown to new members! + No comment provided by engineer. + + + Set timeouts for proxy/VPN + No comment provided by engineer. + + + Settings + No comment provided by engineer. + + + Share + chat item action + + + Share 1-time link + No comment provided by engineer. + + + Share address + No comment provided by engineer. + + + Share address with contacts? + No comment provided by engineer. + + + Share link + No comment provided by engineer. + + + Share one-time invitation link + No comment provided by engineer. + + + Share with contacts + No comment provided by engineer. + + + Show calls in phone history + No comment provided by engineer. + + + Show developer options + No comment provided by engineer. + + + Show preview + No comment provided by engineer. + + + Show: + No comment provided by engineer. + + + SimpleX Address + No comment provided by engineer. + + + SimpleX Chat security was audited by Trail of Bits. + No comment provided by engineer. + + + SimpleX Lock + No comment provided by engineer. + + + SimpleX Lock mode + No comment provided by engineer. + + + SimpleX Lock not enabled! + No comment provided by engineer. + + + SimpleX Lock turned on + No comment provided by engineer. + + + SimpleX address + No comment provided by engineer. + + + SimpleX contact address + simplex link type + + + SimpleX encrypted message or connection event + notification + + + SimpleX group link + simplex link type + + + SimpleX links + No comment provided by engineer. + + + SimpleX one-time invitation + simplex link type + + + Skip + No comment provided by engineer. + + + Skipped messages + No comment provided by engineer. + + + Some non-fatal errors occurred during import - you may see Chat console for more details. + No comment provided by engineer. + + + Somebody + notification title + + + Start a new chat + No comment provided by engineer. + + + Start chat + No comment provided by engineer. + + + Start migration + No comment provided by engineer. + + + Stop + No comment provided by engineer. + + + Stop SimpleX + authentication reason + + + Stop chat to enable database actions + No comment provided by engineer. + + + Stop chat to export, import or delete chat database. You will not be able to receive and send messages while the chat is stopped. + No comment provided by engineer. + + + Stop chat? + No comment provided by engineer. + + + Stop file + cancel file action + + + Stop receiving file? + No comment provided by engineer. + + + Stop sending file? + No comment provided by engineer. + + + Stop sharing + No comment provided by engineer. + + + Stop sharing address? + No comment provided by engineer. + + + Submit + No comment provided by engineer. + + + Support SimpleX Chat + No comment provided by engineer. + + + System + No comment provided by engineer. + + + System authentication + No comment provided by engineer. + + + TCP connection timeout + No comment provided by engineer. + + + TCP_KEEPCNT + No comment provided by engineer. + + + TCP_KEEPIDLE + No comment provided by engineer. + + + TCP_KEEPINTVL + No comment provided by engineer. + + + Take picture + No comment provided by engineer. + + + Tap button + No comment provided by engineer. + + + Tap to activate profile. + No comment provided by engineer. + + + Tap to join + No comment provided by engineer. + + + Tap to join incognito + No comment provided by engineer. + + + Tap to start a new chat + No comment provided by engineer. + + + Test failed at step %@. + server test failure + + + Test server + No comment provided by engineer. + + + Test servers + No comment provided by engineer. + + + Tests failed! + No comment provided by engineer. + + + Thank you for installing SimpleX Chat! + No comment provided by engineer. + + + Thanks to the users – [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! + No comment provided by engineer. + + + Thanks to the users – contribute via Weblate! + No comment provided by engineer. + + + The 1st platform without any user identifiers – private by design. + No comment provided by engineer. + + + The ID of the next message is incorrect (less or equal to the previous). +It can happen because of some bug or when the connection is compromised. + No comment provided by engineer. + + + The app can notify you when you receive messages or contact requests - please open settings to enable. + No comment provided by engineer. + + + The attempt to change database passphrase was not completed. + No comment provided by engineer. + + + The connection you accepted will be cancelled! + No comment provided by engineer. + + + The contact you shared this link with will NOT be able to connect! + No comment provided by engineer. + + + The created archive is available via app Settings / Database / Old database archive. + No comment provided by engineer. + + + The group is fully decentralized – it is visible only to the members. + No comment provided by engineer. + + + The hash of the previous message is different. + No comment provided by engineer. + + + The message will be deleted for all members. + No comment provided by engineer. + + + The message will be marked as moderated for all members. + No comment provided by engineer. + + + The next generation of private messaging + No comment provided by engineer. + + + The old database was not removed during the migration, it can be deleted. + No comment provided by engineer. + + + The profile is only shared with your contacts. + No comment provided by engineer. + + + The sender will NOT be notified + No comment provided by engineer. + + + The servers for new connections of your current chat profile **%@**. + No comment provided by engineer. + + + Theme + No comment provided by engineer. + + + There should be at least one user profile. + No comment provided by engineer. + + + There should be at least one visible user profile. + 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. + No comment provided by engineer. + + + This action cannot be undone - the messages sent and received earlier than selected will be deleted. It may take several minutes. + No comment provided by engineer. + + + This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost. + No comment provided by engineer. + + + This error is permanent for this connection, please re-connect. + No comment provided by engineer. + + + This group no longer exists. + No comment provided by engineer. + + + This setting applies to messages in your current chat profile **%@**. + No comment provided by engineer. + + + To ask any questions and to receive updates: + No comment provided by engineer. + + + To connect, your contact can scan QR code or use the link in the app. + No comment provided by engineer. + + + To find the profile used for an incognito connection, tap the contact or group name on top of the chat. + No comment provided by engineer. + + + To make a new connection + No comment provided by engineer. + + + To protect privacy, instead of user IDs used by all other platforms, SimpleX has identifiers for message queues, separate for each of your contacts. + No comment provided by engineer. + + + To protect timezone, image/voice files use UTC. + No comment provided by engineer. + + + To protect your information, turn on SimpleX Lock. +You will be prompted to complete authentication before this feature is enabled. + No comment provided by engineer. + + + To record voice message please grant permission to use Microphone. + No comment provided by engineer. + + + To reveal your hidden profile, enter a full password into a search field in **Your chat profiles** page. + No comment provided by engineer. + + + To support instant push notifications the chat database has to be migrated. + No comment provided by engineer. + + + To verify end-to-end encryption with your contact compare (or scan) the code on your devices. + No comment provided by engineer. + + + Transport isolation + No comment provided by engineer. + + + Trying to connect to the server used to receive messages from this contact (error: %@). + No comment provided by engineer. + + + Trying to connect to the server used to receive messages from this contact. + No comment provided by engineer. + + + Turn off + No comment provided by engineer. + + + Turn off notifications? + No comment provided by engineer. + + + Turn on + No comment provided by engineer. + + + Unable to record voice message + No comment provided by engineer. + + + Unexpected error: %@ + No comment provided by engineer. + + + Unexpected migration state + No comment provided by engineer. + + + Unfav. + No comment provided by engineer. + + + Unhide + No comment provided by engineer. + + + Unhide chat profile + No comment provided by engineer. + + + Unhide profile + No comment provided by engineer. + + + Unit + No comment provided by engineer. + + + Unknown caller + callkit banner + + + Unknown database error: %@ + No comment provided by engineer. + + + Unknown error + No comment provided by engineer. + + + Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions. + No comment provided by engineer. + + + Unless your contact deleted the connection or this link was already used, it might be a bug - please report it. +To connect, please ask your contact to create another connection link and check that you have a stable network connection. + No comment provided by engineer. + + + Unlock + No comment provided by engineer. + + + Unlock app + authentication reason + + + Unmute + No comment provided by engineer. + + + Unread + No comment provided by engineer. + + + Update + No comment provided by engineer. + + + Update .onion hosts setting? + No comment provided by engineer. + + + Update database passphrase + No comment provided by engineer. + + + Update network settings? + No comment provided by engineer. + + + Update transport isolation mode? + No comment provided by engineer. + + + Updating settings will re-connect the client to all servers. + No comment provided by engineer. + + + Updating this setting will re-connect the client to all servers. + No comment provided by engineer. + + + Upgrade and open chat + No comment provided by engineer. + + + Upload file + server test step + + + Use .onion hosts + No comment provided by engineer. + + + Use SimpleX Chat servers? + No comment provided by engineer. + + + Use chat + No comment provided by engineer. + + + Use for new connections + No comment provided by engineer. + + + Use iOS call interface + No comment provided by engineer. + + + Use server + No comment provided by engineer. + + + User profile + No comment provided by engineer. + + + Using .onion hosts requires compatible VPN provider. + No comment provided by engineer. + + + Using SimpleX Chat servers. + No comment provided by engineer. + + + Verify connection security + No comment provided by engineer. + + + Verify security code + No comment provided by engineer. + + + Via browser + No comment provided by engineer. + + + Video call + No comment provided by engineer. + + + Video will be received when your contact completes uploading it. + No comment provided by engineer. + + + Video will be received when your contact is online, please wait or check later! + No comment provided by engineer. + + + Videos and files up to 1gb + No comment provided by engineer. + + + View security code + No comment provided by engineer. + + + Voice messages + chat feature + + + Voice messages are prohibited in this chat. + No comment provided by engineer. + + + Voice messages are prohibited in this group. + No comment provided by engineer. + + + Voice messages prohibited! + No comment provided by engineer. + + + Voice message… + No comment provided by engineer. + + + Waiting for file + No comment provided by engineer. + + + Waiting for image + No comment provided by engineer. + + + Waiting for video + No comment provided by engineer. + + + Warning: you may lose some data! + No comment provided by engineer. + + + WebRTC ICE servers + No comment provided by engineer. + + + Welcome %@! + No comment provided by engineer. + + + Welcome message + No comment provided by engineer. + + + What's new + No comment provided by engineer. + + + When available + No comment provided by engineer. + + + When people request to connect, you can accept or reject it. + 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 optional welcome message. + No comment provided by engineer. + + + Wrong database passphrase + No comment provided by engineer. + + + Wrong passphrase! + No comment provided by engineer. + + + XFTP servers + No comment provided by engineer. + + + You + No comment provided by engineer. + + + You accepted connection + No comment provided by engineer. + + + You allow + No comment provided by engineer. + + + You already have a chat profile with the same display name. Please choose another name. + No comment provided by engineer. + + + You are already connected to %@. + No comment provided by engineer. + + + You are connected to the server used to receive messages from this contact. + No comment provided by engineer. + + + You are invited to group + No comment provided by engineer. + + + You can accept calls from lock screen, without device and app authentication. + No comment provided by engineer. + + + You can also connect by clicking the link. If it opens in the browser, click **Open in mobile app** button. + No comment provided by engineer. + + + You can create it later + No comment provided by engineer. + + + You can hide or mute a user profile - swipe it to the right. + No comment provided by engineer. + + + You can now send messages to %@ + notification body + + + You can set lock screen notification preview via settings. + No comment provided by engineer. + + + You can share a link or a QR code - anybody will be able to join the group. You won't lose members of the group if you later delete it. + No comment provided by engineer. + + + You can share this address with your contacts to let them connect with **%@**. + No comment provided by engineer. + + + You can share your address as a link or QR code - anybody can connect to you. + No comment provided by engineer. + + + You can start chat via app Settings / Database or by restarting the app + No comment provided by engineer. + + + You can turn on SimpleX Lock via Settings. + No comment provided by engineer. + + + You can use markdown to format messages: + No comment provided by engineer. + + + You can't send messages! + No comment provided by engineer. + + + You control through which server(s) **to receive** the messages, your contacts – the servers you use to message them. + No comment provided by engineer. + + + You could not be verified; please try again. + No comment provided by engineer. + + + You have no chats + No comment provided by engineer. + + + You have to enter passphrase every time the app starts - it is not stored on the device. + No comment provided by engineer. + + + You invited your contact + No comment provided by engineer. + + + You joined this group + No comment provided by engineer. + + + You joined this group. Connecting to inviting group member. + No comment provided by engineer. + + + You must use the most recent version of your chat database on one device ONLY, otherwise you may stop receiving the messages from some contacts. + No comment provided by engineer. + + + You need to allow your contact to send voice messages to be able to send them. + No comment provided by engineer. + + + You rejected group invitation + No comment provided by engineer. + + + You sent group invitation + No comment provided by engineer. + + + You will be connected to group when the group host's device is online, please wait or check later! + No comment provided by engineer. + + + You will be connected when your connection request is accepted, please wait or check later! + No comment provided by engineer. + + + You will be connected when your contact's device is online, please wait or check later! + No comment provided by engineer. + + + You will be required to authenticate when you start or resume the app after 30 seconds in background. + No comment provided by engineer. + + + You will join a group this link refers to and connect to its group members. + No comment provided by engineer. + + + You will still receive calls and notifications from muted profiles when they are active. + No comment provided by engineer. + + + You will stop receiving messages from this group. Chat history will be preserved. + No comment provided by engineer. + + + You won't lose your contacts if you later delete your address. + No comment provided by engineer. + + + You're trying to invite contact with whom you've shared an incognito profile to the group in which you're using your main profile + No comment provided by engineer. + + + You're using an incognito profile for this group - to prevent sharing your main profile inviting contacts is not allowed + No comment provided by engineer. + + + Your %@ servers + No comment provided by engineer. + + + Your ICE servers + No comment provided by engineer. + + + Your SMP servers + No comment provided by engineer. + + + Your SimpleX address + No comment provided by engineer. + + + Your XFTP servers + No comment provided by engineer. + + + Your calls + No comment provided by engineer. + + + Your chat database + No comment provided by engineer. + + + Your chat database is not encrypted - set passphrase to encrypt it. + No comment provided by engineer. + + + Your chat profile will be sent to group members + No comment provided by engineer. + + + Your chat profile will be sent to your contact + No comment provided by engineer. + + + Your chat profiles + No comment provided by engineer. + + + Your contact needs to be online for the connection to complete. +You can cancel this connection and remove the contact (and try later with a new link). + No comment provided by engineer. + + + Your contact sent a file that is larger than currently supported maximum size (%@). + No comment provided by engineer. + + + Your contacts can allow full message deletion. + No comment provided by engineer. + + + Your contacts in SimpleX will see it. +You can change it in Settings. + No comment provided by engineer. + + + Your contacts will remain connected. + No comment provided by engineer. + + + Your current chat database will be DELETED and REPLACED with the imported one. + No comment provided by engineer. + + + Your current profile + No comment provided by engineer. + + + Your preferences + No comment provided by engineer. + + + Your privacy + No comment provided by engineer. + + + Your profile is stored on your device and shared only with your contacts. +SimpleX servers cannot see your profile. + No comment provided by engineer. + + + Your profile will be sent to the contact that you received this link from + No comment provided by engineer. + + + Your profile, contacts and delivered messages are stored on your device. + No comment provided by engineer. + + + Your random profile + No comment provided by engineer. + + + Your server + No comment provided by engineer. + + + Your server address + No comment provided by engineer. + + + Your settings + No comment provided by engineer. + + + [Contribute](https://github.com/simplex-chat/simplex-chat#contribute) + No comment provided by engineer. + + + [Send us email](mailto:chat@simplex.chat) + No comment provided by engineer. + + + [Star on GitHub](https://github.com/simplex-chat/simplex-chat) + No comment provided by engineer. + + + \_italic_ + No comment provided by engineer. + + + \`a + b` + No comment provided by engineer. + + + above, then choose: + No comment provided by engineer. + + + accepted call + call status + + + admin + member role + + + always + pref value + + + audio call (not e2e encrypted) + No comment provided by engineer. + + + bad message ID + integrity error chat item + + + bad message hash + integrity error chat item + + + bold + No comment provided by engineer. + + + call error + call status + + + call in progress + call status + + + calling… + call status + + + cancelled %@ + feature offered item + + + changed address for you + chat item text + + + changed role of %1$@ to %2$@ + rcv group event chat item + + + changed your role to %@ + rcv group event chat item + + + changing address for %@... + chat item text + + + changing address... + chat item text + + + colored + No comment provided by engineer. + + + complete + No comment provided by engineer. + + + connect to SimpleX Chat developers. + No comment provided by engineer. + + + connected + No comment provided by engineer. + + + connecting + No comment provided by engineer. + + + connecting (accepted) + No comment provided by engineer. + + + connecting (announced) + No comment provided by engineer. + + + connecting (introduced) + No comment provided by engineer. + + + connecting (introduction invitation) + No comment provided by engineer. + + + connecting call… + call status + + + connecting… + chat list item title + + + connection established + chat list item title (it should not be shown + + + connection:%@ + connection information + + + contact has e2e encryption + No comment provided by engineer. + + + contact has no e2e encryption + No comment provided by engineer. + + + creator + No comment provided by engineer. + + + custom + dropdown time picker choice + + + database version is newer than the app, but no down migration for: %@ + No comment provided by engineer. + + + days + time unit + + + default (%@) + pref value + + + deleted + deleted chat item + + + deleted group + rcv group event chat item + + + different migration in the app/database: %@ / %@ + No comment provided by engineer. + + + direct + connection level description + + + duplicate message + integrity error chat item + + + e2e encrypted + No comment provided by engineer. + + + enabled + enabled status + + + enabled for contact + enabled status + + + enabled for you + enabled status + + + ended + No comment provided by engineer. + + + ended call %@ + call status + + + error + No comment provided by engineer. + + + group deleted + No comment provided by engineer. + + + group profile updated + snd group event chat item + + + hours + time unit + + + iOS Keychain is used to securely store passphrase - it allows receiving push notifications. + No comment provided by engineer. + + + iOS Keychain will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving push notifications. + No comment provided by engineer. + + + incognito via contact address link + chat list item description + + + incognito via group link + chat list item description + + + incognito via one-time link + chat list item description + + + indirect (%d) + connection level description + + + invalid chat + invalid chat data + + + invalid chat data + No comment provided by engineer. + + + invalid data + invalid chat item + + + invitation to group %@ + group name + + + invited + No comment provided by engineer. + + + invited %@ + rcv group event chat item + + + invited to connect + chat list item title + + + invited via your group link + rcv group event chat item + + + italic + No comment provided by engineer. + + + join as %@ + No comment provided by engineer. + + + left + rcv group event chat item + + + marked deleted + marked deleted chat item preview text + + + member + member role + + + connected + rcv group event chat item + + + message received + notification + + + minutes + time unit + + + missed call + call status + + + moderated + moderated chat item + + + moderated by %@ + No comment provided by engineer. + + + months + time unit + + + never + No comment provided by engineer. + + + new message + notification + + + no + pref value + + + no e2e encryption + No comment provided by engineer. + + + no text + copied message info in history + + + observer + member role + + + off + enabled status + group pref value + + + offered %@ + feature offered item + + + offered %1$@: %2$@ + feature offered item + + + on + group pref value + + + or chat with the developers + No comment provided by engineer. + + + owner + member role + + + peer-to-peer + No comment provided by engineer. + + + received answer… + No comment provided by engineer. + + + received confirmation… + No comment provided by engineer. + + + rejected call + call status + + + removed + No comment provided by engineer. + + + removed %@ + rcv group event chat item + + + removed you + rcv group event chat item + + + sec + network option + + + seconds + time unit + + + secret + No comment provided by engineer. + + + starting… + No comment provided by engineer. + + + strike + No comment provided by engineer. + + + this contact + notification title + + + unknown + connection info + + + updated group profile + rcv group event chat item + + + v%@ (%@) + No comment provided by engineer. + + + via contact address link + chat list item description + + + via group link + chat list item description + + + via one-time link + chat list item description + + + via relay + No comment provided by engineer. + + + video call (not e2e encrypted) + No comment provided by engineer. + + + waiting for answer… + No comment provided by engineer. + + + waiting for confirmation… + No comment provided by engineer. + + + wants to connect to you! + No comment provided by engineer. + + + weeks + time unit + + + yes + pref value + + + you are invited to group + No comment provided by engineer. + + + you are observer + No comment provided by engineer. + + + you changed address + chat item text + + + you changed address for %@ + chat item text + + + you changed role for yourself to %@ + snd group event chat item + + + you changed role of %1$@ to %2$@ + snd group event chat item + + + you left + snd group event chat item + + + you removed %@ + snd group event chat item + + + you shared one-time link + chat list item description + + + you shared one-time link incognito + chat list item description + + + you: + No comment provided by engineer. + + + \~strike~ + No comment provided by engineer. + + +
+ +
+ +
+ + + SimpleX + Bundle name + + + SimpleX needs camera access to scan QR codes to connect to other users and for video calls. + Privacy - Camera Usage Description + + + SimpleX uses Face ID for local authentication + Privacy - Face ID Usage Description + + + SimpleX needs microphone access for audio and video calls, and to record voice messages. + Privacy - Microphone Usage Description + + + SimpleX needs access to Photo Library for saving captured and received media + Privacy - Photo Library Additions Usage Description + + +
+ +
+ +
+ + + SimpleX NSE + Bundle display name + + + SimpleX NSE + Bundle name + + + Copyright © 2022 SimpleX Chat. All rights reserved. + Copyright (human-readable) + + +
+
diff --git a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff index 2a6abac15c..e3665ba9ca 100644 --- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff +++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff @@ -587,6 +587,10 @@ Povolit nevratné smazání odeslaných zpráv. No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Povolit odesílání hlasových zpráv. @@ -2089,6 +2093,18 @@ Soubory a média No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 Konečně je máme! 🚀 @@ -2199,6 +2215,10 @@ Členové skupiny mohou posílat mizící zprávy. No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. Členové skupiny mohou posílat hlasové zprávy. @@ -2927,6 +2947,10 @@ Žádný token zařízení! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! Skupina nebyla nalezena! @@ -3016,6 +3040,10 @@ Předvolby skupiny mohou měnit pouze vlastníci skupiny. No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Pouze majitelé skupin mohou povolit zasílání hlasových zpráv. @@ -3336,6 +3364,10 @@ Zakázat posílání mizících zpráv. No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. Zakázat odesílání hlasových zpráv. diff --git a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff index aaaa35d836..d61d44f11c 100644 --- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff +++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff @@ -402,14 +402,17 @@ Abort + Abbrechen No comment provided by engineer. Abort changing address + Wechsel der Adresse abbrechen No comment provided by engineer. Abort changing address? + Wechsel der Adresse abbrechen? No comment provided by engineer. @@ -495,6 +498,7 @@ Address change will be aborted. Old receiving address will be used. + Der Wechsel der Adresse wird abgebrochen. Die bisherige Adresse wird weiter verwendet. No comment provided by engineer. @@ -587,6 +591,10 @@ Unwiederbringliches löschen von gesendeten Nachrichten erlauben. No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Das Senden von Sprachnachrichten erlauben. @@ -1798,6 +1806,7 @@ Error aborting address change + Fehler beim Abbrechen des Adresswechsels No comment provided by engineer. @@ -2062,6 +2071,7 @@ Favorite + Favorit No comment provided by engineer. @@ -2089,6 +2099,18 @@ Dateien & Medien No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 Endlich haben wir sie! 🚀 @@ -2199,6 +2221,10 @@ Gruppenmitglieder können verschwindende Nachrichten senden. No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. Gruppenmitglieder können Sprachnachrichten versenden. @@ -2579,7 +2605,7 @@ KeyChain error - Keystore Fehler + KeyChain Fehler No comment provided by engineer. @@ -2927,6 +2953,10 @@ Kein Geräte-Token! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! Die Gruppe wurde nicht gefunden! @@ -3016,6 +3046,10 @@ Gruppenpräferenzen können nur von Gruppen-Eigentümern geändert werden. No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Sprachnachrichten können nur von Gruppen-Eigentümern aktiviert werden. @@ -3336,6 +3370,10 @@ Das Senden von verschwindenden Nachrichten verbieten. No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. Das Senden von Sprachnachrichten nicht erlauben. @@ -3423,6 +3461,7 @@ Receiving address will be changed to a different server. Address change will complete after sender comes online. + Die Empfängeradresse wird auf einen anderen Server geändert. Der Adresswechsel wird abgeschlossen, wenn der Absender wieder online ist. No comment provided by engineer. @@ -4441,6 +4480,7 @@ Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funkt Unfav. + Unfav. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff index 71853107f7..8dd0f99e0b 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -591,6 +591,11 @@ Allow to irreversibly delete sent messages. No comment provided by engineer. + + Allow to send files and media. + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Allow to send voice messages. @@ -2095,6 +2100,21 @@ Files & media No comment provided by engineer. + + Files and media + Files and media + chat feature + + + Files and media are prohibited in this group. + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 Finally, we have them! 🚀 @@ -2205,6 +2225,11 @@ Group members can send disappearing messages. No comment provided by engineer. + + Group members can send files and media. + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. Group members can send voice messages. @@ -2933,6 +2958,11 @@ No device token! No comment provided by engineer. + + No filtered chats + No filtered chats + No comment provided by engineer. + Group not found! Group not found! @@ -3022,6 +3052,11 @@ Only group owners can change group preferences. No comment provided by engineer. + + Only group owners can enable files and media. + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Only group owners can enable voice messages. @@ -3342,6 +3377,11 @@ Prohibit sending disappearing messages. No comment provided by engineer. + + Prohibit sending files and media. + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. Prohibit sending voice messages. diff --git a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff index 91aa560ab7..eded7b61c6 100644 --- a/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff +++ b/apps/ios/SimpleX Localizations/es.xcloc/Localized Contents/es.xliff @@ -587,6 +587,10 @@ Se permite la eliminación irreversible de mensajes. No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Permites enviar mensajes de voz. @@ -2089,6 +2093,18 @@ Archivos y multimedia No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 ¡Por fin los tenemos! 🚀 @@ -2199,6 +2215,10 @@ Los miembros del grupo pueden enviar mensajes temporales. No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. Los miembros del grupo pueden enviar mensajes de voz. @@ -2927,6 +2947,10 @@ ¡Sin dispositivo token! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! ¡Grupo no encontrado! @@ -3016,6 +3040,10 @@ Sólo los propietarios pueden modificar las preferencias de grupo. No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Sólo los propietarios pueden activar los mensajes de voz. @@ -3336,6 +3364,10 @@ No se permiten mensajes temporales. No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. No se permiten mensajes de voz. diff --git a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff index 92ae2cbd32..49acc904ba 100644 --- a/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff +++ b/apps/ios/SimpleX Localizations/fr.xcloc/Localized Contents/fr.xliff @@ -402,14 +402,17 @@ Abort + Annuler No comment provided by engineer. Abort changing address + Annuler le changement d'adresse No comment provided by engineer. Abort changing address? + Abandonner le changement d'adresse ? No comment provided by engineer. @@ -495,6 +498,7 @@ Address change will be aborted. Old receiving address will be used. + Le changement d'adresse sera annulé. L'ancienne adresse de réception sera utilisée. No comment provided by engineer. @@ -587,6 +591,10 @@ Autoriser la suppression irréversible de messages envoyés. No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Autoriser l'envoi de messages vocaux. @@ -1798,6 +1806,7 @@ Error aborting address change + Erreur lors de l'annulation du changement d'adresse No comment provided by engineer. @@ -2062,6 +2071,7 @@ Favorite + Favoris No comment provided by engineer. @@ -2089,6 +2099,18 @@ Fichiers & médias No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 Enfin, les voilà ! 🚀 @@ -2199,6 +2221,10 @@ Les membres du groupes peuvent envoyer des messages éphémères. No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. Les membres du groupe peuvent envoyer des messages vocaux. @@ -2927,6 +2953,10 @@ Pas de token d'appareil ! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! Groupe introuvable ! @@ -3016,6 +3046,10 @@ Seuls les propriétaires du groupe peuvent modifier les préférences du groupe. No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Seuls les propriétaires de groupes peuvent activer les messages vocaux. @@ -3336,6 +3370,10 @@ Interdire l’envoi de messages éphémères. No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. Interdire l'envoi de messages vocaux. @@ -3423,6 +3461,7 @@ Receiving address will be changed to a different server. Address change will complete after sender comes online. + L'adresse de réception sera changée pour un autre serveur. Le changement d'adresse sera terminé lorsque l'expéditeur sera en ligne. No comment provided by engineer. @@ -4441,6 +4480,7 @@ Vous serez invité à confirmer l'authentification avant que cette fonction ne s Unfav. + Unfav. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff b/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff index 5972e97ca0..d87da57711 100644 --- a/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff +++ b/apps/ios/SimpleX Localizations/he.xcloc/Localized Contents/he.xliff @@ -222,32 +222,38 @@ Available in v5.1 **הוסיפו איש קשר חדש**: ליצירת קוד QR או קישור חד־פעמיים עבור איש הקשר שלכם. No comment provided by engineer. - + **Create link / QR code** for your contact to use. + **צור קישור / קוד QR** לשימוש איש הקשר שלך. No comment provided by engineer. - + **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. + **יותר פרטי**: בדוק הודעות חדשות כל 20 דקות. אסימון המכשיר משותף עם שרת SimpleX Chat, אך לא כמה אנשי קשר או הודעות יש לך. 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). + **הכי פרטי**: אל תשתמש בשרת ההתראות של SimpleX Chat, בדוק הודעות מעת לעת ברקע (תלוי בתדירות השימוש באפליקציה). No comment provided by engineer. **Paste received link** or open it in the browser and tap **Open in mobile app**. No comment provided by engineer. - + **Please note**: you will NOT be able to recover or change passphrase if you lose it. + **שימו לב**: לא ניתן יהיה לשחזר או לשנות את הסיסמה אם תאבדו אותה. No comment provided by engineer. - + **Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from. + **מומלץ**: אסימון מכשיר והתראות נשלחים לשרת ההתראות של SimpleX Chat, אך לא תוכן ההודעה, גודלה או ממי היא. No comment provided by engineer. - + **Scan QR code**: to connect to your contact in person or via video call. + **סרוק קוד QR**: כדי להתחבר לאיש הקשר שלך באופן אישי או באמצעות שיחת וידאו. No comment provided by engineer. @@ -262,44 +268,52 @@ Available in v5.1 **e2e encrypted** video call No comment provided by engineer. - + \*bold* + \*מובלט* No comment provided by engineer. , No comment provided by engineer. - + . + . No comment provided by engineer. - + 1 day + יום 1 message ttl - + 1 hour + שעה message ttl - + 1 month + חודש message ttl - + 1 week + שבוע message ttl 2 weeks message ttl - + 6 + 6 No comment provided by engineer. - + : + : No comment provided by engineer. @@ -4225,6 +4239,26 @@ SimpleX servers cannot see your profile. %d שבועות time interval + + 1 minute + דקה + No comment provided by engineer. + + + 1-time link + קישור חד־פעמי + No comment provided by engineer. + + + 5 minutes + 5 דקות + No comment provided by engineer. + + + 30 seconds + 30 שניות + No comment provided by engineer. + diff --git a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff index 4677405528..531c5c3fc6 100644 --- a/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff +++ b/apps/ios/SimpleX Localizations/it.xcloc/Localized Contents/it.xliff @@ -402,14 +402,17 @@ Abort + Interrompi No comment provided by engineer. Abort changing address + Interrompi il cambio di indirizzo No comment provided by engineer. Abort changing address? + Interrompere il cambio di indirizzo? No comment provided by engineer. @@ -495,6 +498,7 @@ Address change will be aborted. Old receiving address will be used. + Il cambio di indirizzo verrà interrotto. Verrà usato il vecchio indirizzo di ricezione. No comment provided by engineer. @@ -587,6 +591,10 @@ Permetti di eliminare irreversibilmente i messaggi inviati. No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Permetti l'invio di messaggi vocali. @@ -1798,6 +1806,7 @@ Error aborting address change + Errore nell'interruzione del cambio di indirizzo No comment provided by engineer. @@ -2062,6 +2071,7 @@ Favorite + Preferito No comment provided by engineer. @@ -2089,6 +2099,18 @@ File e multimediali No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 Finalmente le abbiamo! 🚀 @@ -2199,6 +2221,10 @@ I membri del gruppo possono inviare messaggi a tempo. No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. I membri del gruppo possono inviare messaggi vocali. @@ -2927,6 +2953,10 @@ Nessun token del dispositivo! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! Gruppo non trovato! @@ -3016,6 +3046,10 @@ Solo i proprietari del gruppo possono modificarne le preferenze. No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Solo i proprietari del gruppo possono attivare i messaggi vocali. @@ -3336,6 +3370,10 @@ Proibisci l'invio di messaggi a tempo. No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. Proibisci l'invio di messaggi vocali. @@ -3423,6 +3461,7 @@ Receiving address will be changed to a different server. Address change will complete after sender comes online. + L'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell'indirizzo verrà completata dopo che il mittente sarà in linea. No comment provided by engineer. @@ -4441,6 +4480,7 @@ Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzio Unfav. + Non pref. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff index b7f9f92477..ac4f5f55e7 100644 --- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff +++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff @@ -587,6 +587,10 @@ 送信済みメッセージの永久削除を許可する。 No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. 音声メッセージの送信を許可する。 @@ -2088,6 +2092,18 @@ ファイルとメディア No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 No comment provided by engineer. @@ -2197,6 +2213,10 @@ グループのメンバーが消えるメッセージを送信できます。 No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. グループのメンバーが音声メッセージを送信できます。 @@ -2925,6 +2945,10 @@ デバイストークンがありません! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! グループが見つかりません! @@ -3014,6 +3038,10 @@ グループ設定を変えられるのはグループのオーナーだけです。 No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. 音声メッセージを利用可能に設定できるのはグループのオーナーだけです。 @@ -3334,6 +3362,10 @@ 消えるメッセージを使用禁止にする。 No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. 音声メッセージを使用禁止にする。 diff --git a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff index 33216af176..1e4b998e39 100644 --- a/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff +++ b/apps/ios/SimpleX Localizations/nl.xcloc/Localized Contents/nl.xliff @@ -402,14 +402,17 @@ Abort + Afbreken No comment provided by engineer. Abort changing address + Annuleer het wijzigen van het adres No comment provided by engineer. Abort changing address? + Adres wijziging afbreken? No comment provided by engineer. @@ -495,6 +498,7 @@ Address change will be aborted. Old receiving address will be used. + Adres wijziging wordt afgebroken. Het oude ontvangstadres wordt gebruikt. No comment provided by engineer. @@ -587,6 +591,10 @@ Sta toe om verzonden berichten onomkeerbaar te verwijderen. No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Sta toe om spraak berichten te verzenden. @@ -1798,6 +1806,7 @@ Error aborting address change + Fout bij het afbreken van adres wijziging No comment provided by engineer. @@ -2062,6 +2071,7 @@ Favorite + Favoriet No comment provided by engineer. @@ -2089,6 +2099,18 @@ Bestanden en media No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 Eindelijk, we hebben ze! 🚀 @@ -2199,6 +2221,10 @@ Groepsleden kunnen verdwijnende berichten sturen. No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. Groepsleden kunnen spraak berichten verzenden. @@ -2927,6 +2953,10 @@ Geen apparaattoken! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! Groep niet gevonden! @@ -3016,6 +3046,10 @@ Alleen groep eigenaren kunnen groep voorkeuren wijzigen. No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Alleen groep eigenaren kunnen spraak berichten inschakelen. @@ -3336,6 +3370,10 @@ Verbied het verzenden van verdwijnende berichten. No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. Verbieden het verzenden van spraak berichten. @@ -3423,6 +3461,7 @@ Receiving address will be changed to a different server. Address change will complete after sender comes online. + Het ontvangstadres wordt gewijzigd naar een andere server. Adres wijziging wordt voltooid nadat de afzender online is. No comment provided by engineer. @@ -4441,6 +4480,7 @@ U wordt gevraagd de authenticatie te voltooien voordat deze functie wordt ingesc Unfav. + Niet fav. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff index b1cddf6700..c1e7f093ec 100644 --- a/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff +++ b/apps/ios/SimpleX Localizations/pl.xcloc/Localized Contents/pl.xliff @@ -402,14 +402,17 @@ Abort + Przerwij No comment provided by engineer. Abort changing address + Przerwij zmianę adresu No comment provided by engineer. Abort changing address? + Przerwać zmianę adresu? No comment provided by engineer. @@ -495,6 +498,7 @@ Address change will be aborted. Old receiving address will be used. + Zmiana adresu zostanie przerwana. Użyty zostanie stary adres odbiorczy. No comment provided by engineer. @@ -587,6 +591,10 @@ Zezwól na nieodwracalne usunięcie wysłanych wiadomości. No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Zezwól na wysyłanie wiadomości głosowych. @@ -1798,6 +1806,7 @@ Error aborting address change + Błąd przerwania zmiany adresu No comment provided by engineer. @@ -2062,6 +2071,7 @@ Favorite + Ulubione No comment provided by engineer. @@ -2089,6 +2099,18 @@ Pliki i media No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 W końcu je mamy! 🚀 @@ -2199,6 +2221,10 @@ Członkowie grupy mogą wysyłać znikające wiadomości. No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. Członkowie grupy mogą wysyłać wiadomości głosowe. @@ -2927,6 +2953,10 @@ Brak tokenu urządzenia! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! Nie znaleziono grupy! @@ -3016,6 +3046,10 @@ Tylko właściciele grup mogą zmieniać preferencje grupy. No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Tylko właściciele grup mogą włączyć wiadomości głosowe. @@ -3336,6 +3370,10 @@ Zabroń wysyłania znikających wiadomości. No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. Zabroń wysyłania wiadomości głosowych. @@ -3423,6 +3461,7 @@ Receiving address will be changed to a different server. Address change will complete after sender comes online. + Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online. No comment provided by engineer. @@ -4032,6 +4071,7 @@ Some non-fatal errors occurred during import - you may see Chat console for more details. + Podczas importu wystąpiły niekrytyczne błędy - więcej szczegółów można znaleźć w konsoli czatu. No comment provided by engineer. @@ -4440,6 +4480,7 @@ Przed włączeniem tej funkcji zostanie wyświetlony monit uwierzytelniania. Unfav. + Nie ulub. No comment provided by engineer. diff --git a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff index 978251431f..fc697fb463 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -587,6 +587,10 @@ Разрешить необратимо удалять отправленные сообщения. No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. Разрешить отправлять голосовые сообщения. @@ -2089,6 +2093,18 @@ Файлы и медиа No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 Наконец-то, мы их добавили! 🚀 @@ -2199,6 +2215,10 @@ Члены группы могут посылать исчезающие сообщения. No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. Члены группы могут отправлять голосовые сообщения. @@ -2927,6 +2947,10 @@ Отсутствует токен устройства! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! Группа не найдена! @@ -3016,6 +3040,10 @@ Только владельцы группы могут изменять предпочтения группы. No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. Только владельцы группы могут разрешить голосовые сообщения. @@ -3336,6 +3364,10 @@ Запретить посылать исчезающие сообщения. No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. Запретить отправлять голосовые сообщений. diff --git a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff index 0823a735d1..434b19a6de 100644 --- a/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff +++ b/apps/ios/SimpleX Localizations/uk.xcloc/Localized Contents/uk.xliff @@ -1141,657 +1141,819 @@ Видалити повідомлення? No comment provided by engineer. - + Delete messages + Видалити повідомлення No comment provided by engineer. - + Delete messages after + Видаляйте повідомлення після No comment provided by engineer. - + Delete old database + Видалення старої бази даних No comment provided by engineer. - + Delete old database? + Видалити стару базу даних? No comment provided by engineer. - + Delete pending connection + Видалити очікуване з'єднання No comment provided by engineer. - + Delete pending connection? + Видалити очікуване з'єднання? No comment provided by engineer. - + Delete queue + Видалити чергу server test step - + Delete user profile? + Видалити профіль користувача? No comment provided by engineer. - + Description + Опис No comment provided by engineer. - + Develop + Розробник No comment provided by engineer. - + Developer tools + Інструменти для розробників No comment provided by engineer. - + Device + Пристрій No comment provided by engineer. - + Device authentication is disabled. Turning off SimpleX Lock. + Автентифікацію пристрою вимкнено. Вимкнення SimpleX Lock. No comment provided by engineer. - + Device authentication is not enabled. You can turn on SimpleX Lock via Settings, once you enable device authentication. + Автентифікація пристрою не ввімкнена. Ви можете увімкнути SimpleX Lock у Налаштуваннях, коли увімкнете автентифікацію пристрою. No comment provided by engineer. - + Different names, avatars and transport isolation. + Різні імена, аватарки та транспортна ізоляція. No comment provided by engineer. - + Direct messages + Прямі повідомлення chat feature - + Direct messages between members are prohibited in this group. + У цій групі заборонені прямі повідомлення між учасниками. No comment provided by engineer. - + Disable SimpleX Lock + Вимкнути SimpleX Lock authentication reason - + Disappearing messages + Зникаючі повідомлення chat feature - + Disappearing messages are prohibited in this chat. + Зникаючі повідомлення в цьому чаті заборонені. No comment provided by engineer. - + Disappearing messages are prohibited in this group. + У цій групі заборонено зникаючі повідомлення. No comment provided by engineer. - + Disconnect + Від'єднати server test step - + Display name + Відображуване ім'я No comment provided by engineer. - + Display name: + Відображуване ім'я: No comment provided by engineer. - + Do NOT use SimpleX for emergency calls. + НЕ використовуйте SimpleX для екстрених викликів. No comment provided by engineer. - + Do it later + Зробіть це пізніше No comment provided by engineer. - + Duplicate display name! + Дублююче ім'я користувача! No comment provided by engineer. - + Edit + Редагувати chat item action - + Edit group profile + Редагування профілю групи No comment provided by engineer. - + Enable + Увімкнути No comment provided by engineer. - + Enable SimpleX Lock + Увімкнути SimpleX Lock authentication reason - + Enable TCP keep-alive + Увімкнути TCP keep-alive No comment provided by engineer. - + Enable automatic message deletion? + Увімкнути автоматичне видалення повідомлень? No comment provided by engineer. - + Enable instant notifications? + Увімкнути миттєві сповіщення? No comment provided by engineer. - + Enable notifications + Увімкнути сповіщення No comment provided by engineer. - + Enable periodic notifications? + Увімкнути періодичні сповіщення? No comment provided by engineer. - + Encrypt + Зашифрувати No comment provided by engineer. - + Encrypt database? + Зашифрувати базу даних? No comment provided by engineer. - + Encrypted database + Зашифрована база даних No comment provided by engineer. - + Encrypted message or another event + Зашифроване повідомлення або інша подія notification - + Encrypted message: database error + Зашифроване повідомлення: помилка бази даних notification - + Encrypted message: keychain error + Зашифроване повідомлення: помилка ланцюжка ключів notification - + Encrypted message: no passphrase + Зашифроване повідомлення: без ключової фрази notification - + Encrypted message: unexpected error + Зашифроване повідомлення: несподівана помилка notification - + Enter correct passphrase. + Введіть правильну парольну фразу. No comment provided by engineer. - + Enter passphrase… + Введіть пароль… No comment provided by engineer. - + Enter server manually + Увійдіть на сервер вручну No comment provided by engineer. - + Error + Помилка No comment provided by engineer. - + Error accepting contact request + Помилка при прийнятті запиту на контакт No comment provided by engineer. - + Error accessing database file + Помилка доступу до файлу бази даних No comment provided by engineer. - + Error adding member(s) + Помилка додавання користувача(ів) No comment provided by engineer. - + Error changing address + Помилка зміни адреси No comment provided by engineer. - + Error changing role + Помилка зміни ролі No comment provided by engineer. - + Error changing setting + Помилка зміни налаштування No comment provided by engineer. - + Error creating address + Помилка створення адреси No comment provided by engineer. - + Error creating group + Помилка створення групи No comment provided by engineer. - + Error creating group link + Помилка створення посилання на групу No comment provided by engineer. - + Error creating profile! + Помилка створення профілю! No comment provided by engineer. - + Error deleting chat database + Помилка видалення бази даних чату No comment provided by engineer. - + Error deleting chat! + Помилка видалення чату! No comment provided by engineer. - + Error deleting connection + Помилка видалення з'єднання No comment provided by engineer. - + Error deleting contact + Помилка видалення контакту No comment provided by engineer. - + Error deleting database + Помилка видалення бази даних No comment provided by engineer. - + Error deleting old database + Помилка видалення старої бази даних No comment provided by engineer. - + Error deleting token + Помилка видалення токена No comment provided by engineer. - + Error deleting user profile + Помилка видалення профілю користувача No comment provided by engineer. - + Error enabling notifications + Помилка увімкнення сповіщень No comment provided by engineer. - + Error encrypting database + Помилка шифрування бази даних No comment provided by engineer. - + Error exporting chat database + Помилка експорту бази даних чату No comment provided by engineer. - + Error importing chat database + Помилка імпорту бази даних чату No comment provided by engineer. - + Error joining group + Помилка приєднання до групи No comment provided by engineer. - + Error receiving file + Помилка отримання файлу No comment provided by engineer. - + Error removing member + Помилка видалення учасника No comment provided by engineer. - + Error saving ICE servers + Помилка збереження серверів ICE No comment provided by engineer. Error saving SMP servers No comment provided by engineer. - + Error saving group profile + Помилка збереження профілю групи No comment provided by engineer. - + Error saving passphrase to keychain + Помилка збереження пароля на keychain No comment provided by engineer. - + Error sending message + Помилка надсилання повідомлення No comment provided by engineer. - + Error starting chat + Помилка запуску чату No comment provided by engineer. - + Error stopping chat + Помилка зупинки чату No comment provided by engineer. - + Error switching profile! + Помилка перемикання профілю! No comment provided by engineer. - + Error updating group link + Помилка оновлення посилання на групу No comment provided by engineer. - + Error updating message + Повідомлення про помилку оновлення No comment provided by engineer. - + Error updating settings + Помилка оновлення налаштувань No comment provided by engineer. - + Error: %@ + Помилка: %@ No comment provided by engineer. - + Error: URL is invalid + Помилка: URL-адреса невірна No comment provided by engineer. - + Error: no database file + Помилка: немає файлу бази даних No comment provided by engineer. - + Exit without saving + Вихід без збереження No comment provided by engineer. - + Export database + Експорт бази даних No comment provided by engineer. - + Export error: + Помилка експорту: No comment provided by engineer. - + Exported database archive. + Експортований архів бази даних. No comment provided by engineer. - + Exporting database archive... + Експорт архіву бази даних... No comment provided by engineer. - + Failed to remove passphrase + Не вдалося видалити парольну фразу No comment provided by engineer. - + File will be received when your contact is online, please wait or check later! + Файл буде отримано, коли ваш контакт буде онлайн, будь ласка, зачекайте або перевірте пізніше! No comment provided by engineer. - + File: %@ + Файл: %@ No comment provided by engineer. - + Files & media + Файли та медіа No comment provided by engineer. - + For console + Для консолі No comment provided by engineer. - + French interface + Французький інтерфейс No comment provided by engineer. - + Full link + Повне посилання No comment provided by engineer. - + Full name (optional) + Повне ім'я (необов'язково) No comment provided by engineer. - + Full name: + Повне ім'я: No comment provided by engineer. - + GIFs and stickers + GIF-файли та наклейки No comment provided by engineer. - + Group + Група No comment provided by engineer. - + Group display name + Назва групи для відображення No comment provided by engineer. - + Group full name (optional) + Повна назва групи (необов'язково) No comment provided by engineer. - + Group image + Зображення групи No comment provided by engineer. - + Group invitation + Групове запрошення No comment provided by engineer. - + Group invitation expired + Термін дії групового запрошення закінчився No comment provided by engineer. - + Group invitation is no longer valid, it was removed by sender. + Групове запрошення більше не дійсне, воно було видалено відправником. No comment provided by engineer. - + Group link + Посилання на групу No comment provided by engineer. - + Group links + Групові посилання No comment provided by engineer. - + Group members can irreversibly delete sent messages. + Учасники групи можуть безповоротно видаляти надіслані повідомлення. No comment provided by engineer. - + Group members can send direct messages. + Учасники групи можуть надсилати прямі повідомлення. No comment provided by engineer. - + Group members can send disappearing messages. + Учасники групи можуть надсилати зникаючі повідомлення. No comment provided by engineer. - + Group members can send voice messages. + Учасники групи можуть надсилати голосові повідомлення. No comment provided by engineer. - + Group message: + Групове повідомлення: notification - + Group preferences + Параметри груп No comment provided by engineer. - + Group profile + Профіль групи No comment provided by engineer. - + Group profile is stored on members' devices, not on the servers. + Профіль групи зберігається на пристроях учасників, а не на серверах. No comment provided by engineer. - + Group will be deleted for all members - this cannot be undone! + Група буде видалена для всіх учасників - це неможливо скасувати! No comment provided by engineer. - + Group will be deleted for you - this cannot be undone! + Група буде видалена для вас - це не може бути скасовано! No comment provided by engineer. - + Help + Довідка No comment provided by engineer. - + Hidden + Приховано No comment provided by engineer. - + Hide + Приховати chat item action - + Hide app screen in the recent apps. + Приховати екран програми в останніх програмах. No comment provided by engineer. - + How SimpleX works + Як працює SimpleX No comment provided by engineer. - + How it works + Як це працює No comment provided by engineer. - + How to + Як зробити No comment provided by engineer. - + How to use it + Як ним користуватися No comment provided by engineer. - + How to use your servers + Як користуватися вашими серверами No comment provided by engineer. - + ICE servers (one per line) + Сервери ICE (по одному на лінію) No comment provided by engineer. If you can't meet in person, **show QR code in the video call**, or share the link. No comment provided by engineer. - + If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link. + Якщо ви не можете зустрітися особисто, ви можете **сканувати QR-код у відеодзвінку**, або ваш контакт може поділитися посиланням на запрошення. No comment provided by engineer. - + If you need to use the chat now tap **Do it later** below (you will be offered to migrate the database when you restart the app). + Якщо вам потрібно скористатися чатом зараз, натисніть **Зробити це пізніше** нижче (вам буде запропоновано перенести базу даних при перезапуску програми). No comment provided by engineer. - + Ignore + Ігнорувати No comment provided by engineer. - + Image will be received when your contact is online, please wait or check later! + Зображення буде отримано, коли ваш контакт буде онлайн, будь ласка, зачекайте або перевірте пізніше! No comment provided by engineer. - + Immune to spam and abuse + Імунітет до спаму та зловживань No comment provided by engineer. - + Import + Імпорт No comment provided by engineer. - + Import chat database? + Імпортувати базу даних чату? No comment provided by engineer. - + Import database + Імпорт бази даних No comment provided by engineer. - + Improved privacy and security + Покращена конфіденційність та безпека No comment provided by engineer. - + Improved server configuration + Покращена конфігурація сервера No comment provided by engineer. - + Incognito + Інкогніто No comment provided by engineer. - + Incognito mode + Режим інкогніто No comment provided by engineer. - + Incognito mode is not supported here - your main profile will be sent to group members + Режим інкогніто тут не підтримується - ваш основний профіль буде надіслано учасникам групи No comment provided by engineer. - + Incognito mode protects the privacy of your main profile name and image — for each new contact a new random profile is created. + Режим інкогніто захищає конфіденційність імені та зображення вашого основного профілю - для кожного нового контакту створюється новий випадковий профіль. No comment provided by engineer. - + Incoming audio call + Вхідний аудіовиклик notification - + Incoming call + Вхідний дзвінок notification - + Incoming video call + Вхідний відеодзвінок notification - + Incorrect security code! + Неправильний код безпеки! No comment provided by engineer. - + Install [SimpleX Chat for terminal](https://github.com/simplex-chat/simplex-chat) + Встановіть [SimpleX Chat для терміналу] (https://github.com/simplex-chat/simplex-chat) No comment provided by engineer. - + Instant push notifications will be hidden! + Миттєві пуш-сповіщення будуть приховані! + No comment provided by engineer. - + Instantly + Миттєво No comment provided by engineer. - + Interface + Інтерфейс No comment provided by engineer. - + Invalid connection link + Неправильне посилання для підключення No comment provided by engineer. - + Invalid server address! + Неправильна адреса сервера! No comment provided by engineer. - + Invitation expired! + Термін дії запрошення закінчився! No comment provided by engineer. - + Invite members + Запросити учасників No comment provided by engineer. - + Invite to group + Запросити до групи No comment provided by engineer. - + Irreversible message deletion + Безповоротне видалення повідомлення No comment provided by engineer. - + Irreversible message deletion is prohibited in this chat. + У цьому чаті заборонено безповоротне видалення повідомлень. No comment provided by engineer. - + Irreversible message deletion is prohibited in this group. + У цій групі заборонено безповоротне видалення повідомлень. No comment provided by engineer. - + It allows having many anonymous connections without any shared data between them in a single chat profile. + Це дозволяє мати багато анонімних з'єднань без будь-яких спільних даних між ними в одному профілі чату. No comment provided by engineer. @@ -1803,1174 +1965,1464 @@ Please connect to the developers via Settings to receive the updates about the s We will be adding server redundancy to prevent lost messages. No comment provided by engineer. - + It seems like you are already connected via this link. If it is not the case, there was an error (%@). + Схоже, що ви вже підключені за цим посиланням. Якщо це не так, сталася помилка (%@). No comment provided by engineer. - + Italian interface + Італійський інтерфейс No comment provided by engineer. - + Join + Приєднуйтесь No comment provided by engineer. - + Join group + Приєднуйтесь до групи No comment provided by engineer. - + Join incognito + Приєднуйтесь інкогніто No comment provided by engineer. - + Joining group + Приєднання до групи No comment provided by engineer. - + Keychain error + Помилка KeyChain No comment provided by engineer. - + LIVE + НАЖИВО No comment provided by engineer. - + Large file! + Великий файл! No comment provided by engineer. - + Leave + Залишити No comment provided by engineer. - + Leave group + Покинути групу No comment provided by engineer. - + Leave group? + Покинути групу? No comment provided by engineer. - + Light + Світлий No comment provided by engineer. - + Limitations + Обмеження No comment provided by engineer. - + Live message! + Живе повідомлення! No comment provided by engineer. - + Live messages + Живі повідомлення No comment provided by engineer. - + Local name + Місцева назва No comment provided by engineer. - + Local profile data only + Тільки локальні дані профілю No comment provided by engineer. - + Make a private connection + Створіть приватне з'єднання No comment provided by engineer. Make sure SMP server addresses are in correct format, line separated and are not duplicated (%@). No comment provided by engineer. - + Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated. + Переконайтеся, що адреси серверів WebRTC ICE мають правильний формат, розділені рядками і не дублюються. No comment provided by engineer. - + Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?* + Багато людей запитували: *якщо SimpleX не має ідентифікаторів користувачів, як він може доставляти повідомлення?* No comment provided by engineer. - + Mark deleted for everyone + Позначити видалено для всіх No comment provided by engineer. - + Mark read + Позначити прочитано No comment provided by engineer. - + Mark verified + Позначити перевірено No comment provided by engineer. - + Markdown in messages + Виправлення в повідомленнях No comment provided by engineer. - + Max 30 seconds, received instantly. + Максимум 30 секунд, отримується миттєво. No comment provided by engineer. - + Member + Учасник No comment provided by engineer. - + Member role will be changed to "%@". All group members will be notified. + Роль учасника буде змінено на "%@". Всі учасники групи будуть повідомлені про це. No comment provided by engineer. - + Member role will be changed to "%@". The member will receive a new invitation. + Роль учасника буде змінено на "%@". Учасник отримає нове запрошення. No comment provided by engineer. - + Member will be removed from group - this cannot be undone! + Учасник буде видалений з групи - це неможливо скасувати! No comment provided by engineer. - + Message delivery error + Помилка доставки повідомлення No comment provided by engineer. - + Message draft + Чернетка повідомлення No comment provided by engineer. - + Message text + Текст повідомлення No comment provided by engineer. - + Messages + Повідомлення No comment provided by engineer. - + Migrating database archive... + Перенесення архіву бази даних... No comment provided by engineer. - + Migration error: + Помилка міграції: No comment provided by engineer. - + Migration failed. Tap **Skip** below to continue using the current database. Please report the issue to the app developers via chat or email [chat@simplex.chat](mailto:chat@simplex.chat). + Міграція не вдалася. Натисніть **Пропустити** нижче, щоб продовжити використовувати поточну базу даних. Будь ласка, повідомте про проблему розробникам програми через чат або електронну пошту [chat@simplex.chat](mailto:chat@simplex.chat). No comment provided by engineer. - + Migration is completed + Міграцію завершено No comment provided by engineer. - + Moderate + Модерується chat item action - + More improvements are coming soon! + Незабаром буде ще більше покращень! No comment provided by engineer. - + Most likely this contact has deleted the connection with you. + Швидше за все, цей контакт видалив зв'язок з вами. No comment provided by engineer. - + Multiple chat profiles + Кілька профілів чату No comment provided by engineer. - + Mute + Вимкнути звук No comment provided by engineer. - + Name + Ім'я No comment provided by engineer. - + Network & servers + Мережа та сервери No comment provided by engineer. - + Network settings + Налаштування мережі No comment provided by engineer. - + Network status + Стан мережі No comment provided by engineer. - + New contact request + Новий запит на контакт notification - + New contact: + Новий контакт: notification - + New database archive + Новий архів бази даних No comment provided by engineer. - + New in %@ + Нове в %@ No comment provided by engineer. - + New member role + Нова роль учасника No comment provided by engineer. - + New message + Нове повідомлення notification - + New passphrase… + Новий пароль… No comment provided by engineer. - + No + Ні No comment provided by engineer. - + No contacts selected + Не вибрано жодного контакту No comment provided by engineer. - + No contacts to add + Немає контактів для додавання No comment provided by engineer. - + No device token! + Токен пристрою відсутній! No comment provided by engineer. - + Group not found! + Групу не знайдено! No comment provided by engineer. - + No permission to record voice message + Немає дозволу на запис голосового повідомлення No comment provided by engineer. - + No received or sent files + Немає отриманих або відправлених файлів No comment provided by engineer. - + Notifications + Сповіщення No comment provided by engineer. - + Notifications are disabled! + Сповіщення вимкнено! No comment provided by engineer. - + Off (Local) + Вимкнено (локально) No comment provided by engineer. - + Ok + Гаразд No comment provided by engineer. - + Old database + Стара база даних No comment provided by engineer. - + Old database archive + Старий архів бази даних No comment provided by engineer. - + One-time invitation link + Посилання на одноразове запрошення No comment provided by engineer. - + Onion hosts will be required for connection. Requires enabling VPN. + Для підключення будуть потрібні хости onion. Потрібно увімкнути VPN. No comment provided by engineer. - + Onion hosts will be used when available. Requires enabling VPN. + Onion хости будуть використовуватися, коли вони будуть доступні. Потрібно увімкнути VPN. No comment provided by engineer. - + Onion hosts will not be used. + Onion хости не будуть використовуватися. No comment provided by engineer. - + Only client devices store user profiles, contacts, groups, and messages sent with **2-layer end-to-end encryption**. + Тільки клієнтські пристрої зберігають профілі користувачів, контакти, групи та повідомлення, надіслані за допомогою **2-шарового наскрізного шифрування**. No comment provided by engineer. - + Only group owners can change group preferences. + Тільки власники груп можуть змінювати налаштування групи. No comment provided by engineer. - + Only group owners can enable voice messages. + Тільки власники груп можуть вмикати голосові повідомлення. No comment provided by engineer. - + Only you can irreversibly delete messages (your contact can mark them for deletion). + Тільки ви можете безповоротно видалити повідомлення (ваш контакт може позначити їх для видалення). No comment provided by engineer. - + Only you can send disappearing messages. + Тільки ви можете надсилати зникаючі повідомлення. No comment provided by engineer. - + Only you can send voice messages. + Тільки ви можете надсилати голосові повідомлення. No comment provided by engineer. - + Only your contact can irreversibly delete messages (you can mark them for deletion). + Тільки ваш контакт може безповоротно видалити повідомлення (ви можете позначити їх для видалення). No comment provided by engineer. - + Only your contact can send disappearing messages. + Тільки ваш контакт може надсилати зникаючі повідомлення. No comment provided by engineer. - + Only your contact can send voice messages. + Тільки ваш контакт може надсилати голосові повідомлення. No comment provided by engineer. - + Open Settings + Відкрийте Налаштування No comment provided by engineer. - + Open chat + Відкритий чат No comment provided by engineer. - + Open chat console + Відкрийте консоль чату authentication reason - + Open user profiles + Відкрити профілі користувачів authentication reason - + Open-source protocol and code – anybody can run the servers. + Протокол і код з відкритим вихідним кодом - будь-хто може запускати сервери. No comment provided by engineer. - + Opening the link in the browser may reduce connection privacy and security. Untrusted SimpleX links will be red. + Відкриття посилання в браузері може знизити конфіденційність і безпеку з'єднання. Ненадійні посилання SimpleX будуть червоного кольору. No comment provided by engineer. - + PING count + Кількість PING No comment provided by engineer. - + PING interval + Інтервал PING No comment provided by engineer. - + Paste + Вставити No comment provided by engineer. - + Paste image + Вставити зображення No comment provided by engineer. - + Paste received link + Вставте отримане посилання No comment provided by engineer. - + Paste the link you received into the box below to connect with your contact. + Вставте отримане посилання у поле нижче, щоб зв'язатися з вашим контактом. No comment provided by engineer. - + People can connect to you only via the links you share. + Люди можуть зв'язатися з вами лише за посиланнями, якими ви ділитеся. No comment provided by engineer. - + Periodically + Періодично No comment provided by engineer. - + Please ask your contact to enable sending voice messages. + Будь ласка, попросіть вашого контакту увімкнути відправку голосових повідомлень. No comment provided by engineer. - + Please check that you used the correct link or ask your contact to send you another one. + Будь ласка, перевірте, чи ви скористалися правильним посиланням, або попросіть контактну особу надіслати вам інше. No comment provided by engineer. - + Please check your network connection with %@ and try again. + Будь ласка, перевірте підключення до мережі за допомогою %@ і спробуйте ще раз. No comment provided by engineer. - + Please check yours and your contact preferences. + Будь ласка, перевірте свої та контактні налаштування. No comment provided by engineer. - + Please contact group admin. + Зверніться до адміністратора групи. No comment provided by engineer. - + Please enter correct current passphrase. + Будь ласка, введіть правильний поточний пароль. No comment provided by engineer. - + Please enter the previous password after restoring database backup. This action can not be undone. + Будь ласка, введіть попередній пароль після відновлення резервної копії бази даних. Ця дія не може бути скасована. No comment provided by engineer. - + Please restart the app and migrate the database to enable push notifications. + Будь ласка, перезапустіть додаток і перенесіть базу даних, щоб увімкнути push-сповіщення. No comment provided by engineer. - + Please store passphrase securely, you will NOT be able to access chat if you lose it. + Будь ласка, зберігайте пароль надійно, ви НЕ зможете отримати доступ до чату, якщо втратите його. No comment provided by engineer. - + Please store passphrase securely, you will NOT be able to change it if you lose it. + Будь ласка, зберігайте пароль надійно, ви НЕ зможете змінити його, якщо втратите. No comment provided by engineer. - + Possibly, certificate fingerprint in server address is incorrect + Можливо, в адресі сервера неправильно вказано відбиток сертифіката server test error - + Preserve the last message draft, with attachments. + Зберегти чернетку останнього повідомлення з вкладеннями. No comment provided by engineer. - + Preset server + Попередньо встановлений сервер No comment provided by engineer. - + Preset server address + Попередньо встановлена адреса сервера No comment provided by engineer. - + Privacy & security + Конфіденційність і безпека No comment provided by engineer. - + Privacy redefined + Конфіденційність переглянута No comment provided by engineer. - + Private filenames + Приватні імена файлів No comment provided by engineer. - + Profile and server connections + З'єднання профілю та сервера No comment provided by engineer. - + Profile image + Зображення профілю No comment provided by engineer. - + Prohibit irreversible message deletion. + Заборонити незворотне видалення повідомлень. No comment provided by engineer. - + Prohibit sending direct messages to members. + Заборонити надсилати прямі повідомлення учасникам. No comment provided by engineer. - + Prohibit sending disappearing messages. + Заборонити надсилання зникаючих повідомлень. No comment provided by engineer. - + Prohibit sending voice messages. + Заборонити надсилання голосових повідомлень. No comment provided by engineer. - + Protect app screen + Захистіть екран програми No comment provided by engineer. - + Protocol timeout + Тайм-аут протоколу No comment provided by engineer. - + Push notifications + Push-повідомлення No comment provided by engineer. - + Rate the app + Оцініть додаток No comment provided by engineer. - + Read + Читати No comment provided by engineer. - + Read more in our GitHub repository. + Читайте більше в нашому репозиторії на GitHub. No comment provided by engineer. - + Read more in our [GitHub repository](https://github.com/simplex-chat/simplex-chat#readme). + Читайте більше в нашому [GitHub репозиторії] (https://github.com/simplex-chat/simplex-chat#readme). No comment provided by engineer. - + Received file event + Подія отримання файлу notification - + Receiving via + Отримання через No comment provided by engineer. - + Recipients see updates as you type them. + Одержувачі бачать оновлення, коли ви їх вводите. No comment provided by engineer. - + Reduced battery usage + Зменшення використання акумулятора No comment provided by engineer. - + Reject + Відхилити reject incoming call via notification - + Reject contact (sender NOT notified) + Відхилити контакт (відправника НЕ повідомлено) No comment provided by engineer. - + Reject contact request + Відхилити запит на контакт No comment provided by engineer. - + Relay server is only used if necessary. Another party can observe your IP address. + Релейний сервер використовується тільки в разі потреби. Інша сторона може бачити вашу IP-адресу. No comment provided by engineer. - + Relay server protects your IP address, but it can observe the duration of the call. + Сервер ретрансляції захищає вашу IP-адресу, але він може спостерігати за тривалістю дзвінка. No comment provided by engineer. - + Remove + Видалити No comment provided by engineer. - + Remove member + Видалити учасника No comment provided by engineer. - + Remove member? + Видалити учасника? No comment provided by engineer. - + Remove passphrase from keychain? + Видалити парольну фразу з брелока? No comment provided by engineer. - + Reply + Відповісти chat item action - + Required + Потрібно No comment provided by engineer. - + Reset + Перезавантаження No comment provided by engineer. - + Reset colors + Скинути кольори No comment provided by engineer. - + Reset to defaults + Відновити налаштування за замовчуванням No comment provided by engineer. - + Restart the app to create a new chat profile + Перезапустіть програму, щоб створити новий профіль чату No comment provided by engineer. - + Restart the app to use imported chat database + Перезапустіть програму, щоб використовувати імпортовану базу даних чату No comment provided by engineer. - + Restore + Відновити No comment provided by engineer. - + Restore database backup + Відновлення резервної копії бази даних No comment provided by engineer. - + Restore database backup? + Відновити резервну копію бази даних? No comment provided by engineer. - + Restore database error + Відновлення помилки бази даних No comment provided by engineer. - + Reveal + Показувати chat item action - + Revert + Повернутися No comment provided by engineer. - + Role + Роль No comment provided by engineer. - + Run chat + Запустити чат No comment provided by engineer. - + SMP servers + Сервери SMP No comment provided by engineer. - + Save + Зберегти chat item action - + Save (and notify contacts) + Зберегти (і повідомити контактам) No comment provided by engineer. - + Save and notify contact + Зберегти та повідомити контакт No comment provided by engineer. - + Save and notify group members + Зберегти та повідомити учасників групи No comment provided by engineer. - + Save archive + Зберегти архів No comment provided by engineer. - + Save group profile + Зберегти профіль групи No comment provided by engineer. - + Save passphrase and open chat + Збережіть пароль і відкрийте чат No comment provided by engineer. - + Save passphrase in Keychain + Збережіть парольну фразу в Keychain No comment provided by engineer. - + Save preferences? + Зберегти налаштування? No comment provided by engineer. - + Save servers + Зберегти сервери No comment provided by engineer. - + Saved WebRTC ICE servers will be removed + Збережені сервери WebRTC ICE буде видалено No comment provided by engineer. - + Scan QR code + Відскануйте QR-код No comment provided by engineer. - + Scan code + Сканувати код No comment provided by engineer. - + Scan security code from your contact's app. + Відскануйте код безпеки з додатку вашого контакту. No comment provided by engineer. - + Scan server QR code + Відскануйте QR-код сервера No comment provided by engineer. - + Search + Пошук No comment provided by engineer. - + Secure queue + Безпечна черга server test step - + Security assessment + Оцінка безпеки No comment provided by engineer. - + Security code + Код безпеки No comment provided by engineer. - + Send + Надіслати No comment provided by engineer. - + Send a live message - it will update for the recipient(s) as you type it + Надішліть повідомлення в реальному часі - воно буде оновлюватися для одержувача (одержувачів), поки ви його вводите No comment provided by engineer. - + Send direct message + Надішліть пряме повідомлення No comment provided by engineer. - + Send link previews + Надіслати попередній перегляд за посиланням No comment provided by engineer. - + Send live message + Надіслати живе повідомлення No comment provided by engineer. - + Send notifications + Надсилати сповіщення No comment provided by engineer. - + Send notifications: + Надсилати сповіщення: No comment provided by engineer. - + Send questions and ideas + Надсилайте запитання та ідеї No comment provided by engineer. - + Send them from gallery or custom keyboards. + Надсилайте їх із галереї чи власних клавіатур. No comment provided by engineer. - + Sender cancelled file transfer. + Відправник скасував передачу файлу. No comment provided by engineer. - + Sender may have deleted the connection request. + Можливо, відправник видалив запит на підключення. No comment provided by engineer. - + Sending via + Надсилання через No comment provided by engineer. - + Sent file event + Подія надісланого файлу notification - + Sent messages will be deleted after set time. + Надіслані повідомлення будуть видалені через встановлений час. No comment provided by engineer. - + Server requires authorization to create queues, check password + Сервер вимагає авторизації для створення черг, перевірте пароль server test error - + Server test failed! + Тест сервера завершився невдало! No comment provided by engineer. - + Servers + Сервери No comment provided by engineer. - + Set 1 day + Встановити 1 день No comment provided by engineer. - + Set contact name… + Встановити ім'я контакту… No comment provided by engineer. - + Set group preferences + Встановіть налаштування групи No comment provided by engineer. - + Set passphrase to export + Встановити ключову фразу для експорту No comment provided by engineer. - + Set timeouts for proxy/VPN + Встановлення таймаутів для проксі/VPN No comment provided by engineer. - + Settings + Налаштування No comment provided by engineer. - + Share + Поділіться chat item action Share invitation link No comment provided by engineer. - + Share link + Поділіться посиланням No comment provided by engineer. - + Share one-time invitation link + Поділіться посиланням на одноразове запрошення No comment provided by engineer. Show QR code No comment provided by engineer. - + Show calls in phone history + Показувати дзвінки в історії дзвінків No comment provided by engineer. - + Show preview + Показати попередній перегляд No comment provided by engineer. - + SimpleX Chat security was audited by Trail of Bits. + Безпека SimpleX Chat була перевірена компанією Trail of Bits. No comment provided by engineer. - + SimpleX Lock + SimpleX Lock No comment provided by engineer. - + SimpleX Lock turned on + SimpleX Lock увімкнено No comment provided by engineer. - + SimpleX contact address + Контактна адреса SimpleX simplex link type - + SimpleX encrypted message or connection event + Зашифроване повідомлення SimpleX або подія підключення notification - + SimpleX group link + Посилання на групу SimpleX simplex link type - + SimpleX links + Посилання SimpleX No comment provided by engineer. - + SimpleX one-time invitation + Одноразове запрошення SimpleX simplex link type - + Skip + Пропустити No comment provided by engineer. - + Skipped messages + Пропущені повідомлення No comment provided by engineer. - + Somebody + Хтось notification title - + Start a new chat + Почніть новий чат No comment provided by engineer. - + Start chat + Почати чат No comment provided by engineer. - + Start migration + Почати міграцію No comment provided by engineer. - + Stop + Зупинити No comment provided by engineer. - + Stop SimpleX + Зупинити SimpleX authentication reason - + Stop chat to enable database actions + Зупиніть чат, щоб увімкнути дії з базою даних No comment provided by engineer. - + Stop chat to export, import or delete chat database. You will not be able to receive and send messages while the chat is stopped. + Зупиніть чат, щоб експортувати, імпортувати або видалити базу даних чату. Ви не зможете отримувати та надсилати повідомлення, поки чат зупинено. No comment provided by engineer. - + Stop chat? + Зупинити чат? No comment provided by engineer. - + Support SimpleX Chat + Підтримка чату SimpleX No comment provided by engineer. - + System + Система No comment provided by engineer. - + TCP connection timeout + Тайм-аут TCP-з'єднання No comment provided by engineer. - + TCP_KEEPCNT + TCP_KEEPCNT No comment provided by engineer. - + TCP_KEEPIDLE + TCP_KEEPIDLE No comment provided by engineer. - + TCP_KEEPINTVL + TCP_KEEPINTVL No comment provided by engineer. - + Take picture + Сфотографуйте No comment provided by engineer. - + Tap button + Натисніть кнопку No comment provided by engineer. - + Tap to join + Натисніть, щоб приєднатися No comment provided by engineer. - + Tap to join incognito + Натисніть, щоб приєднатися інкогніто No comment provided by engineer. - + Tap to start a new chat + Натисніть, щоб почати новий чат No comment provided by engineer. - + Test failed at step %@. + Тест завершився невдало на кроці %@. server test failure - + Test server + Тестовий сервер No comment provided by engineer. - + Test servers + Тестові сервери No comment provided by engineer. - + Tests failed! + Тести не пройшли! No comment provided by engineer. - + Thank you for installing SimpleX Chat! + Дякуємо, що встановили SimpleX Chat! No comment provided by engineer. - + Thanks to the users – [contribute via Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! + Дякуємо користувачам - [внесок через Weblate](https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat)! No comment provided by engineer. - + Thanks to the users – contribute via Weblate! + Дякуємо користувачам - зробіть свій внесок через Weblate! No comment provided by engineer. - + The 1st platform without any user identifiers – private by design. + Перша платформа без жодних ідентифікаторів користувачів – приватна за дизайном. No comment provided by engineer. - + The app can notify you when you receive messages or contact requests - please open settings to enable. + Додаток може сповіщати вас, коли ви отримуєте повідомлення або запити на контакт - будь ласка, відкрийте налаштування, щоб увімкнути цю функцію. No comment provided by engineer. - + The attempt to change database passphrase was not completed. + Спроба змінити пароль до бази даних не була завершена. No comment provided by engineer. - + The connection you accepted will be cancelled! + Прийняте вами з'єднання буде скасовано! No comment provided by engineer. - + The contact you shared this link with will NOT be able to connect! + Контакт, з яким ви поділилися цим посиланням, НЕ зможе підключитися! No comment provided by engineer. - + The created archive is available via app Settings / Database / Old database archive. + Створений архів доступний через Налаштування програми / База даних / Старий архів бази даних. No comment provided by engineer. - + The group is fully decentralized – it is visible only to the members. + Група повністю децентралізована - її бачать лише учасники. No comment provided by engineer. - + The message will be deleted for all members. + Повідомлення буде видалено для всіх учасників. No comment provided by engineer. - + The message will be marked as moderated for all members. + Повідомлення буде позначено як модероване для всіх учасників. No comment provided by engineer. - + The next generation of private messaging + Наступне покоління приватних повідомлень No comment provided by engineer. - + The old database was not removed during the migration, it can be deleted. + Стара база даних не була видалена під час міграції, її можна видалити. No comment provided by engineer. - + The profile is only shared with your contacts. + Профіль доступний лише вашим контактам. No comment provided by engineer. - + The sender will NOT be notified + Відправник НЕ буде повідомлений No comment provided by engineer. - + The servers for new connections of your current chat profile **%@**. + Сервери для нових підключень вашого поточного профілю чату **%@**. No comment provided by engineer. - + Theme + Тема 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. + Цю дію неможливо скасувати - всі отримані та надіслані файли і медіа будуть видалені. Зображення з низькою роздільною здатністю залишаться. No comment provided by engineer. - + This action cannot be undone - the messages sent and received earlier than selected will be deleted. It may take several minutes. + Цю дію неможливо скасувати - повідомлення, надіслані та отримані раніше, ніж вибрані, будуть видалені. Це може зайняти кілька хвилин. No comment provided by engineer. - + This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost. + Цю дію неможливо скасувати - ваш профіль, контакти, повідомлення та файли будуть безповоротно втрачені. No comment provided by engineer. This feature is experimental! It will only work if the other client has version 4.2 installed. You should see the message in the conversation once the address change is completed – please check that you can still receive messages from this contact (or group member). No comment provided by engineer. - + This group no longer exists. + Цієї групи більше не існує. No comment provided by engineer. - + This setting applies to messages in your current chat profile **%@**. + Це налаштування застосовується до повідомлень у вашому поточному профілі чату **%@**. No comment provided by engineer. - + To ask any questions and to receive updates: + Задати будь-які питання та отримувати новини: No comment provided by engineer. - + To find the profile used for an incognito connection, tap the contact or group name on top of the chat. + Щоб знайти профіль, який використовується для з'єднання інкогніто, торкніться імені контакту або групи у верхній частині чату. No comment provided by engineer. - + To make a new connection + Щоб створити нове з'єднання No comment provided by engineer. - + To protect privacy, instead of user IDs used by all other platforms, SimpleX has identifiers for message queues, separate for each of your contacts. + Щоб захистити конфіденційність, замість ідентифікаторів користувачів, які використовуються на всіх інших платформах, SimpleX має ідентифікатори для черг повідомлень, окремі для кожного з ваших контактів. No comment provided by engineer. - + To protect timezone, image/voice files use UTC. + Для захисту часового поясу у файлах зображень/голосу використовується UTC. No comment provided by engineer. - + To protect your information, turn on SimpleX Lock. You will be prompted to complete authentication before this feature is enabled. + Щоб захистити вашу інформацію, увімкніть SimpleX Lock. +Перед увімкненням цієї функції вам буде запропоновано пройти автентифікацію. No comment provided by engineer. - + To record voice message please grant permission to use Microphone. + Щоб записати голосове повідомлення, будь ласка, надайте дозвіл на використання мікрофону. No comment provided by engineer. - + To support instant push notifications the chat database has to be migrated. + Для підтримки миттєвих push-повідомлень необхідно перенести базу даних чату. No comment provided by engineer. - + To verify end-to-end encryption with your contact compare (or scan) the code on your devices. + Щоб перевірити наскрізне шифрування з вашим контактом, порівняйте (або відскануйте) код на ваших пристроях. No comment provided by engineer. - + Transport isolation + Транспортна ізоляція No comment provided by engineer. - + Trying to connect to the server used to receive messages from this contact (error: %@). + Спроба з'єднатися з сервером, який використовується для отримання повідомлень від цього контакту (помилка: %@). No comment provided by engineer. - + Trying to connect to the server used to receive messages from this contact. + Спроба з'єднатися з сервером, який використовується для отримання повідомлень від цього контакту. No comment provided by engineer. - + Turn off + Вимкнути No comment provided by engineer. - + Turn off notifications? + Вимкнути сповіщення? No comment provided by engineer. - + Turn on + Ввімкнути No comment provided by engineer. - + Unable to record voice message + Не вдається записати голосове повідомлення No comment provided by engineer. - + Unexpected error: %@ + Неочікувана помилка: %@ No comment provided by engineer. - + Unexpected migration state + Неочікуваний стан міграції No comment provided by engineer. - + Unknown caller + Невідомий абонент callkit banner - + Unknown database error: %@ + Невідома помилка бази даних: %@ No comment provided by engineer. - + Unknown error + Невідома помилка No comment provided by engineer. - + Unless you use iOS call interface, enable Do Not Disturb mode to avoid interruptions. + Якщо ви не користуєтеся інтерфейсом виклику iOS, увімкніть режим "Не турбувати", щоб уникнути переривань. No comment provided by engineer. - + Unless your contact deleted the connection or this link was already used, it might be a bug - please report it. To connect, please ask your contact to create another connection link and check that you have a stable network connection. + Якщо ваш контакт не видалив з'єднання або якщо це посилання вже використовувалося, це може бути помилкою - будь ласка, повідомте про це. +Щоб підключитися, попросіть вашого контакта створити інше посилання і перевірте, чи маєте ви стабільне з'єднання з мережею. No comment provided by engineer. - + Unlock + Розблокувати authentication reason - + Unmute + Увімкнути звук No comment provided by engineer. - + Unread + Непрочитане No comment provided by engineer. - + Update + Оновлення No comment provided by engineer. - + Update .onion hosts setting? + Оновити налаштування хостів .onion? No comment provided by engineer. - + Update database passphrase + Оновити парольну фразу бази даних No comment provided by engineer. - + Update network settings? + Оновити налаштування мережі? No comment provided by engineer. - + Update transport isolation mode? + Оновити режим транспортної ізоляції? No comment provided by engineer. @@ -4176,6 +4628,853 @@ SimpleX servers cannot see your profile. Всі ваші контакти залишаться на зв'язку. Повідомлення про оновлення профілю буде надіслано вашим контактам. No comment provided by engineer. + + Delete profile + Видалити профіль + No comment provided by engineer. + + + Enable lock + Увімкнути блокування + No comment provided by engineer. + + + Enter Passcode + Введіть пароль + No comment provided by engineer. + + + Error aborting address change + Помилка скасування зміни адреси + No comment provided by engineer. + + + Favorite + Улюблений + No comment provided by engineer. + + + File will be received when your contact completes uploading it. + Файл буде отримано, коли ваш контакт завершить завантаження. + No comment provided by engineer. + + + Further reduced battery usage + Подальше зменшення використання акумулятора + No comment provided by engineer. + + + Group members can add message reactions. + Учасники групи можуть додавати реакції на повідомлення. + No comment provided by engineer. + + + Hidden chat profiles + Приховані профілі чату + No comment provided by engineer. + + + If you can't meet in person, show QR code in a video call, or share the link. + Якщо ви не можете зустрітися особисто, покажіть QR-код у відеодзвінку або поділіться посиланням. + No comment provided by engineer. + + + If you enter your self-destruct passcode while opening the app: + Якщо ви введете пароль самознищення під час відкриття програми: + No comment provided by engineer. + + + Info + Інформація + chat item action + + + Invite friends + Запросити друзів + No comment provided by engineer. + + + Finally, we have them! 🚀 + Нарешті, вони у нас є! 🚀 + No comment provided by engineer. + + + History + Історія + copied message info + + + If you enter this passcode when opening the app, all app data will be irreversibly removed! + Якщо ви введете цей пароль при відкритті програми, всі дані програми будуть безповоротно видалені! + No comment provided by engineer. + + + Image will be received when your contact completes uploading it. + Зображення буде отримано, коли ваш контакт завершить завантаження. + No comment provided by engineer. + + + Don't create address + Не створювати адресу + No comment provided by engineer. + + + Abort changing address? + Скасувати зміну адреси? + No comment provided by engineer. + + + Abort + Скасувати + No comment provided by engineer. + + + Enable self-destruct + Увімкнути самознищення + No comment provided by engineer. + + + Abort changing address + Скасувати зміну адреси + No comment provided by engineer. + + + Address change will be aborted. Old receiving address will be used. + Зміна адреси буде скасована. Буде використано стару адресу отримання. + No comment provided by engineer. + + + Disappearing message + Зникаюче повідомлення + No comment provided by engineer. + + + Disappears at: %@ + Зникає за: %@ + copied message info + + + Enter welcome message… (optional) + Введіть вітальне повідомлення... (необов'язково) + placeholder + + + Enable self-destruct passcode + Увімкнути пароль самознищення + set passcode view + + + Don't show again + Більше не показувати + No comment provided by engineer. + + + Downgrade and open chat + Пониження та відкритий чат + No comment provided by engineer. + + + Download file + Завантажити файл + server test step + + + Enter password above to show! + Введіть пароль вище, щоб показати! + No comment provided by engineer. + + + Error loading %@ servers + Помилка завантаження %@ серверів + No comment provided by engineer. + + + Error saving %@ servers + Помилка збереження %@ серверів + No comment provided by engineer. + + + Error saving passcode + Помилка збереження пароля + No comment provided by engineer. + + + Error saving user password + Помилка збереження пароля користувача + No comment provided by engineer. + + + Error: + Помилка: + No comment provided by engineer. + + + Error updating user privacy + Помилка оновлення конфіденційності користувача + No comment provided by engineer. + + + Fully re-implemented - work in background! + Повністю перероблено - робота у фоновому режимі! + No comment provided by engineer. + + + Group moderation + Модерація груп + No comment provided by engineer. + + + Group welcome message + Привітальне повідомлення групи + No comment provided by engineer. + + + Hidden profile password + Прихований пароль до профілю + No comment provided by engineer. + + + Hide: + Приховати: + No comment provided by engineer. + + + Immediately + Негайно + No comment provided by engineer. + + + Incorrect passcode + Неправильний пароль + PIN entry + + + Incompatible database version + Несумісна версія бази даних + No comment provided by engineer. + + + Initial role + Початкова роль + No comment provided by engineer. + + + Disappears at + Зникає за + No comment provided by engineer. + + + Duration + Тривалість + No comment provided by engineer. + + + Encrypted message: database migration error + Зашифроване повідомлення: помилка міграції бази даних + notification + + + Enter welcome message… + Введіть вітальне повідомлення… + placeholder + + + Error sending email + Помилка надсилання електронного листа + No comment provided by engineer. + + + File will be deleted from servers. + Файл буде видалено з серверів. + No comment provided by engineer. + + + Fast and no wait until the sender is online! + Швидко і без очікування, поки відправник буде онлайн! + No comment provided by engineer. + + + Hide profile + Приховати профіль + No comment provided by engineer. + + + Deleted at: %@ + Видалено за: %@ + copied message info + + + Deleted at + Видалено за + No comment provided by engineer. + + + KeyChain error + Помилка KeyChain + No comment provided by engineer. + + + Lock mode + Режим блокування + No comment provided by engineer. + + + Message reactions + Реакції на повідомлення + chat feature + + + It can happen when you or your connection used the old database backup. + Це може статися, якщо ви або ваше з'єднання використовували стару резервну копію бази даних. + No comment provided by engineer. + + + Learn more + Дізнайтеся більше + No comment provided by engineer. + + + Lock after + Блокування після + No comment provided by engineer. + + + Let's talk in SimpleX Chat + Поговоримо в чаті SimpleX + email subject + + + Japanese interface + Японський інтерфейс + No comment provided by engineer. + + + Make profile private! + Зробіть профіль приватним! + No comment provided by engineer. + + + It can happen when: +1. The messages expired in the sending client after 2 days or on the server after 30 days. +2. Message decryption failed, because you or your contact used old database backup. +3. The connection was compromised. + Це може статися, коли: +1. Термін дії повідомлень закінчився в клієнті-відправнику через 2 дні або на сервері через 30 днів. +2. Не вдалося розшифрувати повідомлення, тому що ви або ваш контакт використовували стару резервну копію бази даних. +3. З'єднання було скомпрометовано. + No comment provided by engineer. + + + Make sure %@ server addresses are in correct format, line separated and are not duplicated (%@). + Переконайтеся, що адреси серверів %@ мають правильний формат, розділені рядками і не дублюються (%@). + No comment provided by engineer. + + + Message reactions are prohibited in this chat. + Реакції на повідомлення в цьому чаті заборонені. + No comment provided by engineer. + + + Message reactions are prohibited in this group. + Реакції на повідомлення в цій групі заборонені. + No comment provided by engineer. + + + Messages & files + Повідомлення та файли + No comment provided by engineer. + + + Only you can make calls. + Дзвонити можете тільки ви. + No comment provided by engineer. + + + Only your contact can make calls. + Тільки ваш контакт може здійснювати дзвінки. + No comment provided by engineer. + + + Please remember or store it securely - there is no way to recover a lost passcode! + Будь ласка, запам'ятайте або надійно зберігайте його - втрачений пароль неможливо відновити! + No comment provided by engineer. + + + New Passcode + Новий пароль + No comment provided by engineer. + + + Save welcome message? + Зберегти вітальне повідомлення? + No comment provided by engineer. + + + Revoke file + Відкликати файл + cancel file action + + + Save auto-accept settings + Зберегти налаштування автоприйому + No comment provided by engineer. + + + Self-destruct + Самознищення + No comment provided by engineer. + + + Self-destruct passcode + Пароль самознищення + No comment provided by engineer. + + + Moderated at: %@ + Модерується за: %@ + copied message info + + + Only you can add message reactions. + Тільки ви можете додавати реакції на повідомлення. + No comment provided by engineer. + + + Only your contact can add message reactions. + Тільки ваш контакт може додавати реакції на повідомлення. + No comment provided by engineer. + + + React... + Реагувати... + chat item menu + + + Received message + Отримано повідомлення + message info title + + + Record updated at + Запис оновлено за + No comment provided by engineer. + + + Record updated at: %@ + Запис оновлено за: %@ + copied message info + + + Revoke + Відкликати + No comment provided by engineer. + + + Revoke file? + Відкликати файл? + No comment provided by engineer. + + + Save profile password + Зберегти пароль профілю + No comment provided by engineer. + + + Select + Виберіть + No comment provided by engineer. + + + Self-destruct passcode enabled! + Пароль самознищення ввімкнено! + No comment provided by engineer. + + + Send disappearing message + Надіслати зникаюче повідомлення + No comment provided by engineer. + + + Muted when inactive! + Вимкнено, коли неактивний! + No comment provided by engineer. + + + No app password + Немає пароля програми + Authentication unavailable + + + Off + Вимкнено + No comment provided by engineer. + + + Passcode changed! + Пароль змінено! + No comment provided by engineer. + + + Passcode + Пароль + No comment provided by engineer. + + + Passcode entry + Введення пароля + No comment provided by engineer. + + + Passcode not changed! + Пароль не змінено! + No comment provided by engineer. + + + Passcode set! + Пароль встановлено! + No comment provided by engineer. + + + Password to show + Показати пароль + No comment provided by engineer. + + + Protect your chat profiles with a password! + Захистіть свої профілі чату паролем! + No comment provided by engineer. + + + Save and update group profile + Збереження та оновлення профілю групи + No comment provided by engineer. + + + New display name + Нове ім'я відображення + No comment provided by engineer. + + + Prohibit message reactions. + Заборонити реакцію на повідомлення. + No comment provided by engineer. + + + Read more in [User Guide](https://simplex.chat/docs/guide/readme.html#connect-to-friends). + Читайте більше в [Посібнику користувача] (https://simplex.chat/docs/guide/readme.html#connect-to-friends). + No comment provided by engineer. + + + Receiving file will be stopped. + Отримання файлу буде зупинено. + No comment provided by engineer. + + + Save servers? + Зберегти сервери? + No comment provided by engineer. + + + Save settings? + Зберегти налаштування? + No comment provided by engineer. + + + Permanent decryption error + Постійна помилка розшифрування + message decrypt error item + + + Please report it to the developers. + Будь ласка, повідомте про це розробникам. + No comment provided by engineer. + + + Polish interface + Польський інтерфейс + No comment provided by engineer. + + + Preview + Попередній перегляд + No comment provided by engineer. + + + Profile password + Пароль до профілю + No comment provided by engineer. + + + Prohibit audio/video calls. + Заборонити аудіо/відеодзвінки. + No comment provided by engineer. + + + Read more in [User Guide](https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). + Читайте більше в [Посібнику користувача] (https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address). + No comment provided by engineer. + + + Moderated at + Модерується на + No comment provided by engineer. + + + Opening database… + Відкриття бази даних… + No comment provided by engineer. + + + Prohibit messages reactions. + Заборонити реакції на повідомлення. + No comment provided by engineer. + + + Received at + Отримано за + No comment provided by engineer. + + + Read more + Читати далі + No comment provided by engineer. + + + Received at: %@ + Отримано за: %@ + copied message info + + + Self-destruct passcode changed! + Пароль самознищення змінено! + No comment provided by engineer. + + + Migrations: %@ + Міграції: %@. + No comment provided by engineer. + + + Now admins can: +- delete members' messages. +- disable members ("observer" role) + Тепер адміністратори можуть +- видаляти повідомлення користувачів. +- відключати користувачів (роль "спостерігач") + No comment provided by engineer. + + + Profile update will be sent to your contacts. + Оновлення профілю буде надіслано вашим контактам. + No comment provided by engineer. + + + Receiving address will be changed to a different server. Address change will complete after sender comes online. + Адреса отримувача буде змінена на інший сервер. Зміна адреси завершиться після того, як відправник з'явиться в мережі. + No comment provided by engineer. + + + Some non-fatal errors occurred during import - you may see Chat console for more details. + Під час імпорту виникли деякі нефатальні помилки – ви можете переглянути консоль чату, щоб дізнатися більше. + No comment provided by engineer. + + + Show: + Показати: + No comment provided by engineer. + + + SimpleX Address + Адреса SimpleX + No comment provided by engineer. + + + Stop file + Зупинити файл + cancel file action + + + There should be at least one user profile. + Повинен бути принаймні один профіль користувача. + No comment provided by engineer. + + + Unfav. + Нелюб. + No comment provided by engineer. + + + Server requires authorization to upload, check password + Сервер вимагає авторизації для завантаження, перевірте пароль + server test error + + + SimpleX Lock mode + Режим SimpleX Lock + No comment provided by engineer. + + + Submit + Надіслати + No comment provided by engineer. + + + System authentication + Автентифікація системи + No comment provided by engineer. + + + Tap to activate profile. + Натисніть, щоб активувати профіль. + No comment provided by engineer. + + + There should be at least one visible user profile. + Повинен бути принаймні один видимий профіль користувача. + No comment provided by engineer. + + + Unhide chat profile + Показати профіль чату + No comment provided by engineer. + + + Unhide profile + Показати профіль + No comment provided by engineer. + + + Unlock app + Розблокувати додаток + authentication reason + + + Sent message + Надіслано повідомлення + message info title + + + Set it instead of system authentication. + Встановіть його замість аутентифікації системи. + No comment provided by engineer. + + + Share 1-time link + Поділитися 1-разовим посиланням + No comment provided by engineer. + + + Share with contacts + Поділіться з контактами + No comment provided by engineer. + + + SimpleX address + Адреса SimpleX + No comment provided by engineer. + + + Stop sharing + Припиніть ділитися + No comment provided by engineer. + + + Stop sharing address? + Припинити ділитися адресою? + No comment provided by engineer. + + + The hash of the previous message is different. + Хеш попереднього повідомлення відрізняється. + No comment provided by engineer. + + + This error is permanent for this connection, please re-connect. + Ця помилка є постійною для цього з'єднання, будь ласка, перепідключіться. + No comment provided by engineer. + + + Unhide + Показати + No comment provided by engineer. + + + Sent at + Надіслано за + No comment provided by engineer. + + + Sent at: %@ + Надіслано за: %@ + copied message info + + + Set the message shown to new members! + Налаштуйте повідомлення, яке показуватиметься новим користувачам! + No comment provided by engineer. + + + Show developer options + Показати опції розробника + No comment provided by engineer. + + + The ID of the next message is incorrect (less or equal to the previous). +It can happen because of some bug or when the connection is compromised. + Ідентифікатор наступного повідомлення неправильний (менше або дорівнює попередньому). +Це може статися через помилку або коли з'єднання скомпрометовано. + No comment provided by engineer. + + + Sending file will be stopped. + Надсилання файлу буде зупинено. + No comment provided by engineer. + + + Set passcode + Встановити пароль + No comment provided by engineer. + + + Share address with contacts? + Поділіться адресою з контактами? + No comment provided by engineer. + + + Share address + Поділитися адресою + No comment provided by engineer. + + + SimpleX Lock not enabled! + SimpleX Lock не ввімкнено! + No comment provided by engineer. + + + Stop receiving file? + Припинити отримання файлу? + No comment provided by engineer. + + + Stop sending file? + Припинити надсилання файлу? + No comment provided by engineer. + + + To connect, your contact can scan QR code or use the link in the app. + Щоб підключитися, ваш контакт може відсканувати QR-код або скористатися посиланням у додатку. + No comment provided by engineer. + + + To reveal your hidden profile, enter a full password into a search field in **Your chat profiles** page. + Щоб відкрити свій прихований профіль, введіть повний пароль у поле пошуку на сторінці **Ваші профілі чату**. + No comment provided by engineer. + + + Unit + Одиниця + No comment provided by engineer. + diff --git a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff index db14b03b3b..ca3cd3052f 100644 --- a/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff +++ b/apps/ios/SimpleX Localizations/zh-Hans.xcloc/Localized Contents/zh-Hans.xliff @@ -402,14 +402,17 @@ Abort + 中止 No comment provided by engineer. Abort changing address + 中止地址更改 No comment provided by engineer. Abort changing address? + 中止地址更改? No comment provided by engineer. @@ -495,6 +498,7 @@ Address change will be aborted. Old receiving address will be used. + 将中止地址更改。将使用旧接收地址。 No comment provided by engineer. @@ -587,6 +591,10 @@ 允许不可撤回地删除已发送消息。 No comment provided by engineer. + + Allow to send files and media. + No comment provided by engineer. + Allow to send voice messages. 允许发送语音消息。 @@ -694,7 +702,7 @@ Audio and video calls - 音视频通话 + 语音和视频通话 No comment provided by engineer. @@ -1798,6 +1806,7 @@ Error aborting address change + 中止地址更改错误 No comment provided by engineer. @@ -2062,6 +2071,7 @@ Favorite + 最喜欢 No comment provided by engineer. @@ -2089,6 +2099,18 @@ 文件和媒体 No comment provided by engineer. + + Files and media + chat feature + + + Files and media are prohibited in this group. + No comment provided by engineer. + + + Files and media prohibited! + No comment provided by engineer. + Finally, we have them! 🚀 终于我们有它们了! 🚀 @@ -2199,6 +2221,10 @@ 群组成员可以发送限时消息。 No comment provided by engineer. + + Group members can send files and media. + No comment provided by engineer. + Group members can send voice messages. 群组成员可以发送语音消息。 @@ -2574,7 +2600,7 @@ Joining group - 加入群组 + 加入群组中 No comment provided by engineer. @@ -2927,6 +2953,10 @@ 无设备令牌! No comment provided by engineer. + + No filtered chats + No comment provided by engineer. + Group not found! 未找到群组! @@ -3016,6 +3046,10 @@ 只有群主可以改变群组偏好设置。 No comment provided by engineer. + + Only group owners can enable files and media. + No comment provided by engineer. + Only group owners can enable voice messages. 只有群主可以启用语音信息。 @@ -3336,6 +3370,10 @@ 禁止发送限时消息。 No comment provided by engineer. + + Prohibit sending files and media. + No comment provided by engineer. + Prohibit sending voice messages. 禁止发送语音消息。 @@ -3423,6 +3461,7 @@ Receiving address will be changed to a different server. Address change will complete after sender comes online. + 接收地址将变更到不同的服务器。地址更改将在发件人上线后完成。 No comment provided by engineer. @@ -4441,6 +4480,7 @@ You will be prompted to complete authentication before this feature is enabled.< Unfav. + 取消最喜欢 No comment provided by engineer. diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index fdb2d5412b..32f9613688 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -115,6 +115,11 @@ 5CC2C0FC2809BF11000C35E3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FA2809BF11000C35E3 /* Localizable.strings */; }; 5CC2C0FF2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FD2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings */; }; 5CC868F329EB540C0017BBFD /* CIRcvDecryptionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */; }; + 5CCAA6DF2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DA2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a */; }; + 5CCAA6E02A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DB2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a */; }; + 5CCAA6E12A53713A00BAF93B /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DC2A53713A00BAF93B /* libgmpxx.a */; }; + 5CCAA6E22A53713A00BAF93B /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DD2A53713A00BAF93B /* libgmp.a */; }; + 5CCAA6E32A53713A00BAF93B /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DE2A53713A00BAF93B /* libffi.a */; }; 5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */; }; 5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* AddContactView.swift */; }; 5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */; }; @@ -165,11 +170,6 @@ 648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; }; 649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; }; 649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; }; - 64A353102A4C84CE007CD71D /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530B2A4C84CE007CD71D /* libgmp.a */; }; - 64A353112A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530C2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a */; }; - 64A353122A4C84CE007CD71D /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530D2A4C84CE007CD71D /* libffi.a */; }; - 64A353132A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530E2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a */; }; - 64A353142A4C84CE007CD71D /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530F2A4C84CE007CD71D /* libgmpxx.a */; }; 64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; }; 64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */; }; 64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */; }; @@ -392,6 +392,11 @@ 5CC2C0FB2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 5CC2C0FE2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = ""; }; 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIRcvDecryptionError.swift; sourceTree = ""; }; + 5CCAA6DA2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a"; sourceTree = ""; }; + 5CCAA6DB2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a"; sourceTree = ""; }; + 5CCAA6DC2A53713A00BAF93B /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 5CCAA6DD2A53713A00BAF93B /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 5CCAA6DE2A53713A00BAF93B /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavStackCompat.swift; sourceTree = ""; }; 5CCD403327A5F6DF00368C90 /* AddContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactView.swift; sourceTree = ""; }; 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanToConnectView.swift; sourceTree = ""; }; @@ -441,11 +446,6 @@ 6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = ""; }; 649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = ""; }; - 64A3530B2A4C84CE007CD71D /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 64A3530C2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a"; sourceTree = ""; }; - 64A3530D2A4C84CE007CD71D /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 64A3530E2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a"; sourceTree = ""; }; - 64A3530F2A4C84CE007CD71D /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextItemView.swift; sourceTree = ""; }; 64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedItemView.swift; sourceTree = ""; }; 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemInfoView.swift; sourceTree = ""; }; @@ -498,12 +498,12 @@ buildActionMask = 2147483647; files = ( 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, - 64A353132A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a in Frameworks */, - 64A353102A4C84CE007CD71D /* libgmp.a in Frameworks */, - 64A353112A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a in Frameworks */, - 64A353122A4C84CE007CD71D /* libffi.a in Frameworks */, + 5CCAA6E12A53713A00BAF93B /* libgmpxx.a in Frameworks */, + 5CCAA6DF2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a in Frameworks */, + 5CCAA6E02A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a in Frameworks */, + 5CCAA6E32A53713A00BAF93B /* libffi.a in Frameworks */, + 5CCAA6E22A53713A00BAF93B /* libgmp.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - 64A353142A4C84CE007CD71D /* libgmpxx.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -564,11 +564,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - 64A3530D2A4C84CE007CD71D /* libffi.a */, - 64A3530B2A4C84CE007CD71D /* libgmp.a */, - 64A3530F2A4C84CE007CD71D /* libgmpxx.a */, - 64A3530E2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a */, - 64A3530C2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a */, + 5CCAA6DE2A53713A00BAF93B /* libffi.a */, + 5CCAA6DD2A53713A00BAF93B /* libgmp.a */, + 5CCAA6DC2A53713A00BAF93B /* libgmpxx.a */, + 5CCAA6DA2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a */, + 5CCAA6DB2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a */, ); path = Libraries; sourceTree = ""; diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index c10bad4480..a6b9b1a2ec 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -66,6 +66,7 @@ public enum ChatCommand { case apiGetChatItemTTL(userId: Int64) case apiSetNetworkConfig(networkConfig: NetCfg) case apiGetNetworkConfig + case reconnectAllServers case apiSetChatSettings(type: ChatType, id: Int64, chatSettings: ChatSettings) case apiContactInfo(contactId: Int64) case apiGroupMemberInfo(groupId: Int64, groupMemberId: Int64) @@ -176,6 +177,7 @@ public enum ChatCommand { case let .apiGetChatItemTTL(userId): return "/_ttl \(userId)" case let .apiSetNetworkConfig(networkConfig): return "/_network \(encodeJSON(networkConfig))" case .apiGetNetworkConfig: return "/network" + case .reconnectAllServers: return "/reconnect" case let .apiSetChatSettings(type, id, chatSettings): return "/_settings \(ref(type, id)) \(encodeJSON(chatSettings))" case let .apiContactInfo(contactId): return "/_info @\(contactId)" case let .apiGroupMemberInfo(groupId, groupMemberId): return "/_info #\(groupId) \(groupMemberId)" @@ -284,6 +286,7 @@ public enum ChatCommand { case .apiGetChatItemTTL: return "apiGetChatItemTTL" case .apiSetNetworkConfig: return "apiSetNetworkConfig" case .apiGetNetworkConfig: return "apiGetNetworkConfig" + case .reconnectAllServers: return "reconnectAllServers" case .apiSetChatSettings: return "apiSetChatSettings" case .apiContactInfo: return "apiContactInfo" case .apiGroupMemberInfo: return "apiGroupMemberInfo" @@ -994,6 +997,7 @@ public struct NetCfg: Codable, Equatable { public var sessionMode: TransportSessionMode public var tcpConnectTimeout: Int // microseconds public var tcpTimeout: Int // microseconds + public var tcpTimeoutPerKb: Int // microseconds public var tcpKeepAlive: KeepAliveOpts? public var smpPingInterval: Int // microseconds public var smpPingCount: Int // times @@ -1004,6 +1008,7 @@ public struct NetCfg: Codable, Equatable { sessionMode: TransportSessionMode.user, tcpConnectTimeout: 10_000_000, tcpTimeout: 7_000_000, + tcpTimeoutPerKb: 10_000, tcpKeepAlive: KeepAliveOpts.defaults, smpPingInterval: 1200_000_000, smpPingCount: 3, @@ -1015,6 +1020,7 @@ public struct NetCfg: Codable, Equatable { sessionMode: TransportSessionMode.user, tcpConnectTimeout: 20_000_000, tcpTimeout: 15_000_000, + tcpTimeoutPerKb: 20_000, tcpKeepAlive: KeepAliveOpts.defaults, smpPingInterval: 1200_000_000, smpPingCount: 3, diff --git a/apps/ios/SimpleXChat/AppGroup.swift b/apps/ios/SimpleXChat/AppGroup.swift index 0b73e674ce..a9de1da158 100644 --- a/apps/ios/SimpleXChat/AppGroup.swift +++ b/apps/ios/SimpleXChat/AppGroup.swift @@ -20,6 +20,7 @@ let GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS = "networkUseOnionHosts" 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_SMP_PING_INTERVAL = "networkSMPPingInterval" let GROUP_DEFAULT_NETWORK_SMP_PING_COUNT = "networkSMPPingCount" let GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE = "networkEnableKeepAlive" @@ -42,6 +43,7 @@ public func registerGroupDefaults() { GROUP_DEFAULT_NETWORK_SESSION_MODE: TransportSessionMode.user.rawValue, 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_SMP_PING_INTERVAL: NetCfg.defaults.smpPingInterval, GROUP_DEFAULT_NETWORK_SMP_PING_COUNT: NetCfg.defaults.smpPingCount, GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE: NetCfg.defaults.enableKeepAlive, @@ -209,6 +211,7 @@ public func getNetCfg() -> NetCfg { let sessionMode = networkSessionModeGroupDefault.get() 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 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) @@ -227,6 +230,7 @@ public func getNetCfg() -> NetCfg { sessionMode: sessionMode, tcpConnectTimeout: tcpConnectTimeout, tcpTimeout: tcpTimeout, + tcpTimeoutPerKb: tcpTimeoutPerKb, tcpKeepAlive: tcpKeepAlive, smpPingInterval: smpPingInterval, smpPingCount: smpPingCount, @@ -239,6 +243,7 @@ public func setNetCfg(_ cfg: NetCfg) { networkSessionModeGroupDefault.set(cfg.sessionMode) 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.smpPingInterval, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL) groupDefaults.set(cfg.smpPingCount, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT) if let tcpKeepAlive = cfg.tcpKeepAlive { diff --git a/apps/ios/de.lproj/Localizable.strings b/apps/ios/de.lproj/Localizable.strings index d9c2791958..c3eee10701 100644 --- a/apps/ios/de.lproj/Localizable.strings +++ b/apps/ios/de.lproj/Localizable.strings @@ -247,6 +247,15 @@ /* No comment provided by engineer. */ "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "**Für jeden Kontakt und jedes Gruppenmitglied** wird eine separate TCP-Verbindung genutzt.\n**Bitte beachten Sie**: Wenn Sie viele Verbindungen haben, kann der Batterieverbrauch und die Datennutzung wesentlich höher sein und einige Verbindungen können scheitern."; +/* No comment provided by engineer. */ +"Abort" = "Abbrechen"; + +/* No comment provided by engineer. */ +"Abort changing address" = "Wechsel der Adresse abbrechen"; + +/* No comment provided by engineer. */ +"Abort changing address?" = "Wechsel der Adresse abbrechen?"; + /* No comment provided by engineer. */ "About SimpleX" = "Über SimpleX"; @@ -302,6 +311,9 @@ /* No comment provided by engineer. */ "Address" = "Adresse"; +/* No comment provided by engineer. */ +"Address change will be aborted. Old receiving address will be used." = "Der Wechsel der Adresse wird abgebrochen. Die bisherige Adresse wird weiter verwendet."; + /* member role */ "admin" = "Admin"; @@ -1218,6 +1230,9 @@ /* No comment provided by engineer. */ "Error" = "Fehler"; +/* No comment provided by engineer. */ +"Error aborting address change" = "Fehler beim Abbrechen des Adresswechsels"; + /* No comment provided by engineer. */ "Error accepting contact request" = "Fehler beim Annehmen der Kontaktanfrage"; @@ -1374,6 +1389,9 @@ /* No comment provided by engineer. */ "Fast and no wait until the sender is online!" = "Schnell und ohne warten auf den Absender, bis er online ist!"; +/* No comment provided by engineer. */ +"Favorite" = "Favorit"; + /* No comment provided by engineer. */ "File will be deleted from servers." = "Die Datei wird von den Servern gelöscht."; @@ -1738,7 +1756,7 @@ "Keychain error" = "Schlüsselbundfehler"; /* No comment provided by engineer. */ -"KeyChain error" = "Keystore Fehler"; +"KeyChain error" = "KeyChain Fehler"; /* No comment provided by engineer. */ "Large file!" = "Große Datei!"; @@ -2314,6 +2332,9 @@ /* message info title */ "Received message" = "Empfangene Nachricht"; +/* No comment provided by engineer. */ +"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "Die Empfängeradresse wird auf einen anderen Server geändert. Der Adresswechsel wird abgeschlossen, wenn der Absender wieder online ist."; + /* No comment provided by engineer. */ "Receiving file will be stopped." = "Der Empfang der Datei wird beendet."; @@ -2950,6 +2971,9 @@ /* No comment provided by engineer. */ "Unexpected migration state" = "Unerwarteter Migrationsstatus"; +/* No comment provided by engineer. */ +"Unfav." = "Unfav."; + /* No comment provided by engineer. */ "Unhide" = "Verbergen aufheben"; diff --git a/apps/ios/fr.lproj/Localizable.strings b/apps/ios/fr.lproj/Localizable.strings index 417518d5e3..741e42fb65 100644 --- a/apps/ios/fr.lproj/Localizable.strings +++ b/apps/ios/fr.lproj/Localizable.strings @@ -247,6 +247,15 @@ /* No comment provided by engineer. */ "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "Une connexion TCP distincte sera utilisée **pour chaque contact et membre de groupe**.\n**Veuillez noter** : si vous avez de nombreuses connexions, votre consommation de batterie et de réseau peut être nettement plus élevée et certaines liaisons peuvent échouer."; +/* No comment provided by engineer. */ +"Abort" = "Annuler"; + +/* No comment provided by engineer. */ +"Abort changing address" = "Annuler le changement d'adresse"; + +/* No comment provided by engineer. */ +"Abort changing address?" = "Abandonner le changement d'adresse ?"; + /* No comment provided by engineer. */ "About SimpleX" = "À propos de SimpleX"; @@ -302,6 +311,9 @@ /* No comment provided by engineer. */ "Address" = "Adresse"; +/* No comment provided by engineer. */ +"Address change will be aborted. Old receiving address will be used." = "Le changement d'adresse sera annulé. L'ancienne adresse de réception sera utilisée."; + /* member role */ "admin" = "admin"; @@ -1218,6 +1230,9 @@ /* No comment provided by engineer. */ "Error" = "Erreur"; +/* No comment provided by engineer. */ +"Error aborting address change" = "Erreur lors de l'annulation du changement d'adresse"; + /* No comment provided by engineer. */ "Error accepting contact request" = "Erreur de validation de la demande de contact"; @@ -1374,6 +1389,9 @@ /* No comment provided by engineer. */ "Fast and no wait until the sender is online!" = "Rapide et ne nécessitant pas d'attendre que l'expéditeur soit en ligne !"; +/* No comment provided by engineer. */ +"Favorite" = "Favoris"; + /* No comment provided by engineer. */ "File will be deleted from servers." = "Le fichier sera supprimé des serveurs."; @@ -2314,6 +2332,9 @@ /* message info title */ "Received message" = "Message reçu"; +/* No comment provided by engineer. */ +"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "L'adresse de réception sera changée pour un autre serveur. Le changement d'adresse sera terminé lorsque l'expéditeur sera en ligne."; + /* No comment provided by engineer. */ "Receiving file will be stopped." = "La réception du fichier sera interrompue."; @@ -2950,6 +2971,9 @@ /* No comment provided by engineer. */ "Unexpected migration state" = "État de la migration inattendu"; +/* No comment provided by engineer. */ +"Unfav." = "Unfav."; + /* No comment provided by engineer. */ "Unhide" = "Dévoiler"; diff --git a/apps/ios/it.lproj/Localizable.strings b/apps/ios/it.lproj/Localizable.strings index a6579084e4..8282dbd2af 100644 --- a/apps/ios/it.lproj/Localizable.strings +++ b/apps/ios/it.lproj/Localizable.strings @@ -247,6 +247,15 @@ /* No comment provided by engineer. */ "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "Verrà usata una connessione TCP separata **per ogni contatto e membro del gruppo**.\n** Nota**: se hai molte connessioni, il consumo di batteria e traffico può essere notevolmente superiore e alcune connessioni potrebbero fallire."; +/* No comment provided by engineer. */ +"Abort" = "Interrompi"; + +/* No comment provided by engineer. */ +"Abort changing address" = "Interrompi il cambio di indirizzo"; + +/* No comment provided by engineer. */ +"Abort changing address?" = "Interrompere il cambio di indirizzo?"; + /* No comment provided by engineer. */ "About SimpleX" = "Riguardo SimpleX"; @@ -302,6 +311,9 @@ /* No comment provided by engineer. */ "Address" = "Indirizzo"; +/* No comment provided by engineer. */ +"Address change will be aborted. Old receiving address will be used." = "Il cambio di indirizzo verrà interrotto. Verrà usato il vecchio indirizzo di ricezione."; + /* member role */ "admin" = "amministratore"; @@ -1218,6 +1230,9 @@ /* No comment provided by engineer. */ "Error" = "Errore"; +/* No comment provided by engineer. */ +"Error aborting address change" = "Errore nell'interruzione del cambio di indirizzo"; + /* No comment provided by engineer. */ "Error accepting contact request" = "Errore nell'accettazione della richiesta di contatto"; @@ -1374,6 +1389,9 @@ /* No comment provided by engineer. */ "Fast and no wait until the sender is online!" = "Veloce e senza aspettare che il mittente sia in linea!"; +/* No comment provided by engineer. */ +"Favorite" = "Preferito"; + /* No comment provided by engineer. */ "File will be deleted from servers." = "Il file verrà eliminato dai server."; @@ -2314,6 +2332,9 @@ /* message info title */ "Received message" = "Messaggio ricevuto"; +/* No comment provided by engineer. */ +"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "L'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell'indirizzo verrà completata dopo che il mittente sarà in linea."; + /* No comment provided by engineer. */ "Receiving file will be stopped." = "La ricezione del file verrà interrotta."; @@ -2950,6 +2971,9 @@ /* No comment provided by engineer. */ "Unexpected migration state" = "Stato di migrazione imprevisto"; +/* No comment provided by engineer. */ +"Unfav." = "Non pref."; + /* No comment provided by engineer. */ "Unhide" = "Svela"; diff --git a/apps/ios/nl.lproj/Localizable.strings b/apps/ios/nl.lproj/Localizable.strings index 0956835328..dfe3aeec32 100644 --- a/apps/ios/nl.lproj/Localizable.strings +++ b/apps/ios/nl.lproj/Localizable.strings @@ -247,6 +247,15 @@ /* No comment provided by engineer. */ "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "Er wordt een aparte TCP-verbinding gebruikt **voor elk contact en groepslid**.\n**Let op**: als u veel verbindingen heeft, kan uw batterij- en verkeersverbruik aanzienlijk hoger zijn en kunnen sommige verbindingen uitvallen."; +/* No comment provided by engineer. */ +"Abort" = "Afbreken"; + +/* No comment provided by engineer. */ +"Abort changing address" = "Annuleer het wijzigen van het adres"; + +/* No comment provided by engineer. */ +"Abort changing address?" = "Adres wijziging afbreken?"; + /* No comment provided by engineer. */ "About SimpleX" = "Over SimpleX"; @@ -302,6 +311,9 @@ /* No comment provided by engineer. */ "Address" = "Adres"; +/* No comment provided by engineer. */ +"Address change will be aborted. Old receiving address will be used." = "Adres wijziging wordt afgebroken. Het oude ontvangstadres wordt gebruikt."; + /* member role */ "admin" = "Beheerder"; @@ -1218,6 +1230,9 @@ /* No comment provided by engineer. */ "Error" = "Fout"; +/* No comment provided by engineer. */ +"Error aborting address change" = "Fout bij het afbreken van adres wijziging"; + /* No comment provided by engineer. */ "Error accepting contact request" = "Fout bij het accepteren van een contactverzoek"; @@ -1374,6 +1389,9 @@ /* No comment provided by engineer. */ "Fast and no wait until the sender is online!" = "Snel en niet wachten tot de afzender online is!"; +/* No comment provided by engineer. */ +"Favorite" = "Favoriet"; + /* No comment provided by engineer. */ "File will be deleted from servers." = "Het bestand wordt van de servers verwijderd."; @@ -2314,6 +2332,9 @@ /* message info title */ "Received message" = "Ontvangen bericht"; +/* No comment provided by engineer. */ +"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "Het ontvangstadres wordt gewijzigd naar een andere server. Adres wijziging wordt voltooid nadat de afzender online is."; + /* No comment provided by engineer. */ "Receiving file will be stopped." = "Het ontvangen van het bestand wordt gestopt."; @@ -2950,6 +2971,9 @@ /* No comment provided by engineer. */ "Unexpected migration state" = "Onverwachte migratiestatus"; +/* No comment provided by engineer. */ +"Unfav." = "Niet fav."; + /* No comment provided by engineer. */ "Unhide" = "zichtbaar maken"; diff --git a/apps/ios/pl.lproj/Localizable.strings b/apps/ios/pl.lproj/Localizable.strings index 0a02f5b28b..60b9f713c9 100644 --- a/apps/ios/pl.lproj/Localizable.strings +++ b/apps/ios/pl.lproj/Localizable.strings @@ -247,6 +247,15 @@ /* No comment provided by engineer. */ "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "Oddzielne połączenie TCP będzie używane **dla każdego kontaktu i członka grupy**.\n**Uwaga**: jeśli masz wiele połączeń, zużycie baterii i ruchu może być znacznie wyższe, a niektóre połączenia mogą się nie udać."; +/* No comment provided by engineer. */ +"Abort" = "Przerwij"; + +/* No comment provided by engineer. */ +"Abort changing address" = "Przerwij zmianę adresu"; + +/* No comment provided by engineer. */ +"Abort changing address?" = "Przerwać zmianę adresu?"; + /* No comment provided by engineer. */ "About SimpleX" = "O SimpleX"; @@ -302,6 +311,9 @@ /* No comment provided by engineer. */ "Address" = "Adres"; +/* No comment provided by engineer. */ +"Address change will be aborted. Old receiving address will be used." = "Zmiana adresu zostanie przerwana. Użyty zostanie stary adres odbiorczy."; + /* member role */ "admin" = "administrator"; @@ -1218,6 +1230,9 @@ /* No comment provided by engineer. */ "Error" = "Błąd"; +/* No comment provided by engineer. */ +"Error aborting address change" = "Błąd przerwania zmiany adresu"; + /* No comment provided by engineer. */ "Error accepting contact request" = "Błąd przyjmowania prośby o kontakt"; @@ -1374,6 +1389,9 @@ /* No comment provided by engineer. */ "Fast and no wait until the sender is online!" = "Szybko i bez czekania aż nadawca będzie online!"; +/* No comment provided by engineer. */ +"Favorite" = "Ulubione"; + /* No comment provided by engineer. */ "File will be deleted from servers." = "Plik zostanie usunięty z serwerów."; @@ -2314,6 +2332,9 @@ /* message info title */ "Received message" = "Otrzymano wiadomość"; +/* No comment provided by engineer. */ +"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online."; + /* No comment provided by engineer. */ "Receiving file will be stopped." = "Odbieranie pliku zostanie przerwane."; @@ -2698,6 +2719,9 @@ /* No comment provided by engineer. */ "SMP servers" = "Serwery SMP"; +/* No comment provided by engineer. */ +"Some non-fatal errors occurred during import - you may see Chat console for more details." = "Podczas importu wystąpiły niekrytyczne błędy - więcej szczegółów można znaleźć w konsoli czatu."; + /* notification title */ "Somebody" = "Ktoś"; @@ -2947,6 +2971,9 @@ /* No comment provided by engineer. */ "Unexpected migration state" = "Nieoczekiwany stan migracji"; +/* No comment provided by engineer. */ +"Unfav." = "Nie ulub."; + /* No comment provided by engineer. */ "Unhide" = "Odkryj"; diff --git a/apps/ios/zh-Hans.lproj/Localizable.strings b/apps/ios/zh-Hans.lproj/Localizable.strings index 4bf6015355..fa16aed569 100644 --- a/apps/ios/zh-Hans.lproj/Localizable.strings +++ b/apps/ios/zh-Hans.lproj/Localizable.strings @@ -247,6 +247,15 @@ /* No comment provided by engineer. */ "A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "每个联系人和群成员将使用一个独立的 TCP 连接。\n请注意:如果您有许多连接,将会消耗更多的电量和流量,并且某些连接可能会失败。"; +/* No comment provided by engineer. */ +"Abort" = "中止"; + +/* No comment provided by engineer. */ +"Abort changing address" = "中止地址更改"; + +/* No comment provided by engineer. */ +"Abort changing address?" = "中止地址更改?"; + /* No comment provided by engineer. */ "About SimpleX" = "关于SimpleX"; @@ -302,6 +311,9 @@ /* No comment provided by engineer. */ "Address" = "地址"; +/* No comment provided by engineer. */ +"Address change will be aborted. Old receiving address will be used." = "将中止地址更改。将使用旧接收地址。"; + /* member role */ "admin" = "管理员"; @@ -426,7 +438,7 @@ "Audio & video calls" = "语音和视频通话"; /* No comment provided by engineer. */ -"Audio and video calls" = "音视频通话"; +"Audio and video calls" = "语音和视频通话"; /* No comment provided by engineer. */ "audio call (not e2e encrypted)" = "语音通话(非端到端加密)"; @@ -1218,6 +1230,9 @@ /* No comment provided by engineer. */ "Error" = "错误"; +/* No comment provided by engineer. */ +"Error aborting address change" = "中止地址更改错误"; + /* No comment provided by engineer. */ "Error accepting contact request" = "接受联系人请求错误"; @@ -1374,6 +1389,9 @@ /* No comment provided by engineer. */ "Fast and no wait until the sender is online!" = "快速且无需等待发件人在线!"; +/* No comment provided by engineer. */ +"Favorite" = "最喜欢"; + /* No comment provided by engineer. */ "File will be deleted from servers." = "文件将从服务器中删除。"; @@ -1732,7 +1750,7 @@ "Join incognito" = "加入隐身聊天"; /* No comment provided by engineer. */ -"Joining group" = "加入群组"; +"Joining group" = "加入群组中"; /* No comment provided by engineer. */ "Keychain error" = "钥匙串错误"; @@ -2314,6 +2332,9 @@ /* message info title */ "Received message" = "收到的信息"; +/* No comment provided by engineer. */ +"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "接收地址将变更到不同的服务器。地址更改将在发件人上线后完成。"; + /* No comment provided by engineer. */ "Receiving file will be stopped." = "即将停止接收文件。"; @@ -2950,6 +2971,9 @@ /* No comment provided by engineer. */ "Unexpected migration state" = "未预料的迁移状态"; +/* No comment provided by engineer. */ +"Unfav." = "取消最喜欢"; + /* No comment provided by engineer. */ "Unhide" = "取消隐藏"; diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/MainActivity.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/MainActivity.kt index 946973d973..772a6dd5f7 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/MainActivity.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/MainActivity.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.fragment.app.FragmentActivity import androidx.lifecycle.* @@ -30,7 +29,6 @@ import chat.simplex.app.views.SplashView import chat.simplex.app.views.call.ActiveCallView import chat.simplex.app.views.call.IncomingCallAlertView import chat.simplex.app.views.chat.ChatView -import chat.simplex.app.views.chat.group.ProgressIndicator import chat.simplex.app.views.chatlist.* import chat.simplex.app.views.database.DatabaseErrorView import chat.simplex.app.views.helpers.* @@ -40,6 +38,8 @@ import chat.simplex.app.views.localauth.SetAppPasscodeView import chat.simplex.app.views.newchat.* import chat.simplex.app.views.onboarding.* import chat.simplex.app.views.usersettings.LAMode +import chat.simplex.res.MR +import dev.icerock.moko.resources.compose.stringResource import kotlinx.coroutines.* import kotlinx.coroutines.flow.distinctUntilChanged import java.lang.ref.WeakReference @@ -94,7 +94,7 @@ class MainActivity: FragmentActivity() { destroyedAfterBackPress, ::runAuthenticate, ::setPerformLA, - showLANotice = { showLANotice(m.controller.appPrefs.laNoticeShown, this) } + showLANotice = { showLANotice(m.controller.appPrefs.laNoticeShown) } ) } } @@ -175,13 +175,13 @@ class MainActivity: FragmentActivity() { withContext(Dispatchers.Main) { authenticate( if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM) - generalGetString(R.string.auth_unlock) + generalGetString(MR.strings.auth_unlock) else - generalGetString(R.string.la_enter_app_passcode), + generalGetString(MR.strings.la_enter_app_passcode), if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM) - generalGetString(R.string.auth_log_in_using_credential) + generalGetString(MR.strings.auth_log_in_using_credential) else - generalGetString(R.string.auth_unlock), + generalGetString(MR.strings.auth_unlock), selfDestruct = true, completed = { laResult -> when (laResult) { @@ -208,49 +208,49 @@ class MainActivity: FragmentActivity() { } } - private fun showLANotice(laNoticeShown: SharedPreference, activity: FragmentActivity) { + private fun showLANotice(laNoticeShown: SharedPreference) { Log.d(TAG, "showLANotice") if (!laNoticeShown.get()) { laNoticeShown.set(true) AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.la_notice_title_simplex_lock), - text = generalGetString(R.string.la_notice_to_protect_your_information_turn_on_simplex_lock_you_will_be_prompted_to_complete_authentication_before_this_feature_is_enabled), - confirmText = generalGetString(R.string.la_notice_turn_on), + title = generalGetString(MR.strings.la_notice_title_simplex_lock), + text = generalGetString(MR.strings.la_notice_to_protect_your_information_turn_on_simplex_lock_you_will_be_prompted_to_complete_authentication_before_this_feature_is_enabled), + confirmText = generalGetString(MR.strings.la_notice_turn_on), onConfirm = { withBGApi { // to remove this call, change ordering of onConfirm call in AlertManager - showChooseLAMode(laNoticeShown, activity) + showChooseLAMode(laNoticeShown) } } ) } } - private fun showChooseLAMode(laNoticeShown: SharedPreference, activity: FragmentActivity) { + private fun showChooseLAMode(laNoticeShown: SharedPreference) { Log.d(TAG, "showLANotice") laNoticeShown.set(true) AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.la_lock_mode), + title = generalGetString(MR.strings.la_lock_mode), text = null, - confirmText = generalGetString(R.string.la_lock_mode_passcode), - dismissText = generalGetString(R.string.la_lock_mode_system), + confirmText = generalGetString(MR.strings.la_lock_mode_passcode), + dismissText = generalGetString(MR.strings.la_lock_mode_system), onConfirm = { AlertManager.shared.hideAlert() setPasscode() }, onDismiss = { AlertManager.shared.hideAlert() - initialEnableLA(activity) + initialEnableLA() } ) } - private fun initialEnableLA(activity: FragmentActivity) { + private fun initialEnableLA() { val m = vm.chatModel val appPrefs = m.controller.appPrefs m.controller.appPrefs.laMode.set(LAMode.SYSTEM) authenticate( - generalGetString(R.string.auth_enable_simplex_lock), - generalGetString(R.string.auth_confirm_credential), + generalGetString(MR.strings.auth_enable_simplex_lock), + generalGetString(MR.strings.auth_confirm_credential), completed = { laResult -> when (laResult) { LAResult.Success -> { @@ -297,24 +297,24 @@ class MainActivity: FragmentActivity() { } } - private fun setPerformLA(on: Boolean, activity: FragmentActivity) { + private fun setPerformLA(on: Boolean) { vm.chatModel.controller.appPrefs.laNoticeShown.set(true) if (on) { - enableLA(activity) + enableLA() } else { - disableLA(activity) + disableLA() } } - private fun enableLA(activity: FragmentActivity) { + private fun enableLA() { val m = vm.chatModel authenticate( if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM) - generalGetString(R.string.auth_enable_simplex_lock) + generalGetString(MR.strings.auth_enable_simplex_lock) else - generalGetString(R.string.new_passcode), + generalGetString(MR.strings.new_passcode), if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM) - generalGetString(R.string.auth_confirm_credential) + generalGetString(MR.strings.auth_confirm_credential) else "", completed = { laResult -> @@ -341,17 +341,17 @@ class MainActivity: FragmentActivity() { ) } - private fun disableLA(activity: FragmentActivity) { + private fun disableLA() { val m = vm.chatModel authenticate( if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM) - generalGetString(R.string.auth_disable_simplex_lock) + generalGetString(MR.strings.auth_disable_simplex_lock) else - generalGetString(R.string.la_enter_app_passcode), + generalGetString(MR.strings.la_enter_app_passcode), if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM) - generalGetString(R.string.auth_confirm_credential) + generalGetString(MR.strings.auth_confirm_credential) else - generalGetString(R.string.auth_disable_simplex_lock), + generalGetString(MR.strings.auth_disable_simplex_lock), completed = { laResult -> val prefPerformLA = m.controller.appPrefs.performLA val selfDestructPref = m.controller.appPrefs.selfDestruct @@ -392,7 +392,7 @@ fun MainPage( laFailed: MutableState, destroyedAfterBackPress: MutableState, runAuthenticate: () -> Unit, - setPerformLA: (Boolean, FragmentActivity) -> Unit, + setPerformLA: (Boolean) -> Unit, showLANotice: () -> Unit ) { var showChatDatabaseError by rememberSaveable { @@ -434,7 +434,7 @@ fun MainPage( contentAlignment = Alignment.Center ) { SimpleButton( - stringResource(R.string.auth_unlock), + stringResource(MR.strings.auth_unlock), icon = painterResource(R.drawable.ic_lock), click = { laFailed.value = false @@ -561,7 +561,7 @@ private fun InitializationView() { color = MaterialTheme.colors.secondary, strokeWidth = 2.5.dp ) - Text(stringResource(R.string.opening_database)) + Text(stringResource(MR.strings.opening_database)) } } } @@ -602,7 +602,7 @@ fun processNotificationIntent(intent: Intent?, chatModel: ChatModel) { chatModel.clearOverlays.value = true val invitation = chatModel.callInvitations[chatId] if (invitation == null) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.call_already_ended)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.call_already_ended)) } else { chatModel.callManager.acceptIncomingCall(invitation = invitation) } @@ -674,17 +674,17 @@ fun connectIfOpenedViaUri(uri: Uri, chatModel: ChatModel) { } else { withUriAction(uri) { linkType -> val title = when (linkType) { - ConnectionLinkType.CONTACT -> generalGetString(R.string.connect_via_contact_link) - ConnectionLinkType.INVITATION -> generalGetString(R.string.connect_via_invitation_link) - ConnectionLinkType.GROUP -> generalGetString(R.string.connect_via_group_link) + ConnectionLinkType.CONTACT -> generalGetString(MR.strings.connect_via_contact_link) + ConnectionLinkType.INVITATION -> generalGetString(MR.strings.connect_via_invitation_link) + ConnectionLinkType.GROUP -> generalGetString(MR.strings.connect_via_group_link) } AlertManager.shared.showAlertDialog( title = title, text = if (linkType == ConnectionLinkType.GROUP) - generalGetString(R.string.you_will_join_group) + generalGetString(MR.strings.you_will_join_group) else - generalGetString(R.string.profile_will_be_sent_to_contact_sending_link), - confirmText = generalGetString(R.string.connect_via_link_verb), + generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link), + confirmText = generalGetString(MR.strings.connect_via_link_verb), onConfirm = { withApi { Log.d(TAG, "connectIfOpenedViaUri: connecting") diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt index 42bfbe7298..b9df85c4fb 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt @@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat import androidx.work.* import chat.simplex.app.model.ChatController import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.* // based on: @@ -41,8 +42,8 @@ class SimplexService: Service() { override fun onCreate() { super.onCreate() Log.d(TAG, "Simplex service created") - val title = getString(R.string.simplex_service_notification_title) - val text = getString(R.string.simplex_service_notification_text) + val title = generalGetString(MR.strings.simplex_service_notification_title) + val text = generalGetString(MR.strings.simplex_service_notification_text) notificationManager = createNotificationChannel() serviceNotification = createNotification(title, text) startForeground(SIMPLEX_SERVICE_ID, serviceNotification) @@ -142,7 +143,7 @@ class SimplexService: Service() { setupIntent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName) setupIntent.putExtra(Settings.EXTRA_CHANNEL_ID, NOTIFICATION_CHANNEL_ID) val setup = PendingIntent.getActivity(this, 0, setupIntent, flags) - builder.addAction(0, getString(R.string.hide_notification), setup) + builder.addAction(0, generalGetString(MR.strings.hide_notification), setup) } return builder.build() @@ -295,15 +296,15 @@ class SimplexService: Service() { } val title = when(chatDbStatus) { - is DBMigrationResult.ErrorNotADatabase -> generalGetString(R.string.enter_passphrase_notification_title) + is DBMigrationResult.ErrorNotADatabase -> generalGetString(MR.strings.enter_passphrase_notification_title) is DBMigrationResult.OK -> return - else -> generalGetString(R.string.database_initialization_error_title) + else -> generalGetString(MR.strings.database_initialization_error_title) } val description = when(chatDbStatus) { - is DBMigrationResult.ErrorNotADatabase -> generalGetString(R.string.enter_passphrase_notification_desc) + is DBMigrationResult.ErrorNotADatabase -> generalGetString(MR.strings.enter_passphrase_notification_desc) is DBMigrationResult.OK -> return - else -> generalGetString(R.string.database_initialization_error_desc) + else -> generalGetString(MR.strings.database_initialization_error_desc) } val builder = NotificationCompat.Builder(SimplexApp.context, NOTIFICATION_CHANNEL_ID) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/model/ChatModel.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/model/ChatModel.kt index b480814144..a4f66c357b 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/model/ChatModel.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/model/ChatModel.kt @@ -15,6 +15,8 @@ import chat.simplex.app.views.helpers.* import chat.simplex.app.views.onboarding.OnboardingStage import chat.simplex.app.views.usersettings.NotificationPreviewMode import chat.simplex.app.views.usersettings.NotificationsMode +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource import kotlinx.coroutines.* import kotlinx.datetime.* import kotlinx.datetime.TimeZone @@ -693,7 +695,7 @@ sealed class ChatInfo: SomeChat, NamedChat { override val localAlias get() = "" companion object { - private val invalidChatName = generalGetString(R.string.invalid_chat) + private val invalidChatName = generalGetString(MR.strings.invalid_chat) } } @@ -709,15 +711,15 @@ sealed class ChatInfo: SomeChat, NamedChat { sealed class NetworkStatus { val statusString: String get() = when (this) { - is Connected -> generalGetString(R.string.server_connected) - is Error -> generalGetString(R.string.server_error) - else -> generalGetString(R.string.server_connecting) + is Connected -> generalGetString(MR.strings.server_connected) + is Error -> generalGetString(MR.strings.server_error) + else -> generalGetString(MR.strings.server_connecting) } val statusExplanation: String get() = when (this) { - is Connected -> generalGetString(R.string.connected_to_server_to_receive_messages_from_contact) - is Error -> String.format(generalGetString(R.string.trying_to_connect_to_server_to_receive_messages_with_error), error) - else -> generalGetString(R.string.trying_to_connect_to_server_to_receive_messages) + is Connected -> generalGetString(MR.strings.connected_to_server_to_receive_messages_from_contact) + is Error -> String.format(generalGetString(MR.strings.trying_to_connect_to_server_to_receive_messages_with_error), error) + else -> generalGetString(MR.strings.trying_to_connect_to_server_to_receive_messages) } @Serializable @SerialName("unknown") class Unknown: NetworkStatus() @@ -1062,10 +1064,10 @@ enum class GroupMemberRole(val memberRole: String) { @SerialName("owner") Owner("owner"); val text: String get() = when (this) { - Observer -> generalGetString(R.string.group_member_role_observer) - Member -> generalGetString(R.string.group_member_role_member) - Admin -> generalGetString(R.string.group_member_role_admin) - Owner -> generalGetString(R.string.group_member_role_owner) + Observer -> generalGetString(MR.strings.group_member_role_observer) + Member -> generalGetString(MR.strings.group_member_role_member) + Admin -> generalGetString(MR.strings.group_member_role_admin) + Owner -> generalGetString(MR.strings.group_member_role_owner) } } @@ -1093,31 +1095,31 @@ enum class GroupMemberStatus { @SerialName("creator") MemCreator; val text: String get() = when (this) { - MemRemoved -> generalGetString(R.string.group_member_status_removed) - MemLeft -> generalGetString(R.string.group_member_status_left) - MemGroupDeleted -> generalGetString(R.string.group_member_status_group_deleted) - MemInvited -> generalGetString(R.string.group_member_status_invited) - MemIntroduced -> generalGetString(R.string.group_member_status_introduced) - MemIntroInvited -> generalGetString(R.string.group_member_status_intro_invitation) - MemAccepted -> generalGetString(R.string.group_member_status_accepted) - MemAnnounced -> generalGetString(R.string.group_member_status_announced) - MemConnected -> generalGetString(R.string.group_member_status_connected) - MemComplete -> generalGetString(R.string.group_member_status_complete) - MemCreator -> generalGetString(R.string.group_member_status_creator) + MemRemoved -> generalGetString(MR.strings.group_member_status_removed) + MemLeft -> generalGetString(MR.strings.group_member_status_left) + MemGroupDeleted -> generalGetString(MR.strings.group_member_status_group_deleted) + MemInvited -> generalGetString(MR.strings.group_member_status_invited) + MemIntroduced -> generalGetString(MR.strings.group_member_status_introduced) + MemIntroInvited -> generalGetString(MR.strings.group_member_status_intro_invitation) + MemAccepted -> generalGetString(MR.strings.group_member_status_accepted) + MemAnnounced -> generalGetString(MR.strings.group_member_status_announced) + MemConnected -> generalGetString(MR.strings.group_member_status_connected) + MemComplete -> generalGetString(MR.strings.group_member_status_complete) + MemCreator -> generalGetString(MR.strings.group_member_status_creator) } val shortText: String get() = when (this) { - MemRemoved -> generalGetString(R.string.group_member_status_removed) - MemLeft -> generalGetString(R.string.group_member_status_left) - MemGroupDeleted -> generalGetString(R.string.group_member_status_group_deleted) - MemInvited -> generalGetString(R.string.group_member_status_invited) - MemIntroduced -> generalGetString(R.string.group_member_status_connecting) - MemIntroInvited -> generalGetString(R.string.group_member_status_connecting) - MemAccepted -> generalGetString(R.string.group_member_status_connecting) - MemAnnounced -> generalGetString(R.string.group_member_status_connecting) - MemConnected -> generalGetString(R.string.group_member_status_connected) - MemComplete -> generalGetString(R.string.group_member_status_complete) - MemCreator -> generalGetString(R.string.group_member_status_creator) + MemRemoved -> generalGetString(MR.strings.group_member_status_removed) + MemLeft -> generalGetString(MR.strings.group_member_status_left) + MemGroupDeleted -> generalGetString(MR.strings.group_member_status_group_deleted) + MemInvited -> generalGetString(MR.strings.group_member_status_invited) + MemIntroduced -> generalGetString(MR.strings.group_member_status_connecting) + MemIntroInvited -> generalGetString(MR.strings.group_member_status_connecting) + MemAccepted -> generalGetString(MR.strings.group_member_status_connecting) + MemAnnounced -> generalGetString(MR.strings.group_member_status_connecting) + MemConnected -> generalGetString(MR.strings.group_member_status_connected) + MemComplete -> generalGetString(MR.strings.group_member_status_complete) + MemCreator -> generalGetString(MR.strings.group_member_status_creator) } } @@ -1206,17 +1208,17 @@ class PendingContactConnection( override val incognito get() = customUserProfileId != null override fun featureEnabled(feature: ChatFeature) = false override val timedMessagesTTL: Int? get() = null - override val localDisplayName get() = String.format(generalGetString(R.string.connection_local_display_name), pccConnId) + override val localDisplayName get() = String.format(generalGetString(MR.strings.connection_local_display_name), pccConnId) override val displayName: String get() { if (localAlias.isNotEmpty()) return localAlias val initiated = pccConnStatus.initiated return if (initiated == null) { // this should not be in the chat list - generalGetString(R.string.display_name_connection_established) + generalGetString(MR.strings.display_name_connection_established) } else { generalGetString( - if (initiated && !viaContactUri) R.string.display_name_invited_to_connect - else R.string.display_name_connecting + if (initiated && !viaContactUri) MR.strings.display_name_invited_to_connect + else MR.strings.display_name_connecting ) } } @@ -1229,14 +1231,14 @@ class PendingContactConnection( val initiated = pccConnStatus.initiated return if (initiated == null) "" else generalGetString( if (initiated && !viaContactUri) - if (incognito) R.string.description_you_shared_one_time_link_incognito else R.string.description_you_shared_one_time_link + if (incognito) MR.strings.description_you_shared_one_time_link_incognito else MR.strings.description_you_shared_one_time_link else if (viaContactUri) if (groupLinkId != null) - if (incognito) R.string.description_via_group_link_incognito else R.string.description_via_group_link + if (incognito) MR.strings.description_via_group_link_incognito else MR.strings.description_via_group_link else - if (incognito) R.string.description_via_contact_address_link_incognito else R.string.description_via_contact_address_link + if (incognito) MR.strings.description_via_contact_address_link_incognito else MR.strings.description_via_contact_address_link else - if (incognito) R.string.description_via_one_time_link_incognito else R.string.description_via_one_time_link + if (incognito) MR.strings.description_via_one_time_link_incognito else MR.strings.description_via_one_time_link ) } @@ -1312,7 +1314,7 @@ data class ChatItem ( val text: String get() { val mc = content.msgContent return when { - content.text == "" && file != null && mc is MsgContent.MCVoice -> String.format(generalGetString(R.string.voice_message_with_duration), durationText(mc.duration)) + content.text == "" && file != null && mc is MsgContent.MCVoice -> String.format(generalGetString(MR.strings.voice_message_with_duration), durationText(mc.duration)) content.text == "" && file != null -> file.fileName else -> content.text } @@ -1491,7 +1493,7 @@ data class ChatItem ( meta = CIMeta( itemId = TEMP_DELETED_CHAT_ITEM_ID, itemTs = Clock.System.now(), - itemText = generalGetString(R.string.deleted_description), + itemText = generalGetString(MR.strings.deleted_description), itemStatus = CIStatus.RcvRead(), createdAt = Clock.System.now(), updatedAt = Clock.System.now(), @@ -1718,8 +1720,8 @@ sealed class CIContent: ItemContent { override val text: String get() = when (this) { is SndMsgContent -> msgContent.text is RcvMsgContent -> msgContent.text - is SndDeleted -> generalGetString(R.string.deleted_description) - is RcvDeleted -> generalGetString(R.string.deleted_description) + is SndDeleted -> generalGetString(MR.strings.deleted_description) + is RcvDeleted -> generalGetString(MR.strings.deleted_description) is SndCall -> status.text(duration) is RcvCall -> status.text(duration) is RcvIntegrityError -> msgError.text @@ -1736,10 +1738,10 @@ sealed class CIContent: ItemContent { is SndChatPreference -> preferenceText(feature, allowed, param) is RcvGroupFeature -> featureText(groupFeature, preference.enable.text, param) is SndGroupFeature -> featureText(groupFeature, preference.enable.text, param) - is RcvChatFeatureRejected -> "${feature.text}: ${generalGetString(R.string.feature_received_prohibited)}" - is RcvGroupFeatureRejected -> "${groupFeature.text}: ${generalGetString(R.string.feature_received_prohibited)}" - is SndModerated -> generalGetString(R.string.moderated_description) - is RcvModerated -> generalGetString(R.string.moderated_description) + is RcvChatFeatureRejected -> "${feature.text}: ${generalGetString(MR.strings.feature_received_prohibited)}" + is RcvGroupFeatureRejected -> "${groupFeature.text}: ${generalGetString(MR.strings.feature_received_prohibited)}" + is SndModerated -> generalGetString(MR.strings.moderated_description) + is RcvModerated -> generalGetString(MR.strings.moderated_description) is InvalidJSON -> "invalid data" } @@ -1753,11 +1755,11 @@ sealed class CIContent: ItemContent { fun preferenceText(feature: Feature, allowed: FeatureAllowed, param: Int?): String = when { allowed != FeatureAllowed.NO && feature.hasParam && param != null -> - String.format(generalGetString(R.string.feature_offered_item_with_param), feature.text, timeText(param)) + String.format(generalGetString(MR.strings.feature_offered_item_with_param), feature.text, timeText(param)) allowed != FeatureAllowed.NO -> - String.format(generalGetString(R.string.feature_offered_item), feature.text, timeText(param)) + String.format(generalGetString(MR.strings.feature_offered_item), feature.text, timeText(param)) else -> - String.format(generalGetString(R.string.feature_cancelled_item), feature.text, timeText(param)) + String.format(generalGetString(MR.strings.feature_cancelled_item), feature.text, timeText(param)) } } } @@ -1768,8 +1770,8 @@ enum class MsgDecryptError { @SerialName("tooManySkipped") TooManySkipped; val text: String get() = when (this) { - RatchetHeader -> generalGetString(R.string.decryption_error) - TooManySkipped -> generalGetString(R.string.decryption_error) + RatchetHeader -> generalGetString(MR.strings.decryption_error) + TooManySkipped -> generalGetString(MR.strings.decryption_error) } } @@ -1791,7 +1793,7 @@ class CIQuote ( fun sender(membership: GroupMember?): String? = when (chatDir) { - is CIDirection.DirectSnd -> generalGetString(R.string.sender_you_pronoun) + is CIDirection.DirectSnd -> generalGetString(MR.strings.sender_you_pronoun) is CIDirection.DirectRcv -> null is CIDirection.GroupSnd -> membership?.displayName is CIDirection.GroupRcv -> chatDir.groupMember.displayName @@ -1896,6 +1898,7 @@ class CIFile( is CIFileStatus.RcvError -> false } + @Transient val cancelAction: CancelAction? = when (fileStatus) { is CIFileStatus.SndStored -> sndCancelAction is CIFileStatus.SndTransfer -> sndCancelAction @@ -1927,41 +1930,39 @@ class CIFile( } } -@Serializable class CancelAction( - val uiActionId: Int, + val uiActionId: StringResource, val alert: AlertInfo ) -@Serializable class AlertInfo( - val titleId: Int, - val messageId: Int, - val confirmId: Int + val titleId: StringResource, + val messageId: StringResource, + val confirmId: StringResource ) private val sndCancelAction: CancelAction = CancelAction( - uiActionId = R.string.stop_file__action, + uiActionId = MR.strings.stop_file__action, alert = AlertInfo( - titleId = R.string.stop_snd_file__title, - messageId = R.string.stop_snd_file__message, - confirmId = R.string.stop_file__confirm + titleId = MR.strings.stop_snd_file__title, + messageId = MR.strings.stop_snd_file__message, + confirmId = MR.strings.stop_file__confirm ) ) private val revokeCancelAction: CancelAction = CancelAction( - uiActionId = R.string.revoke_file__action, + uiActionId = MR.strings.revoke_file__action, alert = AlertInfo( - titleId = R.string.revoke_file__title, - messageId = R.string.revoke_file__message, - confirmId = R.string.revoke_file__confirm + titleId = MR.strings.revoke_file__title, + messageId = MR.strings.revoke_file__message, + confirmId = MR.strings.revoke_file__confirm ) ) private val rcvCancelAction: CancelAction = CancelAction( - uiActionId = R.string.stop_file__action, + uiActionId = MR.strings.stop_file__action, alert = AlertInfo( - titleId = R.string.stop_rcv_file__title, - messageId = R.string.stop_rcv_file__message, - confirmId = R.string.stop_file__confirm + titleId = MR.strings.stop_rcv_file__title, + messageId = MR.strings.stop_rcv_file__message, + confirmId = MR.strings.stop_file__confirm ) ) @@ -2012,7 +2013,7 @@ class CIGroupInvitation ( val status: CIGroupInvitationStatus, ) { val text: String get() = String.format( - generalGetString(R.string.group_invitation_item_description), + generalGetString(MR.strings.group_invitation_item_description), groupProfile.displayName) companion object { @@ -2065,7 +2066,7 @@ object MsgContentSerializer : KSerializer { return if (json is JsonObject) { if ("type" in json) { val t = json["type"]?.jsonPrimitive?.content ?: "" - val text = json["text"]?.jsonPrimitive?.content ?: generalGetString(R.string.unknown_message_format) + val text = json["text"]?.jsonPrimitive?.content ?: generalGetString(MR.strings.unknown_message_format) when (t) { "text" -> MsgContent.MCText(text) "link" -> { @@ -2089,10 +2090,10 @@ object MsgContentSerializer : KSerializer { else -> MsgContent.MCUnknown(t, text, json) } } else { - MsgContent.MCUnknown(text = generalGetString(R.string.invalid_message_format), json = json) + MsgContent.MCUnknown(text = generalGetString(MR.strings.invalid_message_format), json = json) } } else { - MsgContent.MCUnknown(text = generalGetString(R.string.invalid_message_format), json = json) + MsgContent.MCUnknown(text = generalGetString(MR.strings.invalid_message_format), json = json) } } @@ -2156,7 +2157,7 @@ class FormattedText(val text: String, val format: Format? = null) { if (format is Format.SimplexLink && mode == SimplexLinkMode.DESCRIPTION) simplexLinkText(format.linkType, format.smpHosts) else text fun simplexLinkText(linkType: SimplexLinkType, smpHosts: List): String = - "${linkType.description} (${String.format(generalGetString(R.string.simplex_link_connection), smpHosts.firstOrNull() ?: "?")})" + "${linkType.description} (${String.format(generalGetString(MR.strings.simplex_link_connection), smpHosts.firstOrNull() ?: "?")})" } @Serializable @@ -2197,9 +2198,9 @@ enum class SimplexLinkType(val linkType: String) { group("group"); val description: String get() = generalGetString(when (this) { - contact -> R.string.simplex_link_contact - invitation -> R.string.simplex_link_invitation - group -> R.string.simplex_link_group + contact -> MR.strings.simplex_link_contact + invitation -> MR.strings.simplex_link_invitation + group -> MR.strings.simplex_link_group }) } @@ -2247,14 +2248,14 @@ enum class CICallStatus { @SerialName("error") Error; fun text(sec: Int): String = when (this) { - Pending -> generalGetString(R.string.callstatus_calling) - Missed -> generalGetString(R.string.callstatus_missed) - Rejected -> generalGetString(R.string.callstatus_rejected) - Accepted -> generalGetString(R.string.callstatus_accepted) - Negotiated -> generalGetString(R.string.callstatus_connecting) - Progress -> generalGetString(R.string.callstatus_in_progress) - Ended -> String.format(generalGetString(R.string.callstatus_ended), durationText(sec)) - Error -> generalGetString(R.string.callstatus_error) + Pending -> generalGetString(MR.strings.callstatus_calling) + Missed -> generalGetString(MR.strings.callstatus_missed) + Rejected -> generalGetString(MR.strings.callstatus_rejected) + Accepted -> generalGetString(MR.strings.callstatus_accepted) + Negotiated -> generalGetString(MR.strings.callstatus_connecting) + Progress -> generalGetString(MR.strings.callstatus_in_progress) + Ended -> String.format(generalGetString(MR.strings.callstatus_ended), durationText(sec)) + Error -> generalGetString(MR.strings.callstatus_error) } } @@ -2272,10 +2273,10 @@ sealed class MsgErrorType() { @Serializable @SerialName("msgDuplicate") class MsgDuplicate(): MsgErrorType() val text: String get() = when (this) { - is MsgSkipped -> String.format(generalGetString(R.string.integrity_msg_skipped), toMsgId - fromMsgId + 1) - is MsgBadHash -> generalGetString(R.string.integrity_msg_bad_hash) // not used now - is MsgBadId -> generalGetString(R.string.integrity_msg_bad_id) // not used now - is MsgDuplicate -> generalGetString(R.string.integrity_msg_duplicate) // not used now + is MsgSkipped -> String.format(generalGetString(MR.strings.integrity_msg_skipped), toMsgId - fromMsgId + 1) + is MsgBadHash -> generalGetString(MR.strings.integrity_msg_bad_hash) // not used now + is MsgBadId -> generalGetString(MR.strings.integrity_msg_bad_id) // not used now + is MsgDuplicate -> generalGetString(MR.strings.integrity_msg_duplicate) // not used now } } @@ -2293,16 +2294,16 @@ sealed class RcvGroupEvent() { @Serializable @SerialName("invitedViaGroupLink") class InvitedViaGroupLink(): RcvGroupEvent() val text: String get() = when (this) { - is MemberAdded -> String.format(generalGetString(R.string.rcv_group_event_member_added), profile.profileViewName) - is MemberConnected -> generalGetString(R.string.rcv_group_event_member_connected) - is MemberLeft -> generalGetString(R.string.rcv_group_event_member_left) - is MemberRole -> String.format(generalGetString(R.string.rcv_group_event_changed_member_role), profile.profileViewName, role.text) - is UserRole -> String.format(generalGetString(R.string.rcv_group_event_changed_your_role), role.text) - is MemberDeleted -> String.format(generalGetString(R.string.rcv_group_event_member_deleted), profile.profileViewName) - is UserDeleted -> generalGetString(R.string.rcv_group_event_user_deleted) - is GroupDeleted -> generalGetString(R.string.rcv_group_event_group_deleted) - is GroupUpdated -> generalGetString(R.string.rcv_group_event_updated_group_profile) - is InvitedViaGroupLink -> generalGetString(R.string.rcv_group_event_invited_via_your_group_link) + is MemberAdded -> String.format(generalGetString(MR.strings.rcv_group_event_member_added), profile.profileViewName) + is MemberConnected -> generalGetString(MR.strings.rcv_group_event_member_connected) + is MemberLeft -> generalGetString(MR.strings.rcv_group_event_member_left) + is MemberRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_member_role), profile.profileViewName, role.text) + is UserRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_your_role), role.text) + is MemberDeleted -> String.format(generalGetString(MR.strings.rcv_group_event_member_deleted), profile.profileViewName) + is UserDeleted -> generalGetString(MR.strings.rcv_group_event_user_deleted) + is GroupDeleted -> generalGetString(MR.strings.rcv_group_event_group_deleted) + is GroupUpdated -> generalGetString(MR.strings.rcv_group_event_updated_group_profile) + is InvitedViaGroupLink -> generalGetString(MR.strings.rcv_group_event_invited_via_your_group_link) } } @@ -2315,11 +2316,11 @@ sealed class SndGroupEvent() { @Serializable @SerialName("groupUpdated") class GroupUpdated(val groupProfile: GroupProfile): SndGroupEvent() val text: String get() = when (this) { - is MemberRole -> String.format(generalGetString(R.string.snd_group_event_changed_member_role), profile.profileViewName, role.text) - is UserRole -> String.format(generalGetString(R.string.snd_group_event_changed_role_for_yourself), role.text) - is MemberDeleted -> String.format(generalGetString(R.string.snd_group_event_member_deleted), profile.profileViewName) - is UserLeft -> generalGetString(R.string.snd_group_event_user_left) - is GroupUpdated -> generalGetString(R.string.snd_group_event_group_profile_updated) + is MemberRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_member_role), profile.profileViewName, role.text) + is UserRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_role_for_yourself), role.text) + is MemberDeleted -> String.format(generalGetString(MR.strings.snd_group_event_member_deleted), profile.profileViewName) + is UserLeft -> generalGetString(MR.strings.snd_group_event_user_left) + is GroupUpdated -> generalGetString(MR.strings.snd_group_event_group_profile_updated) } } @@ -2329,8 +2330,8 @@ sealed class RcvConnEvent { val text: String get() = when (this) { is SwitchQueue -> when (phase) { - SwitchPhase.Completed -> generalGetString(R.string.rcv_conn_event_switch_queue_phase_completed) - else -> generalGetString(R.string.rcv_conn_event_switch_queue_phase_changing) + SwitchPhase.Completed -> generalGetString(MR.strings.rcv_conn_event_switch_queue_phase_completed) + else -> generalGetString(MR.strings.rcv_conn_event_switch_queue_phase_changing) } } } @@ -2344,13 +2345,13 @@ sealed class SndConnEvent { is SwitchQueue -> { member?.profile?.profileViewName?.let { return when (phase) { - SwitchPhase.Completed -> String.format(generalGetString(R.string.snd_conn_event_switch_queue_phase_completed_for_member), it) - else -> String.format(generalGetString(R.string.snd_conn_event_switch_queue_phase_changing_for_member), it) + SwitchPhase.Completed -> String.format(generalGetString(MR.strings.snd_conn_event_switch_queue_phase_completed_for_member), it) + else -> String.format(generalGetString(MR.strings.snd_conn_event_switch_queue_phase_changing_for_member), it) } } when (phase) { - SwitchPhase.Completed -> generalGetString(R.string.snd_conn_event_switch_queue_phase_completed) - else -> generalGetString(R.string.snd_conn_event_switch_queue_phase_changing) + SwitchPhase.Completed -> generalGetString(MR.strings.snd_conn_event_switch_queue_phase_completed) + else -> generalGetString(MR.strings.snd_conn_event_switch_queue_phase_changing) } } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/model/NtfManager.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/model/NtfManager.kt index 1a52030c84..f3b7e7a180 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/model/NtfManager.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/model/NtfManager.kt @@ -17,6 +17,7 @@ import chat.simplex.app.views.call.* import chat.simplex.app.views.chatlist.acceptContactRequest import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.NotificationPreviewMode +import chat.simplex.res.MR import kotlinx.datetime.Clock object NtfManager { @@ -86,7 +87,7 @@ object NtfManager { user = user, chatId = cInfo.id, displayName = cInfo.displayName, - msgText = generalGetString(R.string.notification_new_contact_request), + msgText = generalGetString(MR.strings.notification_new_contact_request), image = cInfo.image, listOf(NotificationAction.ACCEPT_CONTACT_REQUEST) ) @@ -97,7 +98,7 @@ object NtfManager { user = user, chatId = contact.id, displayName = contact.displayName, - msgText = generalGetString(R.string.notification_contact_connected) + msgText = generalGetString(MR.strings.notification_contact_connected) ) } @@ -113,8 +114,8 @@ object NtfManager { val recentNotification = (now - prevNtfTime.getOrDefault(chatId, 0) < msgNtfTimeoutMs) prevNtfTime[chatId] = now val previewMode = appPreferences.notificationPreviewMode.get() - val title = if (previewMode == NotificationPreviewMode.HIDDEN.name) generalGetString(R.string.notification_preview_somebody) else displayName - val content = if (previewMode != NotificationPreviewMode.MESSAGE.name) generalGetString(R.string.notification_preview_new_message) else msgText + val title = if (previewMode == NotificationPreviewMode.HIDDEN.name) generalGetString(MR.strings.notification_preview_somebody) else displayName + val content = if (previewMode != NotificationPreviewMode.MESSAGE.name) generalGetString(MR.strings.notification_preview_new_message) else msgText val largeIcon = when { actions.isEmpty() -> null image == null || previewMode == NotificationPreviewMode.HIDDEN.name -> BitmapFactory.decodeResource(context.resources, R.drawable.icon) @@ -142,7 +143,7 @@ object NtfManager { actionIntent.putExtra(ChatIdKey, chatId) val actionPendingIntent: PendingIntent = PendingIntent.getBroadcast(SimplexApp.context, 0, actionIntent, flags) val actionButton = when (action) { - NotificationAction.ACCEPT_CONTACT_REQUEST -> generalGetString(R.string.accept) + NotificationAction.ACCEPT_CONTACT_REQUEST -> generalGetString(MR.strings.accept) } builder.addAction(0, actionButton, actionPendingIntent) } @@ -191,21 +192,21 @@ object NtfManager { val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, Intent(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) NotificationCompat.Builder(context, CallChannel) .setContentIntent(chatPendingIntent(OpenChatAction, invitation.user.userId, invitation.contact.id)) - .addAction(R.drawable.ntf_icon, generalGetString(R.string.accept), chatPendingIntent(AcceptCallAction, invitation.user.userId, contactId)) - .addAction(R.drawable.ntf_icon, generalGetString(R.string.reject), chatPendingIntent(RejectCallAction, invitation.user.userId, contactId, true)) + .addAction(R.drawable.ntf_icon, generalGetString(MR.strings.accept), chatPendingIntent(AcceptCallAction, invitation.user.userId, contactId)) + .addAction(R.drawable.ntf_icon, generalGetString(MR.strings.reject), chatPendingIntent(RejectCallAction, invitation.user.userId, contactId, true)) .setFullScreenIntent(fullScreenPendingIntent, true) .setSound(soundUri) } val text = generalGetString( if (invitation.callType.media == CallMediaType.Video) { - if (invitation.sharedKey == null) R.string.video_call_no_encryption else R.string.encrypted_video_call + if (invitation.sharedKey == null) MR.strings.video_call_no_encryption else MR.strings.encrypted_video_call } else { - if (invitation.sharedKey == null) R.string.audio_call_no_encryption else R.string.encrypted_audio_call + if (invitation.sharedKey == null) MR.strings.audio_call_no_encryption else MR.strings.encrypted_audio_call } ) val previewMode = appPreferences.notificationPreviewMode.get() val title = if (previewMode == NotificationPreviewMode.HIDDEN.name) - generalGetString(R.string.notification_preview_somebody) + generalGetString(MR.strings.notification_preview_somebody) else invitation.contact.displayName val largeIcon = if (image == null || previewMode == NotificationPreviewMode.HIDDEN.name) @@ -281,8 +282,8 @@ object NtfManager { * old ones if needed * */ fun createNtfChannelsMaybeShowAlert() { - manager.createNotificationChannel(NotificationChannel(MessageChannel, generalGetString(R.string.ntf_channel_messages), NotificationManager.IMPORTANCE_HIGH)) - manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(R.string.ntf_channel_calls))) + manager.createNotificationChannel(NotificationChannel(MessageChannel, generalGetString(MR.strings.ntf_channel_messages), NotificationManager.IMPORTANCE_HIGH)) + manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(MR.strings.ntf_channel_calls))) // Remove old channels since they can't be edited manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION") manager.deleteNotificationChannel("chat.simplex.app.LOCK_SCREEN_CALL_NOTIFICATION") diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/model/SimpleXAPI.kt index c55f697048..be21e2d8a9 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/model/SimpleXAPI.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/model/SimpleXAPI.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import chat.simplex.app.* @@ -27,6 +27,8 @@ import chat.simplex.app.views.onboarding.OnboardingStage import chat.simplex.app.views.usersettings.* import com.charleskorn.kaml.Yaml import com.charleskorn.kaml.YamlConfiguration +import chat.simplex.res.MR +import dev.icerock.moko.resources.compose.stringResource import kotlinx.coroutines.* import kotlinx.datetime.Clock import kotlinx.datetime.Instant @@ -129,6 +131,7 @@ class AppPreferences { val networkRequiredHostMode = mkBoolPreference(SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE, false) val networkTCPConnectTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT, NetCfg.defaults.tcpConnectTimeout, NetCfg.proxyDefaults.tcpConnectTimeout) val networkTCPTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT, NetCfg.defaults.tcpTimeout, NetCfg.proxyDefaults.tcpTimeout) + val networkTCPTimeoutPerKb = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB, NetCfg.defaults.tcpTimeoutPerKb, NetCfg.proxyDefaults.tcpTimeoutPerKb) val networkSMPPingInterval = mkLongPreference(SHARED_PREFS_NETWORK_SMP_PING_INTERVAL, NetCfg.defaults.smpPingInterval) val networkSMPPingCount = mkIntPreference(SHARED_PREFS_NETWORK_SMP_PING_COUNT, NetCfg.defaults.smpPingCount) val networkEnableKeepAlive = mkBoolPreference(SHARED_PREFS_NETWORK_ENABLE_KEEP_ALIVE, NetCfg.defaults.enableKeepAlive) @@ -264,6 +267,7 @@ class AppPreferences { private const val SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE = "NetworkRequiredHostMode" private const val SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT = "NetworkTCPConnectTimeout" private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT = "NetworkTCPTimeout" + private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb" private const val SHARED_PREFS_NETWORK_SMP_PING_INTERVAL = "NetworkSMPPingInterval" private const val SHARED_PREFS_NETWORK_SMP_PING_COUNT = "NetworkSMPPingCount" private const val SHARED_PREFS_NETWORK_ENABLE_KEEP_ALIVE = "NetworkEnableKeepAlive" @@ -355,7 +359,7 @@ object ChatController { changeActiveUser_(toUserId, viewPwd) } catch (e: Exception) { Log.e(TAG, "Unable to set active user: ${e.stackTraceToString()}") - AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_active_user_title), e.stackTraceToString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_active_user_title), e.stackTraceToString()) } } @@ -448,9 +452,9 @@ object ChatController { r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorStore && r.chatError.storeError is StoreError.DuplicateName || r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat && r.chatError.errorType is ChatErrorType.UserExists ) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_create_user_duplicate_title), generalGetString(R.string.failed_to_create_user_duplicate_desc)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_create_user_duplicate_title), generalGetString(MR.strings.failed_to_create_user_duplicate_desc)) } else { - AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_create_user_title), r.details) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_create_user_title), r.details) } Log.d(TAG, "apiCreateActiveUser: ${r.responseType} ${r.details}") return null @@ -566,7 +570,7 @@ object ChatController { val r = sendCmd(CC.ApiGetChats(userId)) if (r is CR.ApiChats) return r.chats Log.e(TAG, "failed getting the list of chats: ${r.responseType} ${r.details}") - AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_parse_chats_title), generalGetString(R.string.contact_developers)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_parse_chats_title), generalGetString(MR.strings.contact_developers)) return emptyList() } @@ -574,7 +578,7 @@ object ChatController { val r = sendCmd(CC.ApiGetChat(type, id, pagination, search)) if (r is CR.ApiChat) return r.chat Log.e(TAG, "apiGetChat bad response: ${r.responseType} ${r.details}") - AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_parse_chat_title), generalGetString(R.string.contact_developers)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_parse_chat_title), generalGetString(MR.strings.contact_developers)) return null } @@ -585,7 +589,7 @@ object ChatController { is CR.NewChatItem -> r.chatItem else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiSendMessage", generalGetString(R.string.error_sending_message), r) + apiErrorAlert("apiSendMessage", generalGetString(MR.strings.error_sending_message), r) } null } @@ -596,7 +600,7 @@ object ChatController { return when (val r = sendCmd(CC.ApiGetChatItemInfo(type, id, itemId))) { is CR.ApiChatItemInfo -> r.chatItemInfo else -> { - apiErrorAlert("apiGetChatItemInfo", generalGetString(R.string.error_loading_details), r) + apiErrorAlert("apiGetChatItemInfo", generalGetString(MR.strings.error_loading_details), r) null } } @@ -637,7 +641,7 @@ object ChatController { else { Log.e(TAG, "getUserProtoServers bad response: ${r.responseType} ${r.details}") AlertManager.shared.showAlertMsg( - generalGetString(if (serverProtocol == ServerProtocol.SMP) R.string.error_loading_smp_servers else R.string.error_loading_xftp_servers), + generalGetString(if (serverProtocol == ServerProtocol.SMP) MR.strings.error_loading_smp_servers else MR.strings.error_loading_xftp_servers), "${r.responseType}: ${r.details}" ) null @@ -652,8 +656,8 @@ object ChatController { else -> { Log.e(TAG, "setUserProtoServers bad response: ${r.responseType} ${r.details}") AlertManager.shared.showAlertMsg( - generalGetString(if (serverProtocol == ServerProtocol.SMP) R.string.error_saving_smp_servers else R.string.error_saving_xftp_servers), - generalGetString(if (serverProtocol == ServerProtocol.SMP) R.string.ensure_smp_server_address_are_correct_format_and_unique else R.string.ensure_xftp_server_address_are_correct_format_and_unique) + generalGetString(if (serverProtocol == ServerProtocol.SMP) MR.strings.error_saving_smp_servers else MR.strings.error_saving_xftp_servers), + generalGetString(if (serverProtocol == ServerProtocol.SMP) MR.strings.ensure_smp_server_address_are_correct_format_and_unique else MR.strings.ensure_xftp_server_address_are_correct_format_and_unique) ) false } @@ -700,7 +704,7 @@ object ChatController { else -> { Log.e(TAG, "apiSetNetworkConfig bad response: ${r.responseType} ${r.details}") AlertManager.shared.showAlertMsg( - generalGetString(R.string.error_setting_network_config), + generalGetString(MR.strings.error_setting_network_config), "${r.responseType}: ${r.details}" ) false @@ -736,28 +740,28 @@ object ChatController { suspend fun apiSwitchContact(contactId: Long): ConnectionStats? { val r = sendCmd(CC.APISwitchContact(contactId)) if (r is CR.ContactSwitchStarted) return r.connectionStats - apiErrorAlert("apiSwitchContact", generalGetString(R.string.error_changing_address), r) + apiErrorAlert("apiSwitchContact", generalGetString(MR.strings.error_changing_address), r) return null } suspend fun apiSwitchGroupMember(groupId: Long, groupMemberId: Long): ConnectionStats? { val r = sendCmd(CC.APISwitchGroupMember(groupId, groupMemberId)) if (r is CR.GroupMemberSwitchStarted) return r.connectionStats - apiErrorAlert("apiSwitchGroupMember", generalGetString(R.string.error_changing_address), r) + apiErrorAlert("apiSwitchGroupMember", generalGetString(MR.strings.error_changing_address), r) return null } suspend fun apiAbortSwitchContact(contactId: Long): ConnectionStats? { val r = sendCmd(CC.APIAbortSwitchContact(contactId)) if (r is CR.ContactSwitchAborted) return r.connectionStats - apiErrorAlert("apiAbortSwitchContact", generalGetString(R.string.error_aborting_address_change), r) + apiErrorAlert("apiAbortSwitchContact", generalGetString(MR.strings.error_aborting_address_change), r) return null } suspend fun apiAbortSwitchGroupMember(groupId: Long, groupMemberId: Long): ConnectionStats? { val r = sendCmd(CC.APIAbortSwitchGroupMember(groupId, groupMemberId)) if (r is CR.GroupMemberSwitchAborted) return r.connectionStats - apiErrorAlert("apiAbortSwitchGroupMember", generalGetString(R.string.error_aborting_address_change), r) + apiErrorAlert("apiAbortSwitchGroupMember", generalGetString(MR.strings.error_aborting_address_change), r) return null } @@ -799,7 +803,7 @@ object ChatController { is CR.Invitation -> r.connReqInvitation else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiAddContact", generalGetString(R.string.connection_error), r) + apiErrorAlert("apiAddContact", generalGetString(MR.strings.connection_error), r) } null } @@ -816,16 +820,16 @@ object ChatController { r is CR.SentConfirmation || r is CR.SentInvitation -> return true r is CR.ContactAlreadyExists -> { AlertManager.shared.showAlertMsg( - generalGetString(R.string.contact_already_exists), - String.format(generalGetString(R.string.you_are_already_connected_to_vName_via_this_link), r.contact.displayName) + generalGetString(MR.strings.contact_already_exists), + String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), r.contact.displayName) ) return false } r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat && r.chatError.errorType is ChatErrorType.InvalidConnReq -> { AlertManager.shared.showAlertMsg( - generalGetString(R.string.invalid_connection_link), - generalGetString(R.string.please_check_correct_link_and_maybe_ask_for_a_new_one) + generalGetString(MR.strings.invalid_connection_link), + generalGetString(MR.strings.please_check_correct_link_and_maybe_ask_for_a_new_one) ) return false } @@ -833,14 +837,14 @@ object ChatController { && r.chatError.agentError is AgentErrorType.SMP && r.chatError.agentError.smpErr is SMPErrorType.AUTH -> { AlertManager.shared.showAlertMsg( - generalGetString(R.string.connection_error_auth), - generalGetString(R.string.connection_error_auth_desc) + generalGetString(MR.strings.connection_error_auth), + generalGetString(MR.strings.connection_error_auth_desc) ) return false } else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiConnect", generalGetString(R.string.connection_error), r) + apiErrorAlert("apiConnect", generalGetString(MR.strings.connection_error), r) } return false } @@ -855,10 +859,10 @@ object ChatController { r is CR.GroupDeletedUser && type == ChatType.Group -> return true else -> { val titleId = when (type) { - ChatType.Direct -> R.string.error_deleting_contact - ChatType.Group -> R.string.error_deleting_group - ChatType.ContactRequest -> R.string.error_deleting_contact_request - ChatType.ContactConnection -> R.string.error_deleting_pending_contact_connection + ChatType.Direct -> MR.strings.error_deleting_contact + ChatType.Group -> MR.strings.error_deleting_group + ChatType.ContactRequest -> MR.strings.error_deleting_contact_request + ChatType.ContactConnection -> MR.strings.error_deleting_pending_contact_connection } apiErrorAlert("apiDeleteChat", generalGetString(titleId), r) } @@ -927,7 +931,7 @@ object ChatController { is CR.UserContactLinkCreated -> r.connReqContact else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiCreateUserAddress", generalGetString(R.string.error_creating_address), r) + apiErrorAlert("apiCreateUserAddress", generalGetString(MR.strings.error_creating_address), r) } null } @@ -974,14 +978,14 @@ object ChatController { && r.chatError.agentError is AgentErrorType.SMP && r.chatError.agentError.smpErr is SMPErrorType.AUTH -> { AlertManager.shared.showAlertMsg( - generalGetString(R.string.connection_error_auth), - generalGetString(R.string.sender_may_have_deleted_the_connection_request) + generalGetString(MR.strings.connection_error_auth), + generalGetString(MR.strings.sender_may_have_deleted_the_connection_request) ) null } else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiAcceptContactRequest", generalGetString(R.string.error_accepting_contact_request), r) + apiErrorAlert("apiAcceptContactRequest", generalGetString(MR.strings.error_accepting_contact_request), r) } null } @@ -1054,8 +1058,8 @@ object ChatController { is CR.RcvFileAccepted -> r.chatItem is CR.RcvFileAcceptedSndCancelled -> { AlertManager.shared.showAlertMsg( - generalGetString(R.string.cannot_receive_file), - generalGetString(R.string.sender_cancelled_file_transfer) + generalGetString(MR.strings.cannot_receive_file), + generalGetString(MR.strings.sender_cancelled_file_transfer) ) null } @@ -1066,7 +1070,7 @@ object ChatController { ) { Log.d(TAG, "apiReceiveFile ignoring FileAlreadyReceiving error") } else { - apiErrorAlert("apiReceiveFile", generalGetString(R.string.error_receiving_file), r) + apiErrorAlert("apiReceiveFile", generalGetString(MR.strings.error_receiving_file), r) } } null @@ -1108,7 +1112,7 @@ object ChatController { is CR.SentGroupInvitation -> r.member else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiAddMember", generalGetString(R.string.error_adding_members), r) + apiErrorAlert("apiAddMember", generalGetString(MR.strings.error_adding_members), r) } null } @@ -1125,15 +1129,15 @@ object ChatController { suspend fun deleteGroup() { if (apiDeleteChat(ChatType.Group, groupId)) { chatModel.removeChat("#$groupId") } } if (e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.SMP && e.agentError.smpErr is SMPErrorType.AUTH) { deleteGroup() - AlertManager.shared.showAlertMsg(generalGetString(R.string.alert_title_group_invitation_expired), generalGetString(R.string.alert_message_group_invitation_expired)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.alert_title_group_invitation_expired), generalGetString(MR.strings.alert_message_group_invitation_expired)) } else if (e is ChatError.ChatErrorStore && e.storeError is StoreError.GroupNotFound) { deleteGroup() - AlertManager.shared.showAlertMsg(generalGetString(R.string.alert_title_no_group), generalGetString(R.string.alert_message_no_group)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.alert_title_no_group), generalGetString(MR.strings.alert_message_no_group)) } else if (!(networkErrorAlert(r))) { - apiErrorAlert("apiJoinGroup", generalGetString(R.string.error_joining_group), r) + apiErrorAlert("apiJoinGroup", generalGetString(MR.strings.error_joining_group), r) } } - else -> apiErrorAlert("apiJoinGroup", generalGetString(R.string.error_joining_group), r) + else -> apiErrorAlert("apiJoinGroup", generalGetString(MR.strings.error_joining_group), r) } } @@ -1142,7 +1146,7 @@ object ChatController { is CR.UserDeletedMember -> r.member else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiRemoveMember", generalGetString(R.string.error_removing_member), r) + apiErrorAlert("apiRemoveMember", generalGetString(MR.strings.error_removing_member), r) } null } @@ -1153,7 +1157,7 @@ object ChatController { is CR.MemberRoleUser -> r.member else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiMemberRole", generalGetString(R.string.error_changing_role), r) + apiErrorAlert("apiMemberRole", generalGetString(MR.strings.error_changing_role), r) } throw Exception("failed to change member role: ${r.responseType} ${r.details}") } @@ -1177,13 +1181,13 @@ object ChatController { return when (val r = sendCmd(CC.ApiUpdateGroupProfile(groupId, groupProfile))) { is CR.GroupUpdated -> r.toGroup is CR.ChatCmdError -> { - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_saving_group_profile), "$r.chatError") + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_saving_group_profile), "$r.chatError") null } else -> { Log.e(TAG, "apiUpdateGroup bad response: ${r.responseType} ${r.details}") AlertManager.shared.showAlertMsg( - generalGetString(R.string.error_saving_group_profile), + generalGetString(MR.strings.error_saving_group_profile), "${r.responseType}: ${r.details}" ) null @@ -1196,7 +1200,7 @@ object ChatController { is CR.GroupLinkCreated -> r.connReqContact to r.memberRole else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiCreateGroupLink", generalGetString(R.string.error_creating_link_for_group), r) + apiErrorAlert("apiCreateGroupLink", generalGetString(MR.strings.error_creating_link_for_group), r) } null } @@ -1208,7 +1212,7 @@ object ChatController { is CR.GroupLink -> r.connReqContact to r.memberRole else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiGroupLinkMemberRole", generalGetString(R.string.error_updating_link_for_group), r) + apiErrorAlert("apiGroupLinkMemberRole", generalGetString(MR.strings.error_updating_link_for_group), r) } null } @@ -1220,7 +1224,7 @@ object ChatController { is CR.GroupLinkDeleted -> true else -> { if (!(networkErrorAlert(r))) { - apiErrorAlert("apiDeleteGroupLink", generalGetString(R.string.error_deleting_link_for_group), r) + apiErrorAlert("apiDeleteGroupLink", generalGetString(MR.strings.error_deleting_link_for_group), r) } false } @@ -1268,8 +1272,8 @@ object ChatController { && r.chatError.agentError is AgentErrorType.BROKER && r.chatError.agentError.brokerErr is BrokerErrorType.TIMEOUT -> { AlertManager.shared.showAlertMsg( - generalGetString(R.string.connection_timeout), - String.format(generalGetString(R.string.network_error_desc), serverHostname(r.chatError.agentError.brokerAddress)) + generalGetString(MR.strings.connection_timeout), + String.format(generalGetString(MR.strings.network_error_desc), serverHostname(r.chatError.agentError.brokerAddress)) ) true } @@ -1277,8 +1281,8 @@ object ChatController { && r.chatError.agentError is AgentErrorType.BROKER && r.chatError.agentError.brokerErr is BrokerErrorType.NETWORK -> { AlertManager.shared.showAlertMsg( - generalGetString(R.string.connection_error), - String.format(generalGetString(R.string.network_error_desc), serverHostname(r.chatError.agentError.brokerAddress)) + generalGetString(MR.strings.connection_error), + String.format(generalGetString(MR.strings.network_error_desc), serverHostname(r.chatError.agentError.brokerAddress)) ) true } @@ -1427,7 +1431,7 @@ object ChatController { r.user, cInfo.id, cInfo.displayName, - generalGetString(if (r.toChatItem != null) R.string.marked_deleted_description else R.string.deleted_description) + generalGetString(if (r.toChatItem != null) MR.strings.marked_deleted_description else MR.strings.deleted_description) ) } if (r.toChatItem == null) { @@ -1705,10 +1709,10 @@ object ChatController { Icon( painterResource(R.drawable.ic_bolt), contentDescription = - if (mode == NotificationsMode.SERVICE) stringResource(R.string.icon_descr_instant_notifications) else stringResource(R.string.periodic_notifications), + if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications), ) Text( - if (mode == NotificationsMode.SERVICE) stringResource(R.string.icon_descr_instant_notifications) else stringResource(R.string.periodic_notifications), + if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications), fontWeight = FontWeight.Bold ) } @@ -1716,16 +1720,16 @@ object ChatController { text = { Column { Text( - if (mode == NotificationsMode.SERVICE) annotatedStringResource(R.string.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(R.string.periodic_notifications_desc), + if (mode == NotificationsMode.SERVICE) annotatedStringResource(MR.strings.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(MR.strings.periodic_notifications_desc), Modifier.padding(bottom = 8.dp) ) Text( - annotatedStringResource(R.string.it_can_disabled_via_settings_notifications_still_shown) + annotatedStringResource(MR.strings.it_can_disabled_via_settings_notifications_still_shown) ) } }, confirmButton = { - TextButton(onClick = AlertManager.shared::hideAlert) { Text(stringResource(R.string.ok)) } + TextButton(onClick = AlertManager.shared::hideAlert) { Text(stringResource(MR.strings.ok)) } } ) } @@ -1742,10 +1746,10 @@ object ChatController { Icon( painterResource(R.drawable.ic_bolt), contentDescription = - if (mode == NotificationsMode.SERVICE) stringResource(R.string.icon_descr_instant_notifications) else stringResource(R.string.periodic_notifications), + if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications), ) Text( - if (mode == NotificationsMode.SERVICE) stringResource(R.string.service_notifications) else stringResource(R.string.periodic_notifications), + if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.service_notifications) else stringResource(MR.strings.periodic_notifications), fontWeight = FontWeight.Bold ) } @@ -1753,14 +1757,14 @@ object ChatController { text = { Column { Text( - if (mode == NotificationsMode.SERVICE) annotatedStringResource(R.string.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(R.string.periodic_notifications_desc), + if (mode == NotificationsMode.SERVICE) annotatedStringResource(MR.strings.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(MR.strings.periodic_notifications_desc), Modifier.padding(bottom = 8.dp) ) - Text(annotatedStringResource(R.string.turn_off_battery_optimization)) + Text(annotatedStringResource(MR.strings.turn_off_battery_optimization)) } }, confirmButton = { - TextButton(onClick = ignoreOptimization) { Text(stringResource(R.string.ok)) } + TextButton(onClick = ignoreOptimization) { Text(stringResource(MR.strings.ok)) } } ) } @@ -1773,10 +1777,10 @@ object ChatController { Icon( painterResource(R.drawable.ic_bolt), contentDescription = - if (mode == NotificationsMode.SERVICE) stringResource(R.string.icon_descr_instant_notifications) else stringResource(R.string.periodic_notifications), + if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications), ) Text( - if (mode == NotificationsMode.SERVICE) stringResource(R.string.service_notifications_disabled) else stringResource(R.string.periodic_notifications_disabled), + if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.service_notifications_disabled) else stringResource(MR.strings.periodic_notifications_disabled), fontWeight = FontWeight.Bold ) } @@ -1784,13 +1788,13 @@ object ChatController { text = { Column { Text( - annotatedStringResource(R.string.turning_off_service_and_periodic), + annotatedStringResource(MR.strings.turning_off_service_and_periodic), Modifier.padding(bottom = 8.dp) ) } }, confirmButton = { - TextButton(onClick = AlertManager.shared::hideAlert) { Text(stringResource(R.string.ok)) } + TextButton(onClick = AlertManager.shared::hideAlert) { Text(stringResource(MR.strings.ok)) } } ) } @@ -1832,6 +1836,7 @@ object ChatController { val sessionMode = appPrefs.networkSessionMode.get() val tcpConnectTimeout = appPrefs.networkTCPConnectTimeout.get() val tcpTimeout = appPrefs.networkTCPTimeout.get() + val tcpTimeoutPerKb = appPrefs.networkTCPTimeoutPerKb.get() val smpPingInterval = appPrefs.networkSMPPingInterval.get() val smpPingCount = appPrefs.networkSMPPingCount.get() val enableKeepAlive = appPrefs.networkEnableKeepAlive.get() @@ -1850,6 +1855,7 @@ object ChatController { sessionMode = sessionMode, tcpConnectTimeout = tcpConnectTimeout, tcpTimeout = tcpTimeout, + tcpTimeoutPerKb = tcpTimeoutPerKb, tcpKeepAlive = tcpKeepAlive, smpPingInterval = smpPingInterval, smpPingCount = smpPingCount @@ -1866,6 +1872,7 @@ object ChatController { appPrefs.networkSessionMode.set(cfg.sessionMode) appPrefs.networkTCPConnectTimeout.set(cfg.tcpConnectTimeout) appPrefs.networkTCPTimeout.set(cfg.tcpTimeout) + appPrefs.networkTCPTimeoutPerKb.set(cfg.tcpTimeoutPerKb) appPrefs.networkSMPPingInterval.set(cfg.smpPingInterval) appPrefs.networkSMPPingCount.set(cfg.smpPingCount) if (cfg.tcpKeepAlive != null) { @@ -2324,16 +2331,16 @@ enum class ProtocolTestStep { @SerialName("deleteFile") DeleteFile; val text: String get() = when (this) { - Connect -> generalGetString(R.string.smp_server_test_connect) - Disconnect -> generalGetString(R.string.smp_server_test_disconnect) - CreateQueue -> generalGetString(R.string.smp_server_test_create_queue) - SecureQueue -> generalGetString(R.string.smp_server_test_secure_queue) - DeleteQueue -> generalGetString(R.string.smp_server_test_delete_queue) - CreateFile -> generalGetString(R.string.smp_server_test_create_file) - UploadFile -> generalGetString(R.string.smp_server_test_upload_file) - DownloadFile -> generalGetString(R.string.smp_server_test_download_file) - CompareFile -> generalGetString(R.string.smp_server_test_compare_file) - DeleteFile -> generalGetString(R.string.smp_server_test_delete_file) + Connect -> generalGetString(MR.strings.smp_server_test_connect) + Disconnect -> generalGetString(MR.strings.smp_server_test_disconnect) + CreateQueue -> generalGetString(MR.strings.smp_server_test_create_queue) + SecureQueue -> generalGetString(MR.strings.smp_server_test_secure_queue) + DeleteQueue -> generalGetString(MR.strings.smp_server_test_delete_queue) + CreateFile -> generalGetString(MR.strings.smp_server_test_create_file) + UploadFile -> generalGetString(MR.strings.smp_server_test_upload_file) + DownloadFile -> generalGetString(MR.strings.smp_server_test_download_file) + CompareFile -> generalGetString(MR.strings.smp_server_test_compare_file) + DeleteFile -> generalGetString(MR.strings.smp_server_test_delete_file) } } @@ -2352,14 +2359,14 @@ data class ProtocolTestFailure( } val localizedDescription: String get() { - val err = String.format(generalGetString(R.string.error_smp_test_failed_at_step), testStep.text) + val err = String.format(generalGetString(MR.strings.error_smp_test_failed_at_step), testStep.text) return when { testError is AgentErrorType.SMP && testError.smpErr is SMPErrorType.AUTH -> - err + " " + generalGetString(R.string.error_smp_test_server_auth) + err + " " + generalGetString(MR.strings.error_smp_test_server_auth) testError is AgentErrorType.XFTP && testError.xftpErr is XFTPErrorType.AUTH -> - err + " " + generalGetString(R.string.error_xftp_test_server_auth) + err + " " + generalGetString(MR.strings.error_xftp_test_server_auth) testError is AgentErrorType.BROKER && testError.brokerErr is BrokerErrorType.NETWORK -> - err + " " + generalGetString(R.string.error_smp_test_certificate) + err + " " + generalGetString(MR.strings.error_smp_test_certificate) else -> err } } @@ -2419,6 +2426,7 @@ data class NetCfg( val sessionMode: TransportSessionMode, val tcpConnectTimeout: Long, // microseconds val tcpTimeout: Long, // microseconds + val tcpTimeoutPerKb: Long, // microseconds val tcpKeepAlive: KeepAliveOpts?, val smpPingInterval: Long, // microseconds val smpPingCount: Int, @@ -2445,6 +2453,7 @@ data class NetCfg( sessionMode = TransportSessionMode.User, tcpConnectTimeout = 10_000_000, tcpTimeout = 7_000_000, + tcpTimeoutPerKb = 10_000, tcpKeepAlive = KeepAliveOpts.defaults, smpPingInterval = 1200_000_000, smpPingCount = 3 @@ -2458,6 +2467,7 @@ data class NetCfg( sessionMode = TransportSessionMode.User, tcpConnectTimeout = 20_000_000, tcpTimeout = 15_000_000, + tcpTimeoutPerKb = 20_000, tcpKeepAlive = KeepAliveOpts.defaults, smpPingInterval = 1200_000_000, smpPingCount = 3 @@ -2621,12 +2631,12 @@ sealed class CustomTimeUnit { val text: String get() = when (this) { - Second -> generalGetString(R.string.custom_time_unit_seconds) - Minute -> generalGetString(R.string.custom_time_unit_minutes) - Hour -> generalGetString(R.string.custom_time_unit_hours) - Day -> generalGetString(R.string.custom_time_unit_days) - Week -> generalGetString(R.string.custom_time_unit_weeks) - Month -> generalGetString(R.string.custom_time_unit_months) + Second -> generalGetString(MR.strings.custom_time_unit_seconds) + Minute -> generalGetString(MR.strings.custom_time_unit_minutes) + Hour -> generalGetString(MR.strings.custom_time_unit_hours) + Day -> generalGetString(MR.strings.custom_time_unit_days) + Week -> generalGetString(MR.strings.custom_time_unit_weeks) + Month -> generalGetString(MR.strings.custom_time_unit_months) } companion object { @@ -2649,24 +2659,24 @@ sealed class CustomTimeUnit { fun toText(seconds: Int): String { val (unit, value) = toTimeUnit(seconds) return when (unit) { - Second -> String.format(generalGetString(R.string.ttl_sec), value) - Minute -> String.format(generalGetString(R.string.ttl_min), value) - Hour -> if (value == 1) String.format(generalGetString(R.string.ttl_hour), 1) else String.format(generalGetString(R.string.ttl_hours), value) - Day -> if (value == 1) String.format(generalGetString(R.string.ttl_day), 1) else String.format(generalGetString(R.string.ttl_days), value) - Week -> if (value == 1) String.format(generalGetString(R.string.ttl_week), 1) else String.format(generalGetString(R.string.ttl_weeks), value) - Month -> if (value == 1) String.format(generalGetString(R.string.ttl_month), 1) else String.format(generalGetString(R.string.ttl_months), value) + Second -> String.format(generalGetString(MR.strings.ttl_sec), value) + Minute -> String.format(generalGetString(MR.strings.ttl_min), value) + Hour -> if (value == 1) String.format(generalGetString(MR.strings.ttl_hour), 1) else String.format(generalGetString(MR.strings.ttl_hours), value) + Day -> if (value == 1) String.format(generalGetString(MR.strings.ttl_day), 1) else String.format(generalGetString(MR.strings.ttl_days), value) + Week -> if (value == 1) String.format(generalGetString(MR.strings.ttl_week), 1) else String.format(generalGetString(MR.strings.ttl_weeks), value) + Month -> if (value == 1) String.format(generalGetString(MR.strings.ttl_month), 1) else String.format(generalGetString(MR.strings.ttl_months), value) } } fun toShortText(seconds: Int): String { val (unit, value) = toTimeUnit(seconds) return when (unit) { - Second -> String.format(generalGetString(R.string.ttl_s), value) - Minute -> String.format(generalGetString(R.string.ttl_m), value) - Hour -> String.format(generalGetString(R.string.ttl_h), value) - Day -> String.format(generalGetString(R.string.ttl_d), value) - Week -> String.format(generalGetString(R.string.ttl_w), value) - Month -> String.format(generalGetString(R.string.ttl_mth), value) + Second -> String.format(generalGetString(MR.strings.ttl_s), value) + Minute -> String.format(generalGetString(MR.strings.ttl_m), value) + Hour -> String.format(generalGetString(MR.strings.ttl_h), value) + Day -> String.format(generalGetString(MR.strings.ttl_d), value) + Week -> String.format(generalGetString(MR.strings.ttl_w), value) + Month -> String.format(generalGetString(MR.strings.ttl_mth), value) } } } @@ -2674,20 +2684,20 @@ sealed class CustomTimeUnit { fun timeText(seconds: Int?): String { if (seconds == null) { - return generalGetString(R.string.feature_off) + return generalGetString(MR.strings.feature_off) } if (seconds == 0) { - String.format(generalGetString(R.string.ttl_sec), 0) + String.format(generalGetString(MR.strings.ttl_sec), 0) } return CustomTimeUnit.toText(seconds) } fun shortTimeText(seconds: Int?): String { if (seconds == null) { - return generalGetString(R.string.feature_off) + return generalGetString(MR.strings.feature_off) } if (seconds == 0) { - String.format(generalGetString(R.string.ttl_s), 0) + String.format(generalGetString(MR.strings.ttl_s), 0) } return CustomTimeUnit.toShortText(seconds) } @@ -2760,10 +2770,10 @@ data class FeatureEnabled( ) { val text: String get() = when { - forUser && forContact -> generalGetString(R.string.feature_enabled) - forUser -> generalGetString(R.string.feature_enabled_for_you) - forContact -> generalGetString(R.string.feature_enabled_for_contact) - else -> generalGetString(R.string.feature_off) + forUser && forContact -> generalGetString(MR.strings.feature_enabled) + forUser -> generalGetString(MR.strings.feature_enabled_for_you) + forContact -> generalGetString(MR.strings.feature_enabled_for_contact) + else -> generalGetString(MR.strings.feature_off) } val iconColor: Color @@ -2837,11 +2847,11 @@ enum class ChatFeature: Feature { override val text: String get() = when(this) { - TimedMessages -> generalGetString(R.string.timed_messages) - FullDelete -> generalGetString(R.string.full_deletion) - Reactions -> generalGetString(R.string.message_reactions) - Voice -> generalGetString(R.string.voice_messages) - Calls -> generalGetString(R.string.audio_video_calls) + TimedMessages -> generalGetString(MR.strings.timed_messages) + FullDelete -> generalGetString(MR.strings.full_deletion) + Reactions -> generalGetString(MR.strings.message_reactions) + Voice -> generalGetString(MR.strings.voice_messages) + Calls -> generalGetString(MR.strings.audio_video_calls) } val icon: Painter @@ -2865,63 +2875,63 @@ enum class ChatFeature: Feature { fun allowDescription(allowed: FeatureAllowed): String = when (this) { TimedMessages -> when (allowed) { - FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_to_send_disappearing_messages) - FeatureAllowed.YES -> generalGetString(R.string.allow_disappearing_messages_only_if) - FeatureAllowed.NO -> generalGetString(R.string.prohibit_sending_disappearing_messages) + FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_to_send_disappearing_messages) + FeatureAllowed.YES -> generalGetString(MR.strings.allow_disappearing_messages_only_if) + FeatureAllowed.NO -> generalGetString(MR.strings.prohibit_sending_disappearing_messages) } FullDelete -> when (allowed) { - FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_irreversibly_delete) - FeatureAllowed.YES -> generalGetString(R.string.allow_irreversible_message_deletion_only_if) - FeatureAllowed.NO -> generalGetString(R.string.contacts_can_mark_messages_for_deletion) + FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_irreversibly_delete) + FeatureAllowed.YES -> generalGetString(MR.strings.allow_irreversible_message_deletion_only_if) + FeatureAllowed.NO -> generalGetString(MR.strings.contacts_can_mark_messages_for_deletion) } Reactions -> when (allowed) { - FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_adding_message_reactions) - FeatureAllowed.YES -> generalGetString(R.string.allow_message_reactions_only_if) - FeatureAllowed.NO -> generalGetString(R.string.prohibit_message_reactions) + FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_adding_message_reactions) + FeatureAllowed.YES -> generalGetString(MR.strings.allow_message_reactions_only_if) + FeatureAllowed.NO -> generalGetString(MR.strings.prohibit_message_reactions) } Voice -> when (allowed) { - FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_to_send_voice_messages) - FeatureAllowed.YES -> generalGetString(R.string.allow_voice_messages_only_if) - FeatureAllowed.NO -> generalGetString(R.string.prohibit_sending_voice_messages) + FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_to_send_voice_messages) + FeatureAllowed.YES -> generalGetString(MR.strings.allow_voice_messages_only_if) + FeatureAllowed.NO -> generalGetString(MR.strings.prohibit_sending_voice_messages) } Calls -> when (allowed) { - FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_to_call) - FeatureAllowed.YES -> generalGetString(R.string.allow_calls_only_if) - FeatureAllowed.NO -> generalGetString(R.string.prohibit_calls) + FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_to_call) + FeatureAllowed.YES -> generalGetString(MR.strings.allow_calls_only_if) + FeatureAllowed.NO -> generalGetString(MR.strings.prohibit_calls) } } fun enabledDescription(enabled: FeatureEnabled): String = when (this) { TimedMessages -> when { - enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_send_disappearing) - enabled.forUser -> generalGetString(R.string.only_you_can_send_disappearing) - enabled.forContact -> generalGetString(R.string.only_your_contact_can_send_disappearing) - else -> generalGetString(R.string.disappearing_prohibited_in_this_chat) + enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contact_can_send_disappearing) + enabled.forUser -> generalGetString(MR.strings.only_you_can_send_disappearing) + enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_send_disappearing) + else -> generalGetString(MR.strings.disappearing_prohibited_in_this_chat) } FullDelete -> when { - enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contacts_can_delete) - enabled.forUser -> generalGetString(R.string.only_you_can_delete_messages) - enabled.forContact -> generalGetString(R.string.only_your_contact_can_delete) - else -> generalGetString(R.string.message_deletion_prohibited) + enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contacts_can_delete) + enabled.forUser -> generalGetString(MR.strings.only_you_can_delete_messages) + enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_delete) + else -> generalGetString(MR.strings.message_deletion_prohibited) } Reactions -> when { - enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_add_message_reactions) - enabled.forUser -> generalGetString(R.string.only_you_can_add_message_reactions) - enabled.forContact -> generalGetString(R.string.only_your_contact_can_add_message_reactions) - else -> generalGetString(R.string.message_reactions_prohibited_in_this_chat) + enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contact_can_add_message_reactions) + enabled.forUser -> generalGetString(MR.strings.only_you_can_add_message_reactions) + enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_add_message_reactions) + else -> generalGetString(MR.strings.message_reactions_prohibited_in_this_chat) } Voice -> when { - enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_send_voice) - enabled.forUser -> generalGetString(R.string.only_you_can_send_voice) - enabled.forContact -> generalGetString(R.string.only_your_contact_can_send_voice) - else -> generalGetString(R.string.voice_prohibited_in_this_chat) + enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contact_can_send_voice) + enabled.forUser -> generalGetString(MR.strings.only_you_can_send_voice) + enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_send_voice) + else -> generalGetString(MR.strings.voice_prohibited_in_this_chat) } Calls -> when { - enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_make_calls) - enabled.forUser -> generalGetString(R.string.only_you_can_make_calls) - enabled.forContact -> generalGetString(R.string.only_your_contact_can_make_calls) - else -> generalGetString(R.string.calls_prohibited_with_this_contact) + enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contact_can_make_calls) + enabled.forUser -> generalGetString(MR.strings.only_you_can_make_calls) + enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_make_calls) + else -> generalGetString(MR.strings.calls_prohibited_with_this_contact) } } } @@ -2942,12 +2952,12 @@ enum class GroupFeature: Feature { override val text: String get() = when(this) { - TimedMessages -> generalGetString(R.string.timed_messages) - DirectMessages -> generalGetString(R.string.direct_messages) - FullDelete -> generalGetString(R.string.full_deletion) - Reactions -> generalGetString(R.string.message_reactions) - Voice -> generalGetString(R.string.voice_messages) - Files -> generalGetString(R.string.files_and_media) + TimedMessages -> generalGetString(MR.strings.timed_messages) + DirectMessages -> generalGetString(MR.strings.direct_messages) + FullDelete -> generalGetString(MR.strings.full_deletion) + Reactions -> generalGetString(MR.strings.message_reactions) + Voice -> generalGetString(MR.strings.voice_messages) + Files -> generalGetString(MR.strings.files_and_media) } val icon: Painter @@ -2974,55 +2984,55 @@ enum class GroupFeature: Feature { if (canEdit) { when(this) { TimedMessages -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_disappearing) - GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_disappearing) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_send_disappearing) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_sending_disappearing) } DirectMessages -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.allow_direct_messages) - GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_direct_messages) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_direct_messages) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_direct_messages) } FullDelete -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_delete_messages) - GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_message_deletion) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_delete_messages) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_message_deletion) } Reactions -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.allow_message_reactions) - GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_message_reactions_group) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_message_reactions) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_message_reactions_group) } Voice -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_voice) - GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_voice) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_send_voice) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_sending_voice) } Files -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_files) - GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_files) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_send_files) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_sending_files) } } } else { when(this) { TimedMessages -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_disappearing) - GroupFeatureEnabled.OFF -> generalGetString(R.string.disappearing_messages_are_prohibited) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_disappearing) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.disappearing_messages_are_prohibited) } DirectMessages -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_dms) - GroupFeatureEnabled.OFF -> generalGetString(R.string.direct_messages_are_prohibited_in_chat) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_dms) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.direct_messages_are_prohibited_in_chat) } FullDelete -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_delete) - GroupFeatureEnabled.OFF -> generalGetString(R.string.message_deletion_prohibited_in_chat) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_delete) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.message_deletion_prohibited_in_chat) } Reactions -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_add_message_reactions) - GroupFeatureEnabled.OFF -> generalGetString(R.string.message_reactions_are_prohibited) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_add_message_reactions) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.message_reactions_are_prohibited) } Voice -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_voice) - GroupFeatureEnabled.OFF -> generalGetString(R.string.voice_messages_are_prohibited) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_voice) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.voice_messages_are_prohibited) } Files -> when(enabled) { - GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_files) - GroupFeatureEnabled.OFF -> generalGetString(R.string.files_are_prohibited_in_group) + GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_files) + GroupFeatureEnabled.OFF -> generalGetString(MR.strings.files_are_prohibited_in_group) } } } @@ -3048,10 +3058,10 @@ sealed class ContactFeatureAllowed { } val text: String get() = when (this) { - is UserDefault -> String.format(generalGetString(R.string.chat_preferences_default), default.text) - is Always -> generalGetString(R.string.chat_preferences_always) - is Yes -> generalGetString(R.string.chat_preferences_yes) - is No -> generalGetString(R.string.chat_preferences_no) + is UserDefault -> String.format(generalGetString(MR.strings.chat_preferences_default), default.text) + is Always -> generalGetString(MR.strings.chat_preferences_always) + is Yes -> generalGetString(MR.strings.chat_preferences_yes) + is No -> generalGetString(MR.strings.chat_preferences_no) } } @@ -3124,9 +3134,9 @@ enum class FeatureAllowed { val text: String get() = when(this) { - ALWAYS -> generalGetString(R.string.chat_preferences_always) - YES -> generalGetString(R.string.chat_preferences_yes) - NO -> generalGetString(R.string.chat_preferences_no) + ALWAYS -> generalGetString(MR.strings.chat_preferences_always) + YES -> generalGetString(MR.strings.chat_preferences_yes) + NO -> generalGetString(MR.strings.chat_preferences_no) } } @@ -3204,8 +3214,8 @@ enum class GroupFeatureEnabled { val text: String get() = when (this) { - ON -> generalGetString(R.string.chat_preferences_on) - OFF -> generalGetString(R.string.chat_preferences_off) + ON -> generalGetString(MR.strings.chat_preferences_on) + OFF -> generalGetString(MR.strings.chat_preferences_off) } val iconColor: Color @@ -3648,7 +3658,7 @@ sealed class CR { is Invalid -> str } - fun noDetails(): String ="${responseType}: " + generalGetString(R.string.no_details) + fun noDetails(): String ="${responseType}: " + generalGetString(MR.strings.no_details) private fun withUser(u: User?, s: String): String = if (u != null) "userId: ${u.userId}\n$s" else s } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/ui/theme/Theme.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/ui/theme/Theme.kt index 8f1ec7eab3..0258ccbea0 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/ui/theme/Theme.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/ui/theme/Theme.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.SimplexApp import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -69,15 +70,15 @@ enum class ThemeColor { val text: String get() = when (this) { - PRIMARY -> generalGetString(R.string.color_primary) - PRIMARY_VARIANT -> generalGetString(R.string.color_primary_variant) - SECONDARY -> generalGetString(R.string.color_secondary) - SECONDARY_VARIANT -> generalGetString(R.string.color_secondary_variant) - BACKGROUND -> generalGetString(R.string.color_background) - SURFACE -> generalGetString(R.string.color_surface) - TITLE -> generalGetString(R.string.color_title) - SENT_MESSAGE -> generalGetString(R.string.color_sent_message) - RECEIVED_MESSAGE -> generalGetString(R.string.color_received_message) + PRIMARY -> generalGetString(MR.strings.color_primary) + PRIMARY_VARIANT -> generalGetString(MR.strings.color_primary_variant) + SECONDARY -> generalGetString(MR.strings.color_secondary) + SECONDARY_VARIANT -> generalGetString(MR.strings.color_secondary_variant) + BACKGROUND -> generalGetString(MR.strings.color_background) + SURFACE -> generalGetString(MR.strings.color_surface) + TITLE -> generalGetString(MR.strings.color_title) + SENT_MESSAGE -> generalGetString(MR.strings.color_sent_message) + RECEIVED_MESSAGE -> generalGetString(MR.strings.color_received_message) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/ui/theme/ThemeManager.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/ui/theme/ThemeManager.kt index b7df77b0ae..03d4af64c6 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/ui/theme/ThemeManager.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/ui/theme/ThemeManager.kt @@ -7,6 +7,7 @@ import chat.simplex.app.R import chat.simplex.app.SimplexApp import chat.simplex.app.model.AppPreferences import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR object ThemeManager { private val appPrefs: AppPreferences by lazy { @@ -62,28 +63,28 @@ object ThemeManager { Triple( if (darkForSystemTheme) systemDarkThemeColors().first else LightColorPalette, DefaultTheme.SYSTEM, - generalGetString(R.string.theme_system) + generalGetString(MR.strings.theme_system) ) ) allThemes.add( Triple( LightColorPalette, DefaultTheme.LIGHT, - generalGetString(R.string.theme_light) + generalGetString(MR.strings.theme_light) ) ) allThemes.add( Triple( DarkColorPalette, DefaultTheme.DARK, - generalGetString(R.string.theme_dark) + generalGetString(MR.strings.theme_dark) ) ) allThemes.add( Triple( SimplexColorPalette, DefaultTheme.SIMPLEX, - generalGetString(R.string.theme_simplex) + generalGetString(MR.strings.theme_simplex) ) ) return allThemes diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/WelcomeView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/WelcomeView.kt index aa89292cde..5156155120 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/WelcomeView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/WelcomeView.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.focus.* import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardCapitalization @@ -31,6 +31,8 @@ import chat.simplex.app.views.helpers.* import chat.simplex.app.views.onboarding.OnboardingStage import chat.simplex.app.views.onboarding.ReadableText import com.google.accompanist.insets.navigationBarsWithImePadding +import chat.simplex.res.MR +import dev.icerock.moko.resources.compose.stringResource import kotlinx.coroutines.delay import kotlinx.coroutines.flow.distinctUntilChanged @@ -55,18 +57,18 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) { } })*/ Column(Modifier.padding(horizontal = DEFAULT_PADDING)) { - AppBarTitle(stringResource(R.string.create_profile), bottomPadding = DEFAULT_PADDING) - ReadableText(R.string.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues(), style = MaterialTheme.typography.body1) - ReadableText(R.string.profile_is_only_shared_with_your_contacts, TextAlign.Center, style = MaterialTheme.typography.body1) + AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING) + ReadableText(MR.strings.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues(), style = MaterialTheme.typography.body1) + ReadableText(MR.strings.profile_is_only_shared_with_your_contacts, TextAlign.Center, style = MaterialTheme.typography.body1) Spacer(Modifier.height(DEFAULT_PADDING)) Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Text( - stringResource(R.string.display_name), + stringResource(MR.strings.display_name), fontSize = 16.sp ) if (!isValidDisplayName(displayName.value)) { Text( - stringResource(R.string.no_spaces), + stringResource(MR.strings.no_spaces), fontSize = 16.sp, color = Color.Red ) @@ -75,7 +77,7 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) { ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester) Spacer(Modifier.height(DEFAULT_PADDING)) Text( - stringResource(R.string.full_name_optional__prompt), + stringResource(MR.strings.full_name_optional__prompt), fontSize = 16.sp, modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF) ) @@ -85,7 +87,7 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) { Row { if (chatModel.users.isEmpty()) { SimpleButtonDecorated( - text = stringResource(R.string.about_simplex), + text = stringResource(MR.strings.about_simplex), icon = painterResource(R.drawable.ic_arrow_back_ios_new), textDecoration = TextDecoration.None, fontWeight = FontWeight.Medium @@ -104,8 +106,8 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) { } Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) { Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) { - Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium) - Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = createColor) + Text(stringResource(MR.strings.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium) + Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(MR.strings.create_profile_button), tint = createColor) } } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/CallView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/CallView.kt index 62f4cc7bd1..bcebcdd580 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/CallView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/CallView.kt @@ -13,7 +13,6 @@ import android.util.Log import android.view.ViewGroup import android.webkit.* import androidx.activity.compose.BackHandler -import androidx.annotation.StringRes import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* @@ -25,7 +24,7 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -42,6 +41,8 @@ import chat.simplex.app.views.helpers.ProfileImage import chat.simplex.app.views.helpers.withApi import chat.simplex.app.views.usersettings.NotificationsMode import com.google.accompanist.permissions.rememberMultiplePermissionsState +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource import kotlinx.coroutines.* import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString @@ -272,14 +273,14 @@ private fun ActiveCallOverlayLayout( ToggleAudioButton(call, toggleAudio) Spacer(Modifier.size(40.dp)) IconButton(onClick = dismiss) { - Icon(painterResource(R.drawable.ic_call_end_filled), stringResource(R.string.icon_descr_hang_up), tint = Color.Red, modifier = Modifier.size(64.dp)) + Icon(painterResource(R.drawable.ic_call_end_filled), stringResource(MR.strings.icon_descr_hang_up), tint = Color.Red, modifier = Modifier.size(64.dp)) } if (call.videoEnabled) { - ControlButton(call, painterResource(R.drawable.ic_flip_camera_android_filled), R.string.icon_descr_flip_camera, flipCamera) - ControlButton(call, painterResource(R.drawable.ic_videocam_filled), R.string.icon_descr_video_off, toggleVideo) + ControlButton(call, painterResource(R.drawable.ic_flip_camera_android_filled), MR.strings.icon_descr_flip_camera, flipCamera) + ControlButton(call, painterResource(R.drawable.ic_videocam_filled), MR.strings.icon_descr_video_off, toggleVideo) } else { Spacer(Modifier.size(48.dp)) - ControlButton(call, painterResource(R.drawable.ic_videocam_off), R.string.icon_descr_video_on, toggleVideo) + ControlButton(call, painterResource(R.drawable.ic_videocam_off), MR.strings.icon_descr_video_on, toggleVideo) } } } @@ -297,7 +298,7 @@ private fun ActiveCallOverlayLayout( Box(Modifier.fillMaxWidth().padding(bottom = DEFAULT_BOTTOM_PADDING), contentAlignment = Alignment.CenterStart) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { IconButton(onClick = dismiss) { - Icon(painterResource(R.drawable.ic_call_end_filled), stringResource(R.string.icon_descr_hang_up), tint = Color.Red, modifier = Modifier.size(64.dp)) + Icon(painterResource(R.drawable.ic_call_end_filled), stringResource(MR.strings.icon_descr_hang_up), tint = Color.Red, modifier = Modifier.size(64.dp)) } } Box(Modifier.padding(start = 32.dp)) { @@ -315,7 +316,7 @@ private fun ActiveCallOverlayLayout( } @Composable -private fun ControlButton(call: Call, icon: Painter, @StringRes iconText: Int, action: () -> Unit, enabled: Boolean = true) { +private fun ControlButton(call: Call, icon: Painter, iconText: StringResource, action: () -> Unit, enabled: Boolean = true) { if (call.hasMedia) { IconButton(onClick = action, enabled = enabled) { Icon(icon, stringResource(iconText), tint = if (enabled) Color(0xFFFFFFD8) else MaterialTheme.colors.secondary, modifier = Modifier.size(40.dp)) @@ -328,18 +329,18 @@ private fun ControlButton(call: Call, icon: Painter, @StringRes iconText: Int, a @Composable private fun ToggleAudioButton(call: Call, toggleAudio: () -> Unit) { if (call.audioEnabled) { - ControlButton(call, painterResource(R.drawable.ic_mic), R.string.icon_descr_audio_off, toggleAudio) + ControlButton(call, painterResource(R.drawable.ic_mic), MR.strings.icon_descr_audio_off, toggleAudio) } else { - ControlButton(call, painterResource(R.drawable.ic_mic_off), R.string.icon_descr_audio_on, toggleAudio) + ControlButton(call, painterResource(R.drawable.ic_mic_off), MR.strings.icon_descr_audio_on, toggleAudio) } } @Composable private fun ToggleSoundButton(call: Call, enabled: Boolean, toggleSound: () -> Unit) { if (call.soundSpeaker) { - ControlButton(call, painterResource(R.drawable.ic_volume_up), R.string.icon_descr_speaker_off, toggleSound, enabled) + ControlButton(call, painterResource(R.drawable.ic_volume_up), MR.strings.icon_descr_speaker_off, toggleSound, enabled) } else { - ControlButton(call, painterResource(R.drawable.ic_volume_down), R.string.icon_descr_speaker_on, toggleSound, enabled) + ControlButton(call, painterResource(R.drawable.ic_volume_down), MR.strings.icon_descr_speaker_on, toggleSound, enabled) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt index 5708759ca9..95181e0509 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt @@ -25,7 +25,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -36,6 +36,7 @@ import chat.simplex.app.model.* import chat.simplex.app.model.NtfManager.OpenChatAction import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.ProfileImage +import chat.simplex.res.MR import kotlinx.datetime.Clock class IncomingCallActivity: ComponentActivity() { @@ -170,18 +171,18 @@ fun IncomingCallLockScreenAlertLayout( Text(invitation.contact.chatViewName, style = MaterialTheme.typography.h2) Spacer(Modifier.fillMaxHeight().weight(1f)) Row { - LockScreenCallButton(stringResource(R.string.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall) + LockScreenCallButton(stringResource(MR.strings.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall) Spacer(Modifier.size(48.dp)) - LockScreenCallButton(stringResource(R.string.ignore), painterResource(R.drawable.ic_close), MaterialTheme.colors.primary, ignoreCall) + LockScreenCallButton(stringResource(MR.strings.ignore), painterResource(R.drawable.ic_close), MaterialTheme.colors.primary, ignoreCall) Spacer(Modifier.size(48.dp)) - LockScreenCallButton(stringResource(R.string.accept), painterResource(R.drawable.ic_check_filled), SimplexGreen, acceptCall) + LockScreenCallButton(stringResource(MR.strings.accept), painterResource(R.drawable.ic_check_filled), SimplexGreen, acceptCall) } } else if (callOnLockScreen == CallOnLockScreen.SHOW) { SimpleXLogo() - Text(stringResource(R.string.open_simplex_chat_to_accept_call), textAlign = TextAlign.Center, lineHeight = 22.sp) - Text(stringResource(R.string.allow_accepting_calls_from_lock_screen), textAlign = TextAlign.Center, style = MaterialTheme.typography.body2, lineHeight = 22.sp) + Text(stringResource(MR.strings.open_simplex_chat_to_accept_call), textAlign = TextAlign.Center, lineHeight = 22.sp) + Text(stringResource(MR.strings.allow_accepting_calls_from_lock_screen), textAlign = TextAlign.Center, style = MaterialTheme.typography.body2, lineHeight = 22.sp) Spacer(Modifier.fillMaxHeight().weight(1f)) - SimpleButton(text = stringResource(R.string.open_verb), icon = painterResource(R.drawable.ic_check_filled), click = openApp) + SimpleButton(text = stringResource(MR.strings.open_verb), icon = painterResource(R.drawable.ic_check_filled), click = openApp) } } } @@ -190,7 +191,7 @@ fun IncomingCallLockScreenAlertLayout( private fun SimpleXLogo() { Image( painter = painterResource(if (isInDarkTheme()) R.drawable.logo_light else R.drawable.logo), - contentDescription = stringResource(R.string.image_descr_simplex_logo), + contentDescription = stringResource(MR.strings.image_descr_simplex_logo), modifier = Modifier .padding(vertical = DEFAULT_PADDING) .fillMaxWidth(0.80f) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallAlertView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallAlertView.kt index a8548fadac..b7e663954e 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallAlertView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/IncomingCallAlertView.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import chat.simplex.app.R @@ -21,6 +21,7 @@ import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.ProfileImage import chat.simplex.app.views.usersettings.ProfilePreview +import chat.simplex.res.MR import kotlinx.datetime.Clock @Composable @@ -59,9 +60,9 @@ fun IncomingCallAlertLayout( ProfilePreview(profileOf = invitation.contact, size = 64.dp) } Row(verticalAlignment = Alignment.CenterVertically) { - CallButton(stringResource(R.string.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall) - CallButton(stringResource(R.string.ignore), painterResource(R.drawable.ic_close), MaterialTheme.colors.primary, ignoreCall) - CallButton(stringResource(R.string.accept), painterResource(R.drawable.ic_check_filled), SimplexGreen, acceptCall) + CallButton(stringResource(MR.strings.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall) + CallButton(stringResource(MR.strings.ignore), painterResource(R.drawable.ic_close), MaterialTheme.colors.primary, ignoreCall) + CallButton(stringResource(MR.strings.accept), painterResource(R.drawable.ic_check_filled), SimplexGreen, acceptCall) } } } @@ -75,8 +76,8 @@ fun IncomingCallInfo(invitation: RcvCallInvitation, chatModel: ChatModel) { ProfileImage(size = 32.dp, image = invitation.user.profile.image, color = MaterialTheme.colors.secondaryVariant) Spacer(Modifier.width(4.dp)) } - if (invitation.callType.media == CallMediaType.Video) CallIcon(painterResource(R.drawable.ic_videocam_filled), stringResource(R.string.icon_descr_video_call)) - else CallIcon(painterResource(R.drawable.ic_call_filled), stringResource(R.string.icon_descr_audio_call)) + if (invitation.callType.media == CallMediaType.Video) CallIcon(painterResource(R.drawable.ic_videocam_filled), stringResource(MR.strings.icon_descr_video_call)) + else CallIcon(painterResource(R.drawable.ic_call_filled), stringResource(MR.strings.icon_descr_audio_call)) Spacer(Modifier.width(4.dp)) Text(invitation.callTypeText, color = MaterialTheme.colors.onBackground) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/WebRTC.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/WebRTC.kt index ac586b80b4..cec29c94fe 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/WebRTC.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/call/WebRTC.kt @@ -1,13 +1,12 @@ package chat.simplex.app.views.call -import android.util.Log import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.toUpperCase +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.* import chat.simplex.app.model.Contact import chat.simplex.app.model.User import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR import kotlinx.datetime.Instant import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -33,9 +32,9 @@ data class Call( val encryptionStatus: String @Composable get() = when(callState) { CallState.WaitCapabilities -> "" - CallState.InvitationSent -> stringResource(if (localEncrypted) R.string.status_e2e_encrypted else R.string.status_no_e2e_encryption) - CallState.InvitationAccepted -> stringResource(if (sharedKey == null) R.string.status_contact_has_no_e2e_encryption else R.string.status_contact_has_e2e_encryption) - else -> stringResource(if (!localEncrypted) R.string.status_no_e2e_encryption else if (sharedKey == null) R.string.status_contact_has_no_e2e_encryption else R.string.status_e2e_encrypted) + CallState.InvitationSent -> stringResource(if (localEncrypted) MR.strings.status_e2e_encrypted else MR.strings.status_no_e2e_encryption) + CallState.InvitationAccepted -> stringResource(if (sharedKey == null) MR.strings.status_contact_has_no_e2e_encryption else MR.strings.status_contact_has_e2e_encryption) + else -> stringResource(if (!localEncrypted) MR.strings.status_no_e2e_encryption else if (sharedKey == null) MR.strings.status_contact_has_no_e2e_encryption else MR.strings.status_e2e_encrypted) } val hasMedia: Boolean get() = callState == CallState.OfferSent || callState == CallState.Negotiated || callState == CallState.Connected @@ -53,15 +52,15 @@ enum class CallState { Ended; val text: String @Composable get() = when(this) { - WaitCapabilities -> stringResource(R.string.callstate_starting) - InvitationSent -> stringResource(R.string.callstate_waiting_for_answer) - InvitationAccepted -> stringResource(R.string.callstate_starting) - OfferSent -> stringResource(R.string.callstate_waiting_for_confirmation) - OfferReceived -> stringResource(R.string.callstate_received_answer) - AnswerReceived -> stringResource(R.string.callstate_received_confirmation) - Negotiated -> stringResource(R.string.callstate_connecting) - Connected -> stringResource(R.string.callstate_connected) - Ended -> stringResource(R.string.callstate_ended) + WaitCapabilities -> stringResource(MR.strings.callstate_starting) + InvitationSent -> stringResource(MR.strings.callstate_waiting_for_answer) + InvitationAccepted -> stringResource(MR.strings.callstate_starting) + OfferSent -> stringResource(MR.strings.callstate_waiting_for_confirmation) + OfferReceived -> stringResource(MR.strings.callstate_received_answer) + AnswerReceived -> stringResource(MR.strings.callstate_received_confirmation) + Negotiated -> stringResource(MR.strings.callstate_connecting) + Connected -> stringResource(MR.strings.callstate_connected) + Ended -> stringResource(MR.strings.callstate_ended) } } @@ -99,12 +98,12 @@ sealed class WCallResponse { @Serializable data class CallType(val media: CallMediaType, val capabilities: CallCapabilities) @Serializable data class RcvCallInvitation(val user: User, val contact: Contact, val callType: CallType, val sharedKey: String? = null, val callTs: Instant) { val callTypeText: String get() = generalGetString(when(callType.media) { - CallMediaType.Video -> if (sharedKey == null) R.string.video_call_no_encryption else R.string.encrypted_video_call - CallMediaType.Audio -> if (sharedKey == null) R.string.audio_call_no_encryption else R.string.encrypted_audio_call + CallMediaType.Video -> if (sharedKey == null) MR.strings.video_call_no_encryption else MR.strings.encrypted_video_call + CallMediaType.Audio -> if (sharedKey == null) MR.strings.audio_call_no_encryption else MR.strings.encrypted_audio_call }) val callTitle: String get() = generalGetString(when(callType.media) { - CallMediaType.Video -> R.string.incoming_video_call - CallMediaType.Audio -> R.string.incoming_audio_call + CallMediaType.Video -> MR.strings.incoming_video_call + CallMediaType.Audio -> MR.strings.incoming_audio_call }) } @Serializable data class CallCapabilities(val encryption: Boolean) @@ -114,9 +113,9 @@ sealed class WCallResponse { val remote = remoteCandidate?.candidateType return when { local == RTCIceCandidateType.Host && remote == RTCIceCandidateType.Host -> - stringResource(R.string.call_connection_peer_to_peer) + stringResource(MR.strings.call_connection_peer_to_peer) local == RTCIceCandidateType.Relay && remote == RTCIceCandidateType.Relay -> - stringResource(R.string.call_connection_via_relay) + stringResource(MR.strings.call_connection_via_relay) else -> "${local?.value ?: "unknown"} / ${remote?.value ?: "unknown"}" } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatInfoView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatInfoView.kt index 2c105155a9..b6ff8c2c49 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatInfoView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatInfoView.kt @@ -21,7 +21,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.* import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight @@ -36,6 +36,7 @@ import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.QRCode import chat.simplex.app.views.usersettings.* +import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.datetime.Clock @@ -125,9 +126,9 @@ fun ChatInfoView( fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> Unit)? = null) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_contact_question), - text = generalGetString(R.string.delete_contact_all_messages_deleted_cannot_undo_warning), - confirmText = generalGetString(R.string.delete_verb), + title = generalGetString(MR.strings.delete_contact_question), + text = generalGetString(MR.strings.delete_contact_all_messages_deleted_cannot_undo_warning), + confirmText = generalGetString(MR.strings.delete_verb), onConfirm = { withApi { val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId) @@ -145,9 +146,9 @@ fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> fun clearChatDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> Unit)? = null) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.clear_chat_question), - text = generalGetString(R.string.clear_chat_warning), - confirmText = generalGetString(R.string.clear_verb), + title = generalGetString(MR.strings.clear_chat_question), + text = generalGetString(MR.strings.clear_chat_warning), + confirmText = generalGetString(MR.strings.clear_verb), onConfirm = { withApi { val updatedChatInfo = chatModel.controller.apiClearChat(chatInfo.chatType, chatInfo.apiId) @@ -196,8 +197,8 @@ fun ChatInfoLayout( LocalAliasEditor(localAlias, updateValue = onLocalAliasChanged) SectionSpacer() if (customUserProfile != null) { - SectionView(generalGetString(R.string.incognito).uppercase()) { - InfoRow(generalGetString(R.string.incognito_random_profile), customUserProfile.chatViewName) + SectionView(generalGetString(MR.strings.incognito).uppercase()) { + InfoRow(generalGetString(MR.strings.incognito_random_profile), customUserProfile.chatViewName) } SectionDividerSpaced() } @@ -211,18 +212,18 @@ fun ChatInfoLayout( SectionDividerSpaced() if (contact.contactLink != null) { - SectionView(stringResource(R.string.address_section_title).uppercase()) { + SectionView(stringResource(MR.strings.address_section_title).uppercase()) { QRCode(contact.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f)) ShareAddressButton { shareText(contact.contactLink) } - SectionTextFooter(stringResource(R.string.you_can_share_this_address_with_your_contacts).format(contact.displayName)) + SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(contact.displayName)) } SectionDividerSpaced() } - SectionView(title = stringResource(R.string.conn_stats_section_title_servers)) { + SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers)) { SectionItemView({ AlertManager.shared.showAlertMsg( - generalGetString(R.string.network_status), + generalGetString(MR.strings.network_status), contactNetworkStatus.statusExplanation )}) { NetworkStatusRow(contactNetworkStatus) @@ -240,11 +241,11 @@ fun ChatInfoLayout( } val rcvServers = cStats.rcvQueuesInfo.map { it.rcvServer } if (rcvServers.isNotEmpty()) { - SimplexServers(stringResource(R.string.receiving_via), rcvServers) + SimplexServers(stringResource(MR.strings.receiving_via), rcvServers) } val sndServers = cStats.sndQueuesInfo.map { it.sndServer } if (sndServers.isNotEmpty()) { - SimplexServers(stringResource(R.string.sending_via), sndServers) + SimplexServers(stringResource(MR.strings.sending_via), sndServers) } } } @@ -256,9 +257,9 @@ fun ChatInfoLayout( if (developerTools) { SectionDividerSpaced() - SectionView(title = stringResource(R.string.section_title_for_console)) { - InfoRow(stringResource(R.string.info_row_local_name), chat.chatInfo.localDisplayName) - InfoRow(stringResource(R.string.info_row_database_id), chat.chatInfo.apiId.toString()) + SectionView(title = stringResource(MR.strings.section_title_for_console)) { + InfoRow(stringResource(MR.strings.info_row_local_name), chat.chatInfo.localDisplayName) + InfoRow(stringResource(MR.strings.info_row_database_id), chat.chatInfo.apiId.toString()) } } SectionBottomSpacer() @@ -313,7 +314,7 @@ fun LocalAliasEditor( value, { Text( - generalGetString(R.string.text_field_set_contact_placeholder), + generalGetString(MR.strings.text_field_set_contact_placeholder), textAlign = if (center) TextAlign.Center else TextAlign.Start, color = MaterialTheme.colors.secondary ) @@ -354,10 +355,10 @@ private fun NetworkStatusRow(networkStatus: NetworkStatus) { verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp) ) { - Text(stringResource(R.string.network_status)) + Text(stringResource(MR.strings.network_status)) Icon( painterResource(R.drawable.ic_info), - stringResource(R.string.network_status), + stringResource(MR.strings.network_status), tint = MaterialTheme.colors.primary ) } @@ -380,12 +381,12 @@ private fun ServerImage(networkStatus: NetworkStatus) { Box(Modifier.size(18.dp)) { when (networkStatus) { is NetworkStatus.Connected -> - Icon(painterResource(R.drawable.ic_circle_filled), stringResource(R.string.icon_descr_server_status_connected), tint = Color.Green) + Icon(painterResource(R.drawable.ic_circle_filled), stringResource(MR.strings.icon_descr_server_status_connected), tint = Color.Green) is NetworkStatus.Disconnected -> - Icon(painterResource(R.drawable.ic_pending_filled), stringResource(R.string.icon_descr_server_status_disconnected), tint = MaterialTheme.colors.secondary) + Icon(painterResource(R.drawable.ic_pending_filled), stringResource(MR.strings.icon_descr_server_status_disconnected), tint = MaterialTheme.colors.secondary) is NetworkStatus.Error -> - Icon(painterResource(R.drawable.ic_error_filled), stringResource(R.string.icon_descr_server_status_error), tint = MaterialTheme.colors.secondary) - else -> Icon(painterResource(R.drawable.ic_circle), stringResource(R.string.icon_descr_server_status_pending), tint = MaterialTheme.colors.secondary) + Icon(painterResource(R.drawable.ic_error_filled), stringResource(MR.strings.icon_descr_server_status_error), tint = MaterialTheme.colors.secondary) + else -> Icon(painterResource(R.drawable.ic_circle), stringResource(MR.strings.icon_descr_server_status_pending), tint = MaterialTheme.colors.secondary) } } } @@ -396,7 +397,7 @@ fun SimplexServers(text: String, servers: List) { val clipboardManager: ClipboardManager = LocalClipboardManager.current InfoRowEllipsis(text, info) { clipboardManager.setText(AnnotatedString(servers.joinToString(separator = ","))) - Toast.makeText(SimplexApp.context, generalGetString(R.string.copied), Toast.LENGTH_SHORT).show() + Toast.makeText(SimplexApp.context, generalGetString(MR.strings.copied), Toast.LENGTH_SHORT).show() } } @@ -404,7 +405,7 @@ fun SimplexServers(text: String, servers: List) { fun SwitchAddressButton(disabled: Boolean, switchAddress: () -> Unit) { SectionItemView(switchAddress) { Text( - stringResource(R.string.switch_receiving_address), + stringResource(MR.strings.switch_receiving_address), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary ) } @@ -414,7 +415,7 @@ fun SwitchAddressButton(disabled: Boolean, switchAddress: () -> Unit) { fun AbortSwitchAddressButton(disabled: Boolean, abortSwitchAddress: () -> Unit) { SectionItemView(abortSwitchAddress) { Text( - stringResource(R.string.abort_switch_receiving_address), + stringResource(MR.strings.abort_switch_receiving_address), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary ) } @@ -424,7 +425,7 @@ fun AbortSwitchAddressButton(disabled: Boolean, abortSwitchAddress: () -> Unit) fun VerifyCodeButton(contactVerified: Boolean, onClick: () -> Unit) { SettingsActionItem( if (contactVerified) painterResource(R.drawable.ic_verified_user) else painterResource(R.drawable.ic_shield), - stringResource(if (contactVerified) R.string.view_security_code else R.string.verify_security_code), + stringResource(if (contactVerified) MR.strings.view_security_code else MR.strings.verify_security_code), click = onClick, iconColor = MaterialTheme.colors.secondary, ) @@ -434,7 +435,7 @@ fun VerifyCodeButton(contactVerified: Boolean, onClick: () -> Unit) { private fun ContactPreferencesButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_toggle_on), - stringResource(R.string.contact_preferences), + stringResource(MR.strings.contact_preferences), click = onClick ) } @@ -443,7 +444,7 @@ private fun ContactPreferencesButton(onClick: () -> Unit) { fun ClearChatButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_settings_backup_restore), - stringResource(R.string.clear_chat_button), + stringResource(MR.strings.clear_chat_button), click = onClick, textColor = WarningOrange, iconColor = WarningOrange, @@ -454,7 +455,7 @@ fun ClearChatButton(onClick: () -> Unit) { private fun DeleteContactButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_delete), - stringResource(R.string.button_delete_contact), + stringResource(MR.strings.button_delete_contact), click = onClick, textColor = Color.Red, iconColor = Color.Red, @@ -465,7 +466,7 @@ private fun DeleteContactButton(onClick: () -> Unit) { fun ShareAddressButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_share_filled), - stringResource(R.string.share_address), + stringResource(MR.strings.share_address), onClick, iconColor = MaterialTheme.colors.primary, textColor = MaterialTheme.colors.primary, @@ -480,18 +481,18 @@ private fun setContactAlias(contactApiId: Long, localAlias: String, chatModel: C fun showSwitchAddressAlert(switchAddress: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.switch_receiving_address_question), - text = generalGetString(R.string.switch_receiving_address_desc), - confirmText = generalGetString(R.string.change_verb), + title = generalGetString(MR.strings.switch_receiving_address_question), + text = generalGetString(MR.strings.switch_receiving_address_desc), + confirmText = generalGetString(MR.strings.change_verb), onConfirm = switchAddress ) } fun showAbortSwitchAddressAlert(abortSwitchAddress: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.abort_switch_receiving_address_question), - text = generalGetString(R.string.abort_switch_receiving_address_desc), - confirmText = generalGetString(R.string.abort_switch_receiving_address_confirm), + title = generalGetString(MR.strings.abort_switch_receiving_address_question), + text = generalGetString(MR.strings.abort_switch_receiving_address_desc), + confirmText = generalGetString(MR.strings.abort_switch_receiving_address_confirm), onConfirm = abortSwitchAddress, destructive = true, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatItemInfoView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatItemInfoView.kt index a6dcaa97be..97a8da402f 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatItemInfoView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatItemInfoView.kt @@ -14,7 +14,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -25,6 +25,7 @@ import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.views.chat.item.ItemAction import chat.simplex.app.views.chat.item.MarkdownText import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) { @@ -48,7 +49,7 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) { ) } else { Text( - generalGetString(R.string.item_info_no_text), + generalGetString(MR.strings.item_info_no_text), style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary, lineHeight = 22.sp, fontStyle = FontStyle.Italic) ) } @@ -72,7 +73,7 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) { ) if (current && ci.meta.itemDeleted == null) { Text( - stringResource(R.string.item_info_current), + stringResource(MR.strings.item_info_current), fontSize = 12.sp, color = MaterialTheme.colors.secondary ) @@ -80,11 +81,11 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) { } if (text != "") { DefaultDropdownMenu(showMenu) { - ItemAction(stringResource(R.string.share_verb), painterResource(R.drawable.ic_share), onClick = { + ItemAction(stringResource(MR.strings.share_verb), painterResource(R.drawable.ic_share), onClick = { shareText(text) showMenu.value = false }) - ItemAction(stringResource(R.string.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = { + ItemAction(stringResource(MR.strings.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = { copyText(text) showMenu.value = false }) @@ -94,37 +95,37 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) { } Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) { - AppBarTitle(stringResource(if (sent) R.string.sent_message else R.string.received_message)) + AppBarTitle(stringResource(if (sent) MR.strings.sent_message else MR.strings.received_message)) SectionView { - InfoRow(stringResource(R.string.info_row_sent_at), localTimestamp(ci.meta.itemTs)) + InfoRow(stringResource(MR.strings.info_row_sent_at), localTimestamp(ci.meta.itemTs)) if (!sent) { - InfoRow(stringResource(R.string.info_row_received_at), localTimestamp(ci.meta.createdAt)) + InfoRow(stringResource(MR.strings.info_row_received_at), localTimestamp(ci.meta.createdAt)) } when (val itemDeleted = ci.meta.itemDeleted) { is CIDeleted.Deleted -> if (itemDeleted.deletedTs != null) { - InfoRow(stringResource(R.string.info_row_deleted_at), localTimestamp(itemDeleted.deletedTs)) + InfoRow(stringResource(MR.strings.info_row_deleted_at), localTimestamp(itemDeleted.deletedTs)) } is CIDeleted.Moderated -> if (itemDeleted.deletedTs != null) { - InfoRow(stringResource(R.string.info_row_moderated_at), localTimestamp(itemDeleted.deletedTs)) + InfoRow(stringResource(MR.strings.info_row_moderated_at), localTimestamp(itemDeleted.deletedTs)) } else -> {} } val deleteAt = ci.meta.itemTimed?.deleteAt if (deleteAt != null) { - InfoRow(stringResource(R.string.info_row_disappears_at), localTimestamp(deleteAt)) + InfoRow(stringResource(MR.strings.info_row_disappears_at), localTimestamp(deleteAt)) } if (devTools) { - InfoRow(stringResource(R.string.info_row_database_id), ci.meta.itemId.toString()) - InfoRow(stringResource(R.string.info_row_updated_at), localTimestamp(ci.meta.updatedAt)) + InfoRow(stringResource(MR.strings.info_row_database_id), ci.meta.itemId.toString()) + InfoRow(stringResource(MR.strings.info_row_updated_at), localTimestamp(ci.meta.updatedAt)) } } val versions = ciInfo.itemVersions if (versions.isNotEmpty()) { SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false) SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) { - Text(stringResource(R.string.edit_history), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING)) + Text(stringResource(MR.strings.edit_history), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING)) versions.forEachIndexed { i, ciVersion -> ItemVersionView(ciVersion, current = i == 0) } @@ -137,47 +138,47 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) { fun itemInfoShareText(ci: ChatItem, chatItemInfo: ChatItemInfo, devTools: Boolean): String { val meta = ci.meta val sent = ci.chatDir.sent - val shareText = mutableListOf(generalGetString(if (sent) R.string.sent_message else R.string.received_message), "") + val shareText = mutableListOf(generalGetString(if (sent) MR.strings.sent_message else MR.strings.received_message), "") - shareText.add(String.format(generalGetString(R.string.share_text_sent_at), localTimestamp(meta.itemTs))) + shareText.add(String.format(generalGetString(MR.strings.share_text_sent_at), localTimestamp(meta.itemTs))) if (!ci.chatDir.sent) { - shareText.add(String.format(generalGetString(R.string.share_text_received_at), localTimestamp(meta.createdAt))) + shareText.add(String.format(generalGetString(MR.strings.share_text_received_at), localTimestamp(meta.createdAt))) } when (val itemDeleted = ci.meta.itemDeleted) { is CIDeleted.Deleted -> if (itemDeleted.deletedTs != null) { - shareText.add(String.format(generalGetString(R.string.share_text_deleted_at), localTimestamp(itemDeleted.deletedTs))) + shareText.add(String.format(generalGetString(MR.strings.share_text_deleted_at), localTimestamp(itemDeleted.deletedTs))) } is CIDeleted.Moderated -> if (itemDeleted.deletedTs != null) { - shareText.add(String.format(generalGetString(R.string.share_text_moderated_at), localTimestamp(itemDeleted.deletedTs))) + shareText.add(String.format(generalGetString(MR.strings.share_text_moderated_at), localTimestamp(itemDeleted.deletedTs))) } else -> {} } val deleteAt = ci.meta.itemTimed?.deleteAt if (deleteAt != null) { - shareText.add(String.format(generalGetString(R.string.share_text_disappears_at), localTimestamp(deleteAt))) + shareText.add(String.format(generalGetString(MR.strings.share_text_disappears_at), localTimestamp(deleteAt))) } if (devTools) { - shareText.add(String.format(generalGetString(R.string.share_text_database_id), meta.itemId)) - shareText.add(String.format(generalGetString(R.string.share_text_updated_at), meta.updatedAt)) + shareText.add(String.format(generalGetString(MR.strings.share_text_database_id), meta.itemId)) + shareText.add(String.format(generalGetString(MR.strings.share_text_updated_at), meta.updatedAt)) } val versions = chatItemInfo.itemVersions if (versions.isNotEmpty()) { shareText.add("") - shareText.add(generalGetString(R.string.edit_history)) + shareText.add(generalGetString(MR.strings.edit_history)) versions.forEachIndexed { index, itemVersion -> val ts = localTimestamp(itemVersion.itemVersionTs) shareText.add("") shareText.add( if (index == 0 && ci.meta.itemDeleted == null) { - String.format(generalGetString(R.string.current_version_timestamp), ts) + String.format(generalGetString(MR.strings.current_version_timestamp), ts) } else { localTimestamp(itemVersion.itemVersionTs) } ) val t = itemVersion.msgContent.text - shareText.add(if (t != "") t else generalGetString(R.string.item_info_no_text)) + shareText.add(if (t != "") t else generalGetString(MR.strings.item_info_no_text)) } } return shareText.joinToString(separator = "\n") diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatView.kt index 809f529844..8ffaac1535 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ChatView.kt @@ -21,7 +21,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.* import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale @@ -41,6 +41,7 @@ import chat.simplex.app.views.helpers.* import chat.simplex.app.views.helpers.AppBarHeight import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsWithImePadding +import chat.simplex.res.MR import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlinx.datetime.Clock @@ -421,7 +422,7 @@ fun ChatInfoToolbar( val barButtons = arrayListOf<@Composable RowScope.() -> Unit>() val menuItems = arrayListOf<@Composable () -> Unit>() menuItems.add { - ItemAction(stringResource(android.R.string.search_go).capitalize(Locale.current), painterResource(R.drawable.ic_search), onClick = { + ItemAction(stringResource(MR.strings.search_verb).capitalize(Locale.current), painterResource(R.drawable.ic_search), onClick = { showMenu.value = false showSearch = true }) @@ -433,11 +434,11 @@ fun ChatInfoToolbar( showMenu.value = false startCall(CallMediaType.Audio) }) { - Icon(painterResource(R.drawable.ic_call_500), stringResource(R.string.icon_descr_more_button), tint = MaterialTheme.colors.primary) + Icon(painterResource(R.drawable.ic_call_500), stringResource(MR.strings.icon_descr_more_button), tint = MaterialTheme.colors.primary) } } menuItems.add { - ItemAction(stringResource(R.string.icon_descr_video_call).capitalize(Locale.current), painterResource(R.drawable.ic_videocam), onClick = { + ItemAction(stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current), painterResource(R.drawable.ic_videocam), onClick = { showMenu.value = false startCall(CallMediaType.Video) }) @@ -448,14 +449,14 @@ fun ChatInfoToolbar( showMenu.value = false addMembers(chat.chatInfo.groupInfo) }) { - Icon(painterResource(R.drawable.ic_person_add_500), stringResource(R.string.icon_descr_add_members), tint = MaterialTheme.colors.primary) + Icon(painterResource(R.drawable.ic_person_add_500), stringResource(MR.strings.icon_descr_add_members), tint = MaterialTheme.colors.primary) } } } val ntfsEnabled = remember { mutableStateOf(chat.chatInfo.ntfsEnabled) } menuItems.add { ItemAction( - if (ntfsEnabled.value) stringResource(R.string.mute_chat) else stringResource(R.string.unmute_chat), + if (ntfsEnabled.value) stringResource(MR.strings.mute_chat) else stringResource(MR.strings.unmute_chat), if (ntfsEnabled.value) painterResource(R.drawable.ic_notifications_off) else painterResource(R.drawable.ic_notifications), onClick = { showMenu.value = false @@ -470,7 +471,7 @@ fun ChatInfoToolbar( barButtons.add { IconButton({ showMenu.value = true }) { - Icon(MoreVertFilled, stringResource(R.string.icon_descr_more_button), tint = MaterialTheme.colors.primary) + Icon(MoreVertFilled, stringResource(MR.strings.icon_descr_more_button), tint = MaterialTheme.colors.primary) } } @@ -828,7 +829,7 @@ fun BoxWithConstraintsScope.FloatingButtons( DefaultDropdownMenu(showDropDown, offset = DpOffset(maxWidth - DEFAULT_PADDING, 24.dp + fabSize)) { ItemAction( - generalGetString(R.string.mark_read), + generalGetString(MR.strings.mark_read), painterResource(R.drawable.ic_check), onClick = { markRead( diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeFileView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeFileView.kt index d90d2493ba..5b51f74a88 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeFileView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeFileView.kt @@ -6,11 +6,12 @@ import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.ui.theme.* +import chat.simplex.res.MR @Composable fun ComposeFileView(fileName: String, cancelFile: () -> Unit, cancelEnabled: Boolean) { @@ -25,7 +26,7 @@ fun ComposeFileView(fileName: String, cancelFile: () -> Unit, cancelEnabled: Boo ) { Icon( painterResource(R.drawable.ic_draft_filled), - stringResource(R.string.icon_descr_file), + stringResource(MR.strings.icon_descr_file), Modifier .padding(start = 4.dp, end = 2.dp) .size(36.dp), @@ -37,7 +38,7 @@ fun ComposeFileView(fileName: String, cancelFile: () -> Unit, cancelEnabled: Boo IconButton(onClick = cancelFile, modifier = Modifier.padding(0.dp)) { Icon( painterResource(R.drawable.ic_close), - contentDescription = stringResource(R.string.icon_descr_cancel_file_preview), + contentDescription = stringResource(MR.strings.icon_descr_cancel_file_preview), tint = MaterialTheme.colors.primary, modifier = Modifier.padding(10.dp) ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeImageView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeImageView.kt index f84bee44c8..14750c04b1 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeImageView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeImageView.kt @@ -12,12 +12,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.UploadContent import chat.simplex.app.views.helpers.base64ToBitmap +import chat.simplex.res.MR @Composable fun ComposeImageView(media: ComposePreview.MediaPreview, cancelImages: () -> Unit, cancelEnabled: Boolean) { @@ -65,7 +66,7 @@ fun ComposeImageView(media: ComposePreview.MediaPreview, cancelImages: () -> Uni IconButton(onClick = cancelImages) { Icon( painterResource(R.drawable.ic_close), - contentDescription = stringResource(R.string.icon_descr_cancel_image_preview), + contentDescription = stringResource(MR.strings.icon_descr_cancel_image_preview), tint = MaterialTheme.colors.primary, ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeView.kt index 8b43cb39ad..a57c2c611b 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeView.kt @@ -28,7 +28,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat import chat.simplex.app.* @@ -36,6 +36,7 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.views.chat.item.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.* import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.serialization.* @@ -193,7 +194,7 @@ fun ComposeView( if (isGranted) { cameraLauncher.launchWithFallback() } else { - Toast.makeText(context, generalGetString(R.string.toast_permission_denied), Toast.LENGTH_SHORT).show() + Toast.makeText(context, generalGetString(MR.strings.toast_permission_denied), Toast.LENGTH_SHORT).show() } } val processPickedMedia = { uris: List, text: String? -> @@ -218,8 +219,8 @@ fun ComposeView( } else { bitmap = null AlertManager.shared.showAlertMsg( - generalGetString(R.string.large_file), - String.format(generalGetString(R.string.maximum_supported_file_size), formatBytes(maxFileSize)) + generalGetString(MR.strings.large_file), + String.format(generalGetString(MR.strings.maximum_supported_file_size), formatBytes(maxFileSize)) ) } } else { @@ -252,8 +253,8 @@ fun ComposeView( } } else { AlertManager.shared.showAlertMsg( - generalGetString(R.string.large_file), - String.format(generalGetString(R.string.maximum_supported_file_size), formatBytes(maxFileSize)) + generalGetString(MR.strings.large_file), + String.format(generalGetString(MR.strings.maximum_supported_file_size), formatBytes(maxFileSize)) ) } } @@ -718,8 +719,8 @@ fun ComposeView( val attachmentClicked = if (isGroupAndProhibitedFiles) { { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.files_and_media_prohibited), - text = generalGetString(R.string.only_owners_can_enable_files_and_media) + title = generalGetString(MR.strings.files_and_media_prohibited), + text = generalGetString(MR.strings.only_owners_can_enable_files_and_media) ) } } else { @@ -728,7 +729,7 @@ fun ComposeView( IconButton(attachmentClicked, enabled = !composeState.value.attachmentDisabled && rememberUpdatedState(chat.userCanSend).value) { Icon( painterResource(R.drawable.ic_attach_file_filled_500), - contentDescription = stringResource(R.string.attach), + contentDescription = stringResource(MR.strings.attach), tint = if (!composeState.value.attachmentDisabled && userCanSend.value && !isGroupAndProhibitedFiles) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, modifier = Modifier .size(28.dp) @@ -860,7 +861,7 @@ class PickMultipleImagesFromGallery: ActivityResultContract>() { if (uri != null) uris.add(uri) } if (itemCount > 10) { - AlertManager.shared.showAlertMsg(R.string.images_limit_title, R.string.images_limit_desc) + AlertManager.shared.showAlertMsg(MR.strings.images_limit_title, MR.strings.images_limit_desc) } uris } @@ -887,7 +888,7 @@ class PickMultipleVideosFromGallery: ActivityResultContract>() { if (uri != null) uris.add(uri) } if (itemCount > 10) { - AlertManager.shared.showAlertMsg(R.string.videos_limit_title, R.string.videos_limit_desc) + AlertManager.shared.showAlertMsg(MR.strings.videos_limit_title, MR.strings.videos_limit_desc) } uris } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeVoiceView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeVoiceView.kt index 4013038a12..dc293af439 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeVoiceView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ComposeVoiceView.kt @@ -11,7 +11,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -19,6 +19,7 @@ import chat.simplex.app.R import chat.simplex.app.model.durationText import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.flow.distinctUntilChanged @Composable @@ -58,7 +59,7 @@ fun ComposeVoiceView( ) { Icon( if (audioPlaying.value) painterResource(R.drawable.ic_pause_filled) else painterResource(R.drawable.ic_play_arrow_filled), - stringResource(R.string.icon_descr_file), + stringResource(MR.strings.icon_descr_file), Modifier .padding(start = 4.dp, end = 2.dp) .size(36.dp), @@ -90,7 +91,7 @@ fun ComposeVoiceView( ) { Icon( painterResource(R.drawable.ic_close), - contentDescription = stringResource(R.string.icon_descr_cancel_file_preview), + contentDescription = stringResource(MR.strings.icon_descr_cancel_file_preview), tint = MaterialTheme.colors.primary, modifier = Modifier.padding(10.dp) ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ContactPreferences.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ContactPreferences.kt index 8e9520d04e..046571e008 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ContactPreferences.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ContactPreferences.kt @@ -14,12 +14,13 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.PreferenceToggle +import chat.simplex.res.MR @Composable fun ContactPreferencesView( @@ -81,7 +82,7 @@ private fun ContactPreferencesLayout( .fillMaxWidth() .verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.contact_preferences)) + AppBarTitle(stringResource(MR.strings.contact_preferences)) val timedMessages: MutableState = remember(featuresAllowed) { mutableStateOf(featuresAllowed.timedMessagesAllowed) } val onTTLUpdated = { ttl: Int? -> applyPrefs(featuresAllowed.copy(timedMessagesTTL = ttl)) @@ -140,14 +141,14 @@ private fun FeatureSection( leadingIcon = true, ) { ExposedDropDownSettingRow( - generalGetString(R.string.chat_preferences_you_allow), + generalGetString(MR.strings.chat_preferences_you_allow), ContactFeatureAllowed.values(userDefault).map { it to it.text }, allowFeature, icon = null, onSelected = onSelected ) InfoRow( - generalGetString(R.string.chat_preferences_contact_allows), + generalGetString(MR.strings.chat_preferences_contact_allows), pref.contactPreference.allow.text ) } @@ -175,13 +176,13 @@ private fun TimedMessagesFeatureSection( leadingIcon = true, ) { PreferenceToggle( - generalGetString(R.string.chat_preferences_you_allow), + generalGetString(MR.strings.chat_preferences_you_allow), checked = allowFeature.value, ) { allow -> onSelected(allow, if (allow) featuresAllowed.timedMessagesTTL ?: 86400 else null) } InfoRow( - generalGetString(R.string.chat_preferences_contact_allows), + generalGetString(MR.strings.chat_preferences_contact_allows), pref.contactPreference.allow.text ) if (featuresAllowed.timedMessagesAllowed) { @@ -189,14 +190,14 @@ private fun TimedMessagesFeatureSection( DropdownCustomTimePickerSettingRow( selection = ttl, propagateExternalSelectionUpdate = true, // for Reset - label = generalGetString(R.string.delete_after), + label = generalGetString(MR.strings.delete_after), dropdownValues = TimedMessagesPreference.ttlValues, - customPickerTitle = generalGetString(R.string.delete_after), - customPickerConfirmButtonText = generalGetString(R.string.custom_time_picker_select), + customPickerTitle = generalGetString(MR.strings.delete_after), + customPickerConfirmButtonText = generalGetString(MR.strings.custom_time_picker_select), onSelected = onTTLUpdated ) } else if (pref.contactPreference.allow == FeatureAllowed.YES || pref.contactPreference.allow == FeatureAllowed.ALWAYS) { - InfoRow(generalGetString(R.string.delete_after), timeText(pref.contactPreference.ttl)) + InfoRow(generalGetString(MR.strings.delete_after), timeText(pref.contactPreference.ttl)) } } SectionTextFooter(ChatFeature.TimedMessages.enabledDescription(enabled)) @@ -206,19 +207,19 @@ private fun TimedMessagesFeatureSection( private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) { SectionView { SectionItemView(reset, disabled = disabled) { - Text(stringResource(R.string.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } SectionItemView(save, disabled = disabled) { - Text(stringResource(R.string.save_and_notify_contact), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(stringResource(MR.strings.save_and_notify_contact), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } } } private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) { AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.save_preferences_question), - confirmText = generalGetString(R.string.save_and_notify_contact), - dismissText = generalGetString(R.string.exit_without_saving), + title = generalGetString(MR.strings.save_preferences_question), + confirmText = generalGetString(MR.strings.save_and_notify_contact), + dismissText = generalGetString(MR.strings.exit_without_saving), onConfirm = save, onDismiss = revert, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ContextItemView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ContextItemView.kt index 5a24eaf525..fda4893d47 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ContextItemView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ContextItemView.kt @@ -9,13 +9,14 @@ import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.item.* +import chat.simplex.res.MR import kotlinx.datetime.Clock @Composable @@ -46,7 +47,7 @@ fun ContextItemView( .padding(horizontal = 8.dp) .height(20.dp) .width(20.dp), - contentDescription = stringResource(R.string.icon_descr_context), + contentDescription = stringResource(MR.strings.icon_descr_context), tint = MaterialTheme.colors.secondary, ) MarkdownText( @@ -59,7 +60,7 @@ fun ContextItemView( IconButton(onClick = cancelContextItem) { Icon( painterResource(R.drawable.ic_close), - contentDescription = stringResource(R.string.cancel_verb), + contentDescription = stringResource(MR.strings.cancel_verb), tint = MaterialTheme.colors.primary, modifier = Modifier.padding(10.dp) ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ScanCodeView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ScanCodeView.kt index e9e159137a..69304f8398 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ScanCodeView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/ScanCodeView.kt @@ -6,12 +6,13 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.R import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.QRCodeScanner import com.google.accompanist.permissions.rememberPermissionState +import chat.simplex.res.MR @Composable fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: () -> Unit) { @@ -29,7 +30,7 @@ private fun ScanCodeLayout(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, .fillMaxSize() .padding(horizontal = DEFAULT_PADDING) ) { - AppBarTitle(stringResource(R.string.scan_code), false) + AppBarTitle(stringResource(MR.strings.scan_code), false) Box( Modifier .fillMaxWidth() @@ -42,12 +43,12 @@ private fun ScanCodeLayout(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close() } else { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.incorrect_code) + title = generalGetString(MR.strings.incorrect_code) ) } } } } - Text(stringResource(R.string.scan_code_from_contacts_app)) + Text(stringResource(MR.strings.scan_code_from_contacts_app)) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/SendMsgView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/SendMsgView.kt index 43fcc155ef..6565ad2908 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/SendMsgView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/SendMsgView.kt @@ -48,6 +48,9 @@ import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.item.ItemAction import chat.simplex.app.views.helpers.* import com.google.accompanist.permissions.rememberMultiplePermissionsState +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource +import dev.icerock.moko.resources.compose.stringResource import kotlinx.coroutines.* import java.lang.reflect.Field @@ -96,8 +99,8 @@ fun SendMsgView( .matchParentSize() .clickable(enabled = !userCanSend, indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.observer_cant_send_message_title), - text = generalGetString(R.string.observer_cant_send_message_desc) + title = generalGetString(MR.strings.observer_cant_send_message_title), + text = generalGetString(MR.strings.observer_cant_send_message_desc) ) }) ) @@ -175,7 +178,7 @@ fun SendMsgView( ) { menuItems.add { ItemAction( - generalGetString(R.string.send_live_message), + generalGetString(MR.strings.send_live_message), BoltFilled, onClick = { startLiveMessage(scope, sendLiveMessage, updateLiveMessage, sendButtonSize, sendButtonAlpha, composeState, liveMessageAlertShown) @@ -187,7 +190,7 @@ fun SendMsgView( if (timedMessageAllowed) { menuItems.add { ItemAction( - generalGetString(R.string.disappearing_message), + generalGetString(MR.strings.disappearing_message), painterResource(R.drawable.ic_timer), onClick = { showCustomDisappearingMessageDialog.value = true @@ -230,8 +233,8 @@ private fun CustomDisappearingMessageDialog( } CustomTimePickerDialog( selectedDisappearingMessageTime, - title = generalGetString(R.string.delete_after), - confirmButtonText = generalGetString(R.string.send_disappearing_message_send), + title = generalGetString(MR.strings.delete_after), + confirmButtonText = generalGetString(MR.strings.send_disappearing_message_send), confirmButtonAction = { ttl -> sendMessage(ttl) customDisappearingMessageTimePref?.set?.invoke(ttl) @@ -273,13 +276,13 @@ private fun CustomDisappearingMessageDialog( ) { Text(" ") // centers title Text( - generalGetString(R.string.send_disappearing_message), + generalGetString(MR.strings.send_disappearing_message), fontSize = 16.sp, color = MaterialTheme.colors.secondary ) Icon( painterResource(R.drawable.ic_close), - generalGetString(R.string.icon_descr_close_button), + generalGetString(MR.strings.icon_descr_close_button), tint = MaterialTheme.colors.secondary, modifier = Modifier .size(25.dp) @@ -287,19 +290,19 @@ private fun CustomDisappearingMessageDialog( ) } - ChoiceButton(generalGetString(R.string.send_disappearing_message_30_seconds)) { + ChoiceButton(generalGetString(MR.strings.send_disappearing_message_30_seconds)) { sendMessage(30) setShowDialog(false) } - ChoiceButton(generalGetString(R.string.send_disappearing_message_1_minute)) { + ChoiceButton(generalGetString(MR.strings.send_disappearing_message_1_minute)) { sendMessage(60) setShowDialog(false) } - ChoiceButton(generalGetString(R.string.send_disappearing_message_5_minutes)) { + ChoiceButton(generalGetString(MR.strings.send_disappearing_message_5_minutes)) { sendMessage(300) setShowDialog(false) } - ChoiceButton(generalGetString(R.string.send_disappearing_message_custom_time)) { + ChoiceButton(generalGetString(MR.strings.send_disappearing_message_custom_time)) { showCustomTimePicker.value = true } } @@ -411,14 +414,14 @@ private fun NativeKeyboard( showDeleteTextButton.value = it.lineCount >= 4 && !cs.inProgress } if (composeState.value.preview is ComposePreview.VoicePreview) { - ComposeOverlay(R.string.voice_message_send_text, textStyle, padding) + ComposeOverlay(MR.strings.voice_message_send_text, textStyle, padding) } else if (userIsObserver) { - ComposeOverlay(R.string.you_are_observer, textStyle, padding) + ComposeOverlay(MR.strings.you_are_observer, textStyle, padding) } } @Composable -private fun ComposeOverlay(textId: Int, textStyle: MutableState, padding: PaddingValues) { +private fun ComposeOverlay(textId: StringResource, textStyle: MutableState, padding: PaddingValues) { Text( generalGetString(textId), Modifier.padding(padding), @@ -491,7 +494,7 @@ private fun DisallowedVoiceButton(enabled: Boolean, onClick: () -> Unit) { IconButton(onClick, Modifier.size(36.dp), enabled = enabled) { Icon( painterResource(R.drawable.ic_keyboard_voice), - stringResource(R.string.icon_descr_record_voice_message), + stringResource(MR.strings.icon_descr_record_voice_message), tint = MaterialTheme.colors.secondary, modifier = Modifier .size(36.dp) @@ -505,7 +508,7 @@ private fun VoiceButtonWithoutPermission(onClick: () -> Unit) { IconButton(onClick, Modifier.size(36.dp)) { Icon( painterResource(R.drawable.ic_keyboard_voice_filled), - stringResource(R.string.icon_descr_record_voice_message), + stringResource(MR.strings.icon_descr_record_voice_message), tint = MaterialTheme.colors.primary, modifier = Modifier .size(34.dp) @@ -537,7 +540,7 @@ private fun StopRecordButton(onClick: () -> Unit) { IconButton(onClick, Modifier.size(36.dp)) { Icon( painterResource(R.drawable.ic_stop_filled), - stringResource(R.string.icon_descr_record_voice_message), + stringResource(MR.strings.icon_descr_record_voice_message), tint = MaterialTheme.colors.primary, modifier = Modifier .size(36.dp) @@ -551,7 +554,7 @@ private fun RecordVoiceButton(interactionSource: MutableInteractionSource) { IconButton({}, Modifier.size(36.dp), interactionSource = interactionSource) { Icon( painterResource(R.drawable.ic_keyboard_voice_filled), - stringResource(R.string.icon_descr_record_voice_message), + stringResource(MR.strings.icon_descr_record_voice_message), tint = MaterialTheme.colors.primary, modifier = Modifier .size(34.dp) @@ -572,7 +575,7 @@ private fun CancelLiveMessageButton( IconButton(onClick, Modifier.size(36.dp)) { Icon( painterResource(R.drawable.ic_close), - stringResource(R.string.icon_descr_cancel_live_message), + stringResource(MR.strings.icon_descr_cancel_live_message), tint = MaterialTheme.colors.primary, modifier = Modifier .size(36.dp) @@ -605,7 +608,7 @@ private fun SendMsgButton( ) { Icon( icon, - stringResource(R.string.icon_descr_send_message), + stringResource(MR.strings.icon_descr_send_message), tint = Color.White, modifier = Modifier .size(sizeDp.value.dp) @@ -634,7 +637,7 @@ private fun StartLiveMessageButton(enabled: Boolean, onClick: () -> Unit) { ) { Icon( BoltFilled, - stringResource(R.string.icon_descr_send_message), + stringResource(MR.strings.icon_descr_send_message), tint = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, modifier = Modifier .size(36.dp) @@ -685,9 +688,9 @@ private fun startLiveMessage( start() } else { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.live_message), - text = generalGetString(R.string.send_live_message_desc), - confirmText = generalGetString(R.string.send_verb), + title = generalGetString(MR.strings.live_message), + text = generalGetString(MR.strings.send_live_message_desc), + confirmText = generalGetString(MR.strings.send_verb), onConfirm = { liveMessageAlertShown.set(true) start() @@ -697,22 +700,22 @@ private fun startLiveMessage( private fun showNeedToAllowVoiceAlert(onConfirm: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.allow_voice_messages_question), - text = generalGetString(R.string.you_need_to_allow_to_send_voice), - confirmText = generalGetString(R.string.allow_verb), - dismissText = generalGetString(R.string.cancel_verb), + title = generalGetString(MR.strings.allow_voice_messages_question), + text = generalGetString(MR.strings.you_need_to_allow_to_send_voice), + confirmText = generalGetString(MR.strings.allow_verb), + dismissText = generalGetString(MR.strings.cancel_verb), onConfirm = onConfirm, ) } private fun showDisabledVoiceAlert(isDirectChat: Boolean) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.voice_messages_prohibited), + title = generalGetString(MR.strings.voice_messages_prohibited), text = generalGetString( if (isDirectChat) - R.string.ask_your_contact_to_enable_voice + MR.strings.ask_your_contact_to_enable_voice else - R.string.only_group_owners_can_enable_voice + MR.strings.only_group_owners_can_enable_voice ) ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/VerifyCodeView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/VerifyCodeView.kt index 472883d556..48b2e80e06 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/VerifyCodeView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/VerifyCodeView.kt @@ -11,7 +11,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -19,6 +19,7 @@ import chat.simplex.app.R import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.QRCode +import chat.simplex.res.MR @Composable fun VerifyCodeView( @@ -60,14 +61,14 @@ private fun VerifyCodeLayout( .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING) ) { - AppBarTitle(stringResource(R.string.security_code), false) + AppBarTitle(stringResource(MR.strings.security_code), false) val splitCode = splitToParts(connectionCode, 24) Row(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), horizontalArrangement = Arrangement.Center) { if (connectionVerified) { Icon(painterResource(R.drawable.ic_verified_user), null, Modifier.padding(end = 4.dp).size(22.dp), tint = MaterialTheme.colors.secondary) - Text(String.format(stringResource(R.string.is_verified), displayName)) + Text(String.format(stringResource(MR.strings.is_verified), displayName)) } else { - Text(String.format(stringResource(R.string.is_not_verified), displayName)) + Text(String.format(stringResource(MR.strings.is_not_verified), displayName)) } } @@ -94,7 +95,7 @@ private fun VerifyCodeLayout( } Text( - generalGetString(R.string.to_verify_compare), + generalGetString(MR.strings.to_verify_compare), Modifier.padding(bottom = DEFAULT_PADDING) ) @@ -103,20 +104,20 @@ private fun VerifyCodeLayout( horizontalArrangement = Arrangement.spacedBy(10.dp) ) { if (connectionVerified) { - SimpleButton(generalGetString(R.string.clear_verification), painterResource(R.drawable.ic_shield)) { + SimpleButton(generalGetString(MR.strings.clear_verification), painterResource(R.drawable.ic_shield)) { verifyCode(null) {} } } else { - SimpleButton(generalGetString(R.string.scan_code), painterResource(R.drawable.ic_qr_code)) { + SimpleButton(generalGetString(MR.strings.scan_code), painterResource(R.drawable.ic_qr_code)) { ModalManager.shared.showModal { ScanCodeView(verifyCode) { } } } - SimpleButton(generalGetString(R.string.mark_code_verified), painterResource(R.drawable.ic_verified_user)) { + SimpleButton(generalGetString(MR.strings.mark_code_verified), painterResource(R.drawable.ic_verified_user)) { verifyCode(connectionCode) { verified -> if (!verified) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.incorrect_code) + title = generalGetString(MR.strings.incorrect_code) ) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt index 9d5284bbe7..764621f4a1 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/AddGroupMembersView.kt @@ -19,7 +19,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -32,6 +32,7 @@ import chat.simplex.app.views.chat.ChatInfoToolbarTitle import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.InfoAboutIncognito import chat.simplex.app.views.usersettings.SettingsActionItem +import chat.simplex.res.MR @Composable fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, chatModel: ChatModel, close: () -> Unit) { @@ -112,12 +113,12 @@ fun AddGroupMembersLayout( .fillMaxWidth() .verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.button_add_members)) + AppBarTitle(stringResource(MR.strings.button_add_members)) InfoAboutIncognito( chatModelIncognito, false, - generalGetString(R.string.group_unsupported_incognito_main_profile_sent), - generalGetString(R.string.group_main_profile_sent), + generalGetString(MR.strings.group_unsupported_incognito_main_profile_sent), + generalGetString(MR.strings.group_main_profile_sent), true ) Spacer(Modifier.size(DEFAULT_PADDING)) @@ -139,7 +140,7 @@ fun AddGroupMembersLayout( horizontalArrangement = Arrangement.Center ) { Text( - stringResource(R.string.no_contacts_to_add), + stringResource(MR.strings.no_contacts_to_add), Modifier.padding(), color = MaterialTheme.colors.secondary ) @@ -148,7 +149,7 @@ fun AddGroupMembersLayout( SectionView { if (creatingGroup) { SectionItemView(openPreferences) { - Text(stringResource(R.string.set_group_preferences)) + Text(stringResource(MR.strings.set_group_preferences)) } } RoleSelectionRow(groupInfo, selectedRole, allowModifyMembers) @@ -162,7 +163,7 @@ fun AddGroupMembersLayout( InviteSectionFooter(selectedContactsCount = selectedContacts.size, allowModifyMembers, clearSelection) } SectionDividerSpaced(maxTopPadding = true) - SectionView(stringResource(R.string.select_contacts)) { + SectionView(stringResource(MR.strings.select_contacts)) { SectionItemView(padding = PaddingValues(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF)) { SearchRowView(searchText, selectedContacts.size) } @@ -179,7 +180,7 @@ private fun SearchRowView( selectedContactsSize: Int ) { Box(Modifier.width(36.dp), contentAlignment = Alignment.Center) { - Icon(painterResource(R.drawable.ic_search), stringResource(android.R.string.search_go), tint = MaterialTheme.colors.secondary) + Icon(painterResource(R.drawable.ic_search), stringResource(MR.strings.search_verb), tint = MaterialTheme.colors.secondary) } Spacer(Modifier.width(DEFAULT_SPACE_AFTER_ICON)) SearchTextField(Modifier.fillMaxWidth(), searchText = searchText, alwaysVisible = true) { @@ -201,7 +202,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState Unit, disabled: Boolean) { SettingsActionItem( painterResource(R.drawable.ic_check), - stringResource(R.string.invite_to_group_button), + stringResource(MR.strings.invite_to_group_button), click = onClick, textColor = MaterialTheme.colors.primary, iconColor = MaterialTheme.colors.primary, @@ -226,7 +227,7 @@ fun InviteMembersButton(onClick: () -> Unit, disabled: Boolean) { fun SkipInvitingButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_check), - stringResource(R.string.skip_inviting_button), + stringResource(MR.strings.skip_inviting_button), click = onClick, textColor = MaterialTheme.colors.primary, iconColor = MaterialTheme.colors.primary, @@ -242,7 +243,7 @@ fun InviteSectionFooter(selectedContactsCount: Int, enabled: Boolean, clearSelec ) { if (selectedContactsCount >= 1) { Text( - String.format(generalGetString(R.string.num_contacts_selected), selectedContactsCount), + String.format(generalGetString(MR.strings.num_contacts_selected), selectedContactsCount), color = MaterialTheme.colors.secondary, fontSize = 12.sp ) @@ -250,14 +251,14 @@ fun InviteSectionFooter(selectedContactsCount: Int, enabled: Boolean, clearSelec Modifier.clickable { if (enabled) clearSelection() } ) { Text( - stringResource(R.string.clear_contacts_selection_button), + stringResource(MR.strings.clear_contacts_selection_button), color = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, fontSize = 12.sp ) } } else { Text( - stringResource(R.string.no_contacts_selected), + stringResource(MR.strings.no_contacts_selected), color = MaterialTheme.colors.secondary, fontSize = 12.sp ) @@ -328,7 +329,7 @@ fun ContactCheckRow( Spacer(Modifier.fillMaxWidth().weight(1f)) Icon( icon, - contentDescription = stringResource(R.string.icon_descr_contact_checked), + contentDescription = stringResource(MR.strings.icon_descr_contact_checked), tint = iconColor ) } @@ -336,9 +337,9 @@ fun ContactCheckRow( fun showProhibitedToInviteIncognitoAlertDialog() { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.invite_prohibited), - text = generalGetString(R.string.invite_prohibited_description), - confirmText = generalGetString(R.string.ok), + title = generalGetString(MR.strings.invite_prohibited), + text = generalGetString(MR.strings.invite_prohibited_description), + confirmText = generalGetString(MR.strings.ok), ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt index fdb94ac6fa..b5b972b959 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupChatInfoView.kt @@ -18,7 +18,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextOverflow @@ -34,6 +34,7 @@ import chat.simplex.app.views.chatlist.cantInviteIncognitoAlert import chat.simplex.app.views.chatlist.setGroupMembers import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.* +import chat.simplex.res.MR @Composable fun GroupChatInfoView(chatModel: ChatModel, groupLink: String?, groupLinkMemberRole: GroupMemberRole?, onGroupLinkUpdated: (Pair) -> Unit, close: () -> Unit) { @@ -108,12 +109,12 @@ fun GroupChatInfoView(chatModel: ChatModel, groupLink: String?, groupLinkMemberR fun deleteGroupDialog(chatInfo: ChatInfo, groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> Unit)? = null) { val alertTextKey = - if (groupInfo.membership.memberCurrent) R.string.delete_group_for_all_members_cannot_undo_warning - else R.string.delete_group_for_self_cannot_undo_warning + if (groupInfo.membership.memberCurrent) MR.strings.delete_group_for_all_members_cannot_undo_warning + else MR.strings.delete_group_for_self_cannot_undo_warning AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_group_question), + title = generalGetString(MR.strings.delete_group_question), text = generalGetString(alertTextKey), - confirmText = generalGetString(R.string.delete_verb), + confirmText = generalGetString(MR.strings.delete_verb), onConfirm = { withApi { val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId) @@ -131,9 +132,9 @@ fun deleteGroupDialog(chatInfo: ChatInfo, groupInfo: GroupInfo, chatModel: ChatM fun leaveGroupDialog(groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> Unit)? = null) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.leave_group_question), - text = generalGetString(R.string.you_will_stop_receiving_messages_from_this_group_chat_history_will_be_preserved), - confirmText = generalGetString(R.string.leave_group_button), + title = generalGetString(MR.strings.leave_group_question), + text = generalGetString(MR.strings.you_will_stop_receiving_messages_from_this_group_chat_history_will_be_preserved), + confirmText = generalGetString(MR.strings.leave_group_button), onConfirm = { withApi { chatModel.controller.leaveGroup(groupInfo.groupId) @@ -183,10 +184,10 @@ fun GroupChatInfoLayout( } GroupPreferencesButton(openPreferences) } - SectionTextFooter(stringResource(R.string.only_group_owners_can_change_prefs)) + SectionTextFooter(stringResource(MR.strings.only_group_owners_can_change_prefs)) SectionDividerSpaced(maxTopPadding = true) - SectionView(title = String.format(generalGetString(R.string.group_info_section_title_num_members), members.count() + 1)) { + SectionView(title = String.format(generalGetString(MR.strings.group_info_section_title_num_members), members.count() + 1)) { if (groupInfo.canAddMembers) { if (groupLink == null) { CreateGroupLinkButton(manageGroupLink) @@ -199,7 +200,7 @@ fun GroupChatInfoLayout( AddMembersButton(tint, onAddMembersClick) } val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) } - val filteredMembers = derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim()) } } + val filteredMembers = remember { derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim()) } } } if (members.size > 8) { SectionItemView(padding = PaddingValues(start = 14.dp, end = DEFAULT_PADDING_HALF)) { SearchRowView(searchText) @@ -223,9 +224,9 @@ fun GroupChatInfoLayout( if (developerTools) { SectionDividerSpaced() - SectionView(title = stringResource(R.string.section_title_for_console)) { - InfoRow(stringResource(R.string.info_row_local_name), groupInfo.localDisplayName) - InfoRow(stringResource(R.string.info_row_database_id), groupInfo.apiId.toString()) + SectionView(title = stringResource(MR.strings.section_title_for_console)) { + InfoRow(stringResource(MR.strings.info_row_local_name), groupInfo.localDisplayName) + InfoRow(stringResource(MR.strings.info_row_database_id), groupInfo.apiId.toString()) } } SectionBottomSpacer() @@ -260,7 +261,7 @@ private fun GroupChatInfoHeader(cInfo: ChatInfo) { private fun GroupPreferencesButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_toggle_on), - stringResource(R.string.group_preferences), + stringResource(MR.strings.group_preferences), click = onClick ) } @@ -269,7 +270,7 @@ private fun GroupPreferencesButton(onClick: () -> Unit) { private fun AddMembersButton(tint: Color = MaterialTheme.colors.primary, onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_add), - stringResource(R.string.button_add_members), + stringResource(MR.strings.button_add_members), onClick, iconColor = tint, textColor = tint @@ -313,7 +314,7 @@ private fun MemberRow(member: GroupMember, user: Boolean = false) { ) } val s = member.memberStatus.shortText - val statusDescr = if (user) String.format(generalGetString(R.string.group_info_member_you), s) else s + val statusDescr = if (user) String.format(generalGetString(MR.strings.group_info_member_you), s) else s Text( statusDescr, color = MaterialTheme.colors.secondary, @@ -339,7 +340,7 @@ private fun MemberVerifiedShield() { private fun GroupLinkButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_link), - stringResource(R.string.group_link), + stringResource(MR.strings.group_link), onClick, iconColor = MaterialTheme.colors.secondary ) @@ -349,7 +350,7 @@ private fun GroupLinkButton(onClick: () -> Unit) { private fun CreateGroupLinkButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_add_link), - stringResource(R.string.create_group_link), + stringResource(MR.strings.create_group_link), onClick, iconColor = MaterialTheme.colors.secondary ) @@ -359,7 +360,7 @@ private fun CreateGroupLinkButton(onClick: () -> Unit) { fun EditGroupProfileButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_edit), - stringResource(R.string.button_edit_group_profile), + stringResource(MR.strings.button_edit_group_profile), onClick, iconColor = MaterialTheme.colors.secondary ) @@ -368,9 +369,9 @@ fun EditGroupProfileButton(onClick: () -> Unit) { @Composable private fun AddOrEditWelcomeMessage(welcomeMessage: String?, onClick: () -> Unit) { val text = if (welcomeMessage == null) { - stringResource(R.string.button_add_welcome_message) + stringResource(MR.strings.button_add_welcome_message) } else { - stringResource(R.string.button_welcome_message) + stringResource(MR.strings.button_welcome_message) } SettingsActionItem( painterResource(R.drawable.ic_maps_ugc), @@ -384,7 +385,7 @@ private fun AddOrEditWelcomeMessage(welcomeMessage: String?, onClick: () -> Unit private fun LeaveGroupButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_logout), - stringResource(R.string.button_leave_group), + stringResource(MR.strings.button_leave_group), onClick, iconColor = Color.Red, textColor = Color.Red @@ -395,7 +396,7 @@ private fun LeaveGroupButton(onClick: () -> Unit) { private fun DeleteGroupButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_delete), - stringResource(R.string.button_delete_group), + stringResource(MR.strings.button_delete_group), onClick, iconColor = Color.Red, textColor = Color.Red @@ -407,7 +408,7 @@ private fun SearchRowView( searchText: MutableState = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) } ) { Box(Modifier.width(36.dp), contentAlignment = Alignment.Center) { - Icon(painterResource(R.drawable.ic_search), stringResource(android.R.string.search_go), tint = MaterialTheme.colors.secondary) + Icon(painterResource(R.drawable.ic_search), stringResource(MR.strings.search_verb), tint = MaterialTheme.colors.secondary) } Spacer(Modifier.width(14.dp)) SearchTextField(Modifier.fillMaxWidth(), searchText = searchText, alwaysVisible = true) { diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupLinkView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupLinkView.kt index 45ccb4ca56..f473ac4cbd 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupLinkView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupLinkView.kt @@ -11,7 +11,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R @@ -19,6 +19,7 @@ import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.QRCode +import chat.simplex.res.MR @Composable fun GroupLinkView(chatModel: ChatModel, groupInfo: GroupInfo, connReqContact: String?, memberRole: GroupMemberRole?, onGroupLinkUpdated: (Pair) -> Unit) { @@ -64,9 +65,9 @@ fun GroupLinkView(chatModel: ChatModel, groupInfo: GroupInfo, connReqContact: St }, deleteLink = { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_link_question), - text = generalGetString(R.string.all_group_members_will_remain_connected), - confirmText = generalGetString(R.string.delete_verb), + title = generalGetString(MR.strings.delete_link_question), + text = generalGetString(MR.strings.all_group_members_will_remain_connected), + confirmText = generalGetString(MR.strings.delete_verb), onConfirm = { withApi { val r = chatModel.controller.apiDeleteGroupLink(groupInfo.groupId) @@ -100,9 +101,9 @@ fun GroupLinkLayout( Modifier .verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.group_link)) + AppBarTitle(stringResource(MR.strings.group_link)) Text( - stringResource(R.string.you_can_share_group_link_anybody_will_be_able_to_connect), + stringResource(MR.strings.you_can_share_group_link_anybody_will_be_able_to_connect), Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = 12.dp), lineHeight = 22.sp ) @@ -112,7 +113,7 @@ fun GroupLinkLayout( verticalArrangement = Arrangement.SpaceEvenly ) { if (groupLink == null) { - SimpleButton(stringResource(R.string.button_create_group_link), icon = painterResource(R.drawable.ic_add_link), disabled = creatingLink, click = createLink) + SimpleButton(stringResource(MR.strings.button_create_group_link), icon = painterResource(R.drawable.ic_add_link), disabled = creatingLink, click = createLink) } else { RoleSelectionRow(groupInfo, groupLinkMemberRole) var initialLaunch by remember { mutableStateOf(true) } @@ -129,12 +130,12 @@ fun GroupLinkLayout( modifier = Modifier.padding(horizontal = DEFAULT_PADDING, vertical = 10.dp) ) { SimpleButton( - stringResource(R.string.share_link), + stringResource(MR.strings.share_link), icon = painterResource(R.drawable.ic_share), click = share ) SimpleButton( - stringResource(R.string.delete_link), + stringResource(MR.strings.delete_link), icon = painterResource(R.drawable.ic_delete), color = Color.Red, click = deleteLink @@ -155,7 +156,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState Unit)? = null) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.button_remove_member), - text = generalGetString(R.string.member_will_be_removed_from_group_cannot_be_undone), - confirmText = generalGetString(R.string.remove_member_confirmation), + title = generalGetString(MR.strings.button_remove_member), + text = generalGetString(MR.strings.member_will_be_removed_from_group_cannot_be_undone), + confirmText = generalGetString(MR.strings.remove_member_confirmation), onConfirm = { withApi { val removedMember = chatModel.controller.apiRemoveMember(member.groupId, member.groupMemberId) @@ -218,7 +219,7 @@ fun GroupMemberInfoLayout( if (member.contactLink != null) { val context = LocalContext.current - SectionView(stringResource(R.string.address_section_title).uppercase()) { + SectionView(stringResource(MR.strings.address_section_title).uppercase()) { QRCode(member.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f)) ShareAddressButton { shareText(member.contactLink) } if (contactId != null) { @@ -228,30 +229,30 @@ fun GroupMemberInfoLayout( } else { ConnectViaAddressButton(onClick = { connectViaAddress(member.contactLink) }) } - SectionTextFooter(stringResource(R.string.you_can_share_this_address_with_your_contacts).format(member.displayName)) + SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(member.displayName)) } SectionDividerSpaced() } - SectionView(title = stringResource(R.string.member_info_section_title_member)) { - InfoRow(stringResource(R.string.info_row_group), groupInfo.displayName) + SectionView(title = stringResource(MR.strings.member_info_section_title_member)) { + InfoRow(stringResource(MR.strings.info_row_group), groupInfo.displayName) val roles = remember { member.canChangeRoleTo(groupInfo) } if (roles != null) { RoleSelectionRow(roles, newRole, onRoleSelected) } else { - InfoRow(stringResource(R.string.role_in_group), member.memberRole.text) + InfoRow(stringResource(MR.strings.role_in_group), member.memberRole.text) } val conn = member.activeConn if (conn != null) { val connLevelDesc = - if (conn.connLevel == 0) stringResource(R.string.conn_level_desc_direct) - else String.format(generalGetString(R.string.conn_level_desc_indirect), conn.connLevel) - InfoRow(stringResource(R.string.info_row_connection), connLevelDesc) + if (conn.connLevel == 0) stringResource(MR.strings.conn_level_desc_direct) + else String.format(generalGetString(MR.strings.conn_level_desc_indirect), conn.connLevel) + InfoRow(stringResource(MR.strings.info_row_connection), connLevelDesc) } } if (cStats != null) { SectionDividerSpaced() - SectionView(title = stringResource(R.string.conn_stats_section_title_servers)) { + SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers)) { SwitchAddressButton( disabled = cStats.rcvQueuesInfo.any { it.rcvSwitchStatus != null }, switchAddress = switchMemberAddress @@ -264,11 +265,11 @@ fun GroupMemberInfoLayout( } val rcvServers = cStats.rcvQueuesInfo.map { it.rcvServer } if (rcvServers.isNotEmpty()) { - SimplexServers(stringResource(R.string.receiving_via), rcvServers) + SimplexServers(stringResource(MR.strings.receiving_via), rcvServers) } val sndServers = cStats.sndQueuesInfo.map { it.sndServer } if (sndServers.isNotEmpty()) { - SimplexServers(stringResource(R.string.sending_via), sndServers) + SimplexServers(stringResource(MR.strings.sending_via), sndServers) } } } @@ -282,9 +283,9 @@ fun GroupMemberInfoLayout( if (developerTools) { SectionDividerSpaced() - SectionView(title = stringResource(R.string.section_title_for_console)) { - InfoRow(stringResource(R.string.info_row_local_name), member.localDisplayName) - InfoRow(stringResource(R.string.info_row_database_id), member.groupMemberId.toString()) + SectionView(title = stringResource(MR.strings.section_title_for_console)) { + InfoRow(stringResource(MR.strings.info_row_local_name), member.localDisplayName) + InfoRow(stringResource(MR.strings.info_row_database_id), member.groupMemberId.toString()) } } SectionBottomSpacer() @@ -324,7 +325,7 @@ fun GroupMemberInfoHeader(member: GroupMember) { fun RemoveMemberButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_delete), - stringResource(R.string.button_remove_member), + stringResource(MR.strings.button_remove_member), click = onClick, textColor = Color.Red, iconColor = Color.Red, @@ -335,7 +336,7 @@ fun RemoveMemberButton(onClick: () -> Unit) { fun OpenChatButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_chat), - stringResource(R.string.button_send_direct_message), + stringResource(MR.strings.button_send_direct_message), click = onClick, textColor = MaterialTheme.colors.primary, iconColor = MaterialTheme.colors.primary, @@ -346,7 +347,7 @@ fun OpenChatButton(onClick: () -> Unit) { fun ConnectViaAddressButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_link), - stringResource(R.string.connect_button), + stringResource(MR.strings.connect_button), click = onClick, textColor = MaterialTheme.colors.primary, iconColor = MaterialTheme.colors.primary, @@ -366,7 +367,7 @@ private fun RoleSelectionRow( ) { val values = remember { roles.map { it to it.text } } ExposedDropDownSettingRow( - generalGetString(R.string.change_role), + generalGetString(MR.strings.change_role), values, selectedRole, icon = null, @@ -383,12 +384,12 @@ private fun updateMemberRoleDialog( onConfirm: () -> Unit ) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.change_member_role_question), + title = generalGetString(MR.strings.change_member_role_question), text = if (member.memberCurrent) - String.format(generalGetString(R.string.member_role_will_be_changed_with_notification), newRole.text) + String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification), newRole.text) else - String.format(generalGetString(R.string.member_role_will_be_changed_with_invitation), newRole.text), - confirmText = generalGetString(R.string.change_verb), + String.format(generalGetString(MR.strings.member_role_will_be_changed_with_invitation), newRole.text), + confirmText = generalGetString(MR.strings.change_verb), onDismiss = onDismiss, onConfirm = onConfirm, onDismissRequest = onDismiss diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt index d6157140b7..1801a0ff75 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupPreferences.kt @@ -13,12 +13,13 @@ import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.PreferenceToggleWithIcon +import chat.simplex.res.MR @Composable fun GroupPreferencesView(m: ChatModel, chatId: String, close: () -> Unit,) { @@ -71,7 +72,7 @@ private fun GroupPreferencesLayout( Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.group_preferences)) + AppBarTitle(stringResource(MR.strings.group_preferences)) val timedMessages = remember(preferences) { mutableStateOf(preferences.timedMessages.enable) } val onTTLUpdated = { ttl: Int? -> applyPrefs(preferences.copy(timedMessages = preferences.timedMessages.copy(ttl = ttl))) @@ -149,10 +150,10 @@ private fun FeatureSection( DropdownCustomTimePickerSettingRow( selection = ttl, propagateExternalSelectionUpdate = true, // for Reset - label = generalGetString(R.string.delete_after), + label = generalGetString(MR.strings.delete_after), dropdownValues = TimedMessagesPreference.ttlValues, - customPickerTitle = generalGetString(R.string.delete_after), - customPickerConfirmButtonText = generalGetString(R.string.custom_time_picker_select), + customPickerTitle = generalGetString(MR.strings.delete_after), + customPickerConfirmButtonText = generalGetString(MR.strings.custom_time_picker_select), onSelected = onTTLUpdated ) } @@ -164,7 +165,7 @@ private fun FeatureSection( iconTint = iconTint, ) if (timedOn) { - InfoRow(generalGetString(R.string.delete_after), timeText(preferences.timedMessages.ttl)) + InfoRow(generalGetString(MR.strings.delete_after), timeText(preferences.timedMessages.ttl)) } } } @@ -175,19 +176,19 @@ private fun FeatureSection( private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) { SectionView { SectionItemView(reset, disabled = disabled) { - Text(stringResource(R.string.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } SectionItemView(save, disabled = disabled) { - Text(stringResource(R.string.save_and_notify_group_members), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(stringResource(MR.strings.save_and_notify_group_members), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } } } private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) { AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.save_preferences_question), - confirmText = generalGetString(R.string.save_and_notify_group_members), - dismissText = generalGetString(R.string.exit_without_saving), + title = generalGetString(MR.strings.save_preferences_question), + confirmText = generalGetString(MR.strings.save_and_notify_group_members), + dismissText = generalGetString(MR.strings.exit_without_saving), onConfirm = save, onDismiss = revert, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupProfileView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupProfileView.kt index 93e37c9e74..5031babd49 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupProfileView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/GroupProfileView.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -28,6 +28,7 @@ import chat.simplex.app.views.onboarding.ReadableText import chat.simplex.app.views.usersettings.* import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsWithImePadding +import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -105,7 +106,7 @@ fun GroupProfileLayout( Modifier.fillMaxWidth() .padding(horizontal = DEFAULT_PADDING) ) { - ReadableText(R.string.group_profile_is_stored_on_members_devices, TextAlign.Center) + ReadableText(MR.strings.group_profile_is_stored_on_members_devices, TextAlign.Center) Box( Modifier .fillMaxWidth() @@ -124,13 +125,13 @@ fun GroupProfileLayout( } Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Text( - stringResource(R.string.group_display_name_field), + stringResource(MR.strings.group_display_name_field), fontSize = 16.sp ) if (!isValidDisplayName(displayName.value)) { Spacer(Modifier.size(DEFAULT_PADDING_HALF)) Text( - stringResource(R.string.no_spaces), + stringResource(MR.strings.no_spaces), fontSize = 16.sp, color = Color.Red ) @@ -139,7 +140,7 @@ fun GroupProfileLayout( ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester) Spacer(Modifier.height(DEFAULT_PADDING)) Text( - stringResource(R.string.group_full_name_field), + stringResource(MR.strings.group_full_name_field), fontSize = 16.sp, modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF) ) @@ -148,7 +149,7 @@ fun GroupProfileLayout( val enabled = !dataUnchanged && displayName.value.isNotEmpty() && isValidDisplayName(displayName.value) if (enabled) { Text( - stringResource(R.string.save_group_profile), + stringResource(MR.strings.save_group_profile), modifier = Modifier.clickable { saveProfile( groupProfile.copy( @@ -162,7 +163,7 @@ fun GroupProfileLayout( ) } else { Text( - stringResource(R.string.save_group_profile), + stringResource(MR.strings.save_group_profile), color = MaterialTheme.colors.secondary ) } @@ -182,9 +183,9 @@ fun GroupProfileLayout( private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) { AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.save_preferences_question), - confirmText = generalGetString(R.string.save_and_notify_group_members), - dismissText = generalGetString(R.string.exit_without_saving), + title = generalGetString(MR.strings.save_preferences_question), + confirmText = generalGetString(MR.strings.save_and_notify_group_members), + dismissText = generalGetString(MR.strings.exit_without_saving), onConfirm = save, onDismiss = revert, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/WelcomeMessageView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/WelcomeMessageView.kt index 91a999c6f7..8875b61dfc 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/WelcomeMessageView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/group/WelcomeMessageView.kt @@ -15,7 +15,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.* @@ -24,6 +24,7 @@ import chat.simplex.app.model.* import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.views.chat.item.MarkdownText import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.delay @Composable @@ -74,14 +75,14 @@ private fun GroupWelcomeLayout( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { val editMode = remember { mutableStateOf(true) } - AppBarTitle(stringResource(R.string.group_welcome_title)) + AppBarTitle(stringResource(MR.strings.group_welcome_title)) val wt = rememberSaveable { welcomeText } if (groupInfo.canEdit) { if (editMode.value) { val focusRequester = remember { FocusRequester() } TextEditor( wt, - Modifier.height(140.dp), stringResource(R.string.enter_welcome_message), + Modifier.height(140.dp), stringResource(MR.strings.enter_welcome_message), focusRequester = focusRequester ) LaunchedEffect(Unit) { @@ -131,7 +132,7 @@ private fun TextPreview(text: String, linkMode: SimplexLinkMode, markdown: Boole private fun SaveButton(save: () -> Unit, disabled: Boolean) { SectionView { SectionItemView(save, disabled = disabled) { - Text(stringResource(R.string.save_and_update_group_profile), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(stringResource(MR.strings.save_and_update_group_profile), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } } } @@ -141,12 +142,12 @@ private fun ChangeModeButton(editMode: Boolean, click: () -> Unit, disabled: Boo SectionItemView(click, disabled = disabled) { Icon( painterResource(if (editMode) R.drawable.ic_visibility else R.drawable.ic_edit), - contentDescription = generalGetString(R.string.edit_verb), + contentDescription = generalGetString(MR.strings.edit_verb), tint = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary, ) TextIconSpaced() Text( - stringResource(if (editMode) R.string.group_welcome_preview else R.string.edit_verb), + stringResource(if (editMode) MR.strings.group_welcome_preview else MR.strings.edit_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary ) } @@ -157,19 +158,19 @@ private fun CopyTextButton(click: () -> Unit) { SectionItemView(click) { Icon( painterResource(R.drawable.ic_content_copy), - contentDescription = generalGetString(R.string.copy_verb), + contentDescription = generalGetString(MR.strings.copy_verb), tint = MaterialTheme.colors.primary, ) TextIconSpaced() - Text(stringResource(R.string.copy_verb), color = MaterialTheme.colors.primary) + Text(stringResource(MR.strings.copy_verb), color = MaterialTheme.colors.primary) } } private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) { AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.save_welcome_message_question), - confirmText = generalGetString(R.string.save_and_update_group_profile), - dismissText = generalGetString(R.string.exit_without_saving), + title = generalGetString(MR.strings.save_welcome_message_question), + confirmText = generalGetString(MR.strings.save_and_update_group_profile), + dismissText = generalGetString(MR.strings.exit_without_saving), onConfirm = save, onDismiss = revert, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CICallItemView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CICallItemView.kt index 378ee4d5b4..12d2b9e5e5 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CICallItemView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CICallItemView.kt @@ -7,12 +7,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* +import chat.simplex.res.MR @Composable fun CICallItemView(cInfo: ChatInfo, cItem: ChatItem, status: CICallStatus, duration: Int, acceptCall: (Contact) -> Unit) { @@ -21,20 +22,20 @@ fun CICallItemView(cInfo: ChatInfo, cItem: ChatItem, status: CICallStatus, durat Modifier .padding(horizontal = 4.dp) .padding(bottom = 8.dp), horizontalAlignment = Alignment.CenterHorizontally) { - @Composable fun ConnectingCallIcon() = Icon(painterResource(R.drawable.ic_settings_phone), stringResource(R.string.icon_descr_call_connecting), tint = SimplexGreen) + @Composable fun ConnectingCallIcon() = Icon(painterResource(R.drawable.ic_settings_phone), stringResource(MR.strings.icon_descr_call_connecting), tint = SimplexGreen) when (status) { CICallStatus.Pending -> if (sent) { - Icon(painterResource(R.drawable.ic_call), stringResource(R.string.icon_descr_call_pending_sent)) + Icon(painterResource(R.drawable.ic_call), stringResource(MR.strings.icon_descr_call_pending_sent)) } else { AcceptCallButton(cInfo, acceptCall) } - CICallStatus.Missed -> Icon(painterResource(R.drawable.ic_call), stringResource(R.string.icon_descr_call_missed), tint = Color.Red) - CICallStatus.Rejected -> Icon(painterResource(R.drawable.ic_call_end), stringResource(R.string.icon_descr_call_rejected), tint = Color.Red) + CICallStatus.Missed -> Icon(painterResource(R.drawable.ic_call), stringResource(MR.strings.icon_descr_call_missed), tint = Color.Red) + CICallStatus.Rejected -> Icon(painterResource(R.drawable.ic_call_end), stringResource(MR.strings.icon_descr_call_rejected), tint = Color.Red) CICallStatus.Accepted -> ConnectingCallIcon() CICallStatus.Negotiated -> ConnectingCallIcon() - CICallStatus.Progress -> Icon(painterResource(R.drawable.ic_phone_in_talk_filled), stringResource(R.string.icon_descr_call_progress), tint = SimplexGreen) + CICallStatus.Progress -> Icon(painterResource(R.drawable.ic_phone_in_talk_filled), stringResource(MR.strings.icon_descr_call_progress), tint = SimplexGreen) CICallStatus.Ended -> Row { - Icon(painterResource(R.drawable.ic_call_end), stringResource(R.string.icon_descr_call_ended), tint = MaterialTheme.colors.secondary, modifier = Modifier.padding(end = 4.dp)) + Icon(painterResource(R.drawable.ic_call_end), stringResource(MR.strings.icon_descr_call_ended), tint = MaterialTheme.colors.secondary, modifier = Modifier.padding(end = 4.dp)) Text(durationText(duration), color = MaterialTheme.colors.secondary) } CICallStatus.Error -> {} @@ -52,9 +53,9 @@ fun CICallItemView(cInfo: ChatInfo, cItem: ChatItem, status: CICallStatus, durat @Composable fun AcceptCallButton(cInfo: ChatInfo, acceptCall: (Contact) -> Unit) { if (cInfo is ChatInfo.Direct) { - SimpleButton(stringResource(R.string.answer_call), painterResource(R.drawable.ic_ring_volume)) { acceptCall(cInfo.contact) } + SimpleButton(stringResource(MR.strings.answer_call), painterResource(R.drawable.ic_ring_volume)) { acceptCall(cInfo.contact) } } else { - Icon(painterResource(R.drawable.ic_ring_volume), stringResource(R.string.answer_call), tint = MaterialTheme.colors.secondary) + Icon(painterResource(R.drawable.ic_ring_volume), stringResource(MR.strings.answer_call), tint = MaterialTheme.colors.secondary) } // if case let .direct(contact) = chatInfo { // Button { diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFeaturePreferenceView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFeaturePreferenceView.kt index ab9d0896a1..cdb261d58b 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFeaturePreferenceView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFeaturePreferenceView.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR @Composable fun CIFeaturePreferenceView( @@ -30,7 +31,7 @@ fun CIFeaturePreferenceView( if (contact != null && allowed != FeatureAllowed.NO && contact.allowsFeature(feature) && !contact.userAllowsFeature(feature)) { val acceptStyle = SpanStyle(color = MaterialTheme.colors.primary, fontSize = 12.sp) val setParam = feature == ChatFeature.TimedMessages && contact.mergedPreferences.timedMessages.userPreference.pref.ttl == null - val acceptTextId = if (setParam) R.string.accept_feature_set_1_day else R.string.accept_feature + val acceptTextId = if (setParam) MR.strings.accept_feature_set_1_day else MR.strings.accept_feature val param = if (setParam) 86400 else null val annotatedText = buildAnnotatedString { withStyle(chatEventStyle) { append(chatItem.content.text + " ") } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt index 98aedc361e..ac2491f88e 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.* import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -23,6 +23,7 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.datetime.Clock @Composable @@ -44,14 +45,14 @@ fun CIFileView( ) { Icon( painterResource(R.drawable.ic_draft_filled), - stringResource(R.string.icon_descr_file), + stringResource(MR.strings.icon_descr_file), Modifier.fillMaxSize(), tint = color ) if (innerIcon != null) { Icon( innerIcon, - stringResource(R.string.icon_descr_file), + stringResource(MR.strings.icon_descr_file), Modifier .size(32.dp) .padding(top = 12.dp), @@ -76,8 +77,8 @@ fun CIFileView( receiveFile(file.fileId) } else { AlertManager.shared.showAlertMsg( - generalGetString(R.string.large_file), - String.format(generalGetString(R.string.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol))) + generalGetString(MR.strings.large_file), + String.format(generalGetString(MR.strings.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol))) ) } } @@ -85,13 +86,13 @@ fun CIFileView( when (file.fileProtocol) { FileProtocol.XFTP -> AlertManager.shared.showAlertMsg( - generalGetString(R.string.waiting_for_file), - generalGetString(R.string.file_will_be_received_when_contact_completes_uploading) + generalGetString(MR.strings.waiting_for_file), + generalGetString(MR.strings.file_will_be_received_when_contact_completes_uploading) ) FileProtocol.SMP -> AlertManager.shared.showAlertMsg( - generalGetString(R.string.waiting_for_file), - generalGetString(R.string.file_will_be_received_when_contact_is_online) + generalGetString(MR.strings.waiting_for_file), + generalGetString(MR.strings.file_will_be_received_when_contact_is_online) ) } is CIFileStatus.RcvComplete -> { @@ -99,7 +100,7 @@ fun CIFileView( if (filePath != null) { saveFileLauncher.launch(file.fileName) } else { - Toast.makeText(context, generalGetString(R.string.file_not_found), Toast.LENGTH_SHORT).show() + Toast.makeText(context, generalGetString(MR.strings.file_not_found), Toast.LENGTH_SHORT).show() } } else -> {} diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIGroupInvitationView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIGroupInvitationView.kt index e53af51af0..6a0e07619a 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIGroupInvitationView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIGroupInvitationView.kt @@ -8,7 +8,7 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.* @@ -18,6 +18,7 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun CIGroupInvitationView( @@ -60,11 +61,11 @@ fun CIGroupInvitationView( @Composable fun groupInvitationText() { when { - sent -> Text(stringResource(R.string.you_sent_group_invitation)) - !sent && groupInvitation.status == CIGroupInvitationStatus.Pending -> Text(stringResource(R.string.you_are_invited_to_group)) - !sent && groupInvitation.status == CIGroupInvitationStatus.Accepted -> Text(stringResource(R.string.you_joined_this_group)) - !sent && groupInvitation.status == CIGroupInvitationStatus.Rejected -> Text(stringResource(R.string.you_rejected_group_invitation)) - !sent && groupInvitation.status == CIGroupInvitationStatus.Expired -> Text(stringResource(R.string.group_invitation_expired)) + sent -> Text(stringResource(MR.strings.you_sent_group_invitation)) + !sent && groupInvitation.status == CIGroupInvitationStatus.Pending -> Text(stringResource(MR.strings.you_are_invited_to_group)) + !sent && groupInvitation.status == CIGroupInvitationStatus.Accepted -> Text(stringResource(MR.strings.you_joined_this_group)) + !sent && groupInvitation.status == CIGroupInvitationStatus.Rejected -> Text(stringResource(MR.strings.you_rejected_group_invitation)) + !sent && groupInvitation.status == CIGroupInvitationStatus.Expired -> Text(stringResource(MR.strings.group_invitation_expired)) } } @@ -95,7 +96,7 @@ fun CIGroupInvitationView( if (action) { groupInvitationText() Text(stringResource( - if (chatIncognito) R.string.group_invitation_tap_to_join_incognito else R.string.group_invitation_tap_to_join), + if (chatIncognito) MR.strings.group_invitation_tap_to_join_incognito else MR.strings.group_invitation_tap_to_join), color = if (chatIncognito) Indigo else MaterialTheme.colors.primary) } else { Box(Modifier.padding(end = 48.dp)) { diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt index 4c94bed48d..b5933c9d35 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt @@ -2,7 +2,6 @@ package chat.simplex.app.views.chat.item import android.graphics.Bitmap import android.os.Build.VERSION.SDK_INT -import androidx.annotation.StringRes import androidx.compose.foundation.Image import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* @@ -19,7 +18,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.* import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.core.content.FileProvider @@ -32,6 +31,8 @@ import coil.compose.rememberAsyncImagePainter import coil.decode.GifDecoder import coil.decode.ImageDecoderDecoder import coil.request.ImageRequest +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource import java.io.File @Composable @@ -52,7 +53,7 @@ fun CIImageView( } @Composable - fun fileIcon(icon: Painter, @StringRes stringId: Int) { + fun fileIcon(icon: Painter, stringId: StringResource) { Icon( icon, stringResource(stringId), @@ -77,14 +78,14 @@ fun CIImageView( FileProtocol.SMP -> {} } is CIFileStatus.SndTransfer -> progressIndicator() - is CIFileStatus.SndComplete -> fileIcon(painterResource(R.drawable.ic_check_filled), R.string.icon_descr_image_snd_complete) - is CIFileStatus.SndCancelled -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file) - is CIFileStatus.SndError -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file) - is CIFileStatus.RcvInvitation -> fileIcon(painterResource(R.drawable.ic_arrow_downward), R.string.icon_descr_asked_to_receive) - is CIFileStatus.RcvAccepted -> fileIcon(painterResource(R.drawable.ic_more_horiz), R.string.icon_descr_waiting_for_image) + is CIFileStatus.SndComplete -> fileIcon(painterResource(R.drawable.ic_check_filled), MR.strings.icon_descr_image_snd_complete) + is CIFileStatus.SndCancelled -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file) + is CIFileStatus.SndError -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file) + is CIFileStatus.RcvInvitation -> fileIcon(painterResource(R.drawable.ic_arrow_downward), MR.strings.icon_descr_asked_to_receive) + is CIFileStatus.RcvAccepted -> fileIcon(painterResource(R.drawable.ic_more_horiz), MR.strings.icon_descr_waiting_for_image) is CIFileStatus.RcvTransfer -> progressIndicator() - is CIFileStatus.RcvCancelled -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file) - is CIFileStatus.RcvError -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file) + is CIFileStatus.RcvCancelled -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file) + is CIFileStatus.RcvError -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file) else -> {} } } @@ -101,7 +102,7 @@ fun CIImageView( fun imageView(imageBitmap: Bitmap, onClick: () -> Unit) { Image( imageBitmap.asImageBitmap(), - contentDescription = stringResource(R.string.image_descr), + contentDescription = stringResource(MR.strings.image_descr), // .width(1000.dp) is a hack for image to increase IntrinsicSize of FramedItemView // if text is short and take all available width if text is long modifier = Modifier @@ -118,7 +119,7 @@ fun CIImageView( fun imageView(painter: Painter, onClick: () -> Unit) { Image( painter, - contentDescription = stringResource(R.string.image_descr), + contentDescription = stringResource(MR.strings.image_descr), // .width(1000.dp) is a hack for image to increase IntrinsicSize of FramedItemView // if text is short and take all available width if text is long modifier = Modifier @@ -175,21 +176,21 @@ fun CIImageView( receiveFile(file.fileId) } else { AlertManager.shared.showAlertMsg( - generalGetString(R.string.large_file), - String.format(generalGetString(R.string.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol))) + generalGetString(MR.strings.large_file), + String.format(generalGetString(MR.strings.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol))) ) } CIFileStatus.RcvAccepted -> when (file.fileProtocol) { FileProtocol.XFTP -> AlertManager.shared.showAlertMsg( - generalGetString(R.string.waiting_for_image), - generalGetString(R.string.image_will_be_received_when_contact_completes_uploading) + generalGetString(MR.strings.waiting_for_image), + generalGetString(MR.strings.image_will_be_received_when_contact_completes_uploading) ) FileProtocol.SMP -> AlertManager.shared.showAlertMsg( - generalGetString(R.string.waiting_for_image), - generalGetString(R.string.image_will_be_received_when_contact_is_online) + generalGetString(MR.strings.waiting_for_image), + generalGetString(MR.strings.image_will_be_received_when_contact_is_online) ) } CIFileStatus.RcvTransfer(rcvProgress = 7, rcvTotal = 10) -> {} // ? diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIInvalidJSONView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIInvalidJSONView.kt index 34ea631c72..d1aad7c297 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIInvalidJSONView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIInvalidJSONView.kt @@ -8,13 +8,14 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.SettingsActionItem +import chat.simplex.res.MR @Composable fun CIInvalidJSONView(json: String) { @@ -22,7 +23,7 @@ fun CIInvalidJSONView(json: String) { .clickable { ModalManager.shared.showModal(true) { InvalidJSONView(json) } } .padding(horizontal = 10.dp, vertical = 6.dp) ) { - Text(stringResource(R.string.invalid_data), color = Color.Red, fontStyle = FontStyle.Italic) + Text(stringResource(MR.strings.invalid_data), color = Color.Red, fontStyle = FontStyle.Italic) } } @@ -31,7 +32,7 @@ fun InvalidJSONView(json: String) { Column { Spacer(Modifier.height(DEFAULT_PADDING)) SectionView { - SettingsActionItem(painterResource(R.drawable.ic_share), generalGetString(R.string.share_verb), click = { + SettingsActionItem(painterResource(R.drawable.ic_share), generalGetString(MR.strings.share_verb), click = { shareText(json) }) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIRcvDecryptionError.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIRcvDecryptionError.kt index c33544f2b7..80e4ea15ba 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIRcvDecryptionError.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIRcvDecryptionError.kt @@ -5,19 +5,20 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.views.helpers.AlertManager import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR @Composable fun CIRcvDecryptionError(msgDecryptError: MsgDecryptError, msgCount: UInt, ci: ChatItem, timedMessagesTTL: Int?, showMember: Boolean) { CIMsgError(ci, timedMessagesTTL, showMember) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.decryption_error), + title = generalGetString(MR.strings.decryption_error), text = when (msgDecryptError) { - MsgDecryptError.RatchetHeader -> String.format(generalGetString(R.string.alert_text_decryption_error_header), msgCount.toLong()) + "\n" + - generalGetString(R.string.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" + - generalGetString(R.string.alert_text_fragment_permanent_error_reconnect) - MsgDecryptError.TooManySkipped -> String.format(generalGetString(R.string.alert_text_decryption_error_too_many_skipped), msgCount.toLong()) + "\n" + - generalGetString(R.string.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" + - generalGetString(R.string.alert_text_fragment_permanent_error_reconnect) + MsgDecryptError.RatchetHeader -> String.format(generalGetString(MR.strings.alert_text_decryption_error_header), msgCount.toLong()) + "\n" + + generalGetString(MR.strings.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" + + generalGetString(MR.strings.alert_text_fragment_permanent_error_reconnect) + MsgDecryptError.TooManySkipped -> String.format(generalGetString(MR.strings.alert_text_decryption_error_too_many_skipped), msgCount.toLong()) + "\n" + + generalGetString(MR.strings.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" + + generalGetString(MR.strings.alert_text_fragment_permanent_error_reconnect) } ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt index cfbfb714b0..71f27a40c4 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt @@ -3,7 +3,6 @@ package chat.simplex.app.views.chat.item import android.graphics.Bitmap import android.graphics.Rect import android.net.Uri -import androidx.annotation.StringRes import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CornerSize @@ -18,7 +17,7 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.* import androidx.compose.ui.platform.* import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.* import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.FileProvider @@ -30,6 +29,8 @@ import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH import com.google.android.exoplayer2.ui.StyledPlayerView +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource import java.io.File @Composable @@ -68,14 +69,14 @@ fun CIVideoView( when (file.fileProtocol) { FileProtocol.XFTP -> AlertManager.shared.showAlertMsg( - generalGetString(R.string.waiting_for_video), - generalGetString(R.string.video_will_be_received_when_contact_completes_uploading) + generalGetString(MR.strings.waiting_for_video), + generalGetString(MR.strings.video_will_be_received_when_contact_completes_uploading) ) FileProtocol.SMP -> AlertManager.shared.showAlertMsg( - generalGetString(R.string.waiting_for_video), - generalGetString(R.string.video_will_be_received_when_contact_is_online) + generalGetString(MR.strings.waiting_for_video), + generalGetString(MR.strings.video_will_be_received_when_contact_is_online) ) } CIFileStatus.RcvTransfer(rcvProgress = 7, rcvTotal = 10) -> {} // ? @@ -220,7 +221,7 @@ private fun ImageView(preview: Bitmap, showMenu: MutableState, onClick: val width = remember(preview) { if (preview.width * 0.97 <= preview.height) videoViewFullWidth(windowWidth) * 0.75f else 1000.dp } Image( preview.asImageBitmap(), - contentDescription = stringResource(R.string.video_descr), + contentDescription = stringResource(MR.strings.video_descr), modifier = Modifier .width(width) .combinedClickable( @@ -252,7 +253,7 @@ private fun progressIndicator() { } @Composable -private fun fileIcon(icon: Painter, @StringRes stringId: Int) { +private fun fileIcon(icon: Painter, stringId: StringResource) { Icon( icon, stringResource(stringId), @@ -295,19 +296,19 @@ private fun loadingIndicator(file: CIFile?) { FileProtocol.XFTP -> progressCircle(file.fileStatus.sndProgress, file.fileStatus.sndTotal) FileProtocol.SMP -> progressIndicator() } - is CIFileStatus.SndComplete -> fileIcon(painterResource(R.drawable.ic_check_filled), R.string.icon_descr_video_snd_complete) - is CIFileStatus.SndCancelled -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file) - is CIFileStatus.SndError -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file) - is CIFileStatus.RcvInvitation -> fileIcon(painterResource(R.drawable.ic_arrow_downward), R.string.icon_descr_video_asked_to_receive) - is CIFileStatus.RcvAccepted -> fileIcon(painterResource(R.drawable.ic_more_horiz), R.string.icon_descr_waiting_for_video) + is CIFileStatus.SndComplete -> fileIcon(painterResource(R.drawable.ic_check_filled), MR.strings.icon_descr_video_snd_complete) + is CIFileStatus.SndCancelled -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file) + is CIFileStatus.SndError -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file) + is CIFileStatus.RcvInvitation -> fileIcon(painterResource(R.drawable.ic_arrow_downward), MR.strings.icon_descr_video_asked_to_receive) + is CIFileStatus.RcvAccepted -> fileIcon(painterResource(R.drawable.ic_more_horiz), MR.strings.icon_descr_waiting_for_video) is CIFileStatus.RcvTransfer -> if (file.fileProtocol == FileProtocol.XFTP && file.fileStatus.rcvProgress < file.fileStatus.rcvTotal) { progressCircle(file.fileStatus.rcvProgress, file.fileStatus.rcvTotal) } else { progressIndicator() } - is CIFileStatus.RcvCancelled -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file) - is CIFileStatus.RcvError -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file) + is CIFileStatus.RcvCancelled -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file) + is CIFileStatus.RcvError -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file) else -> {} } } @@ -326,8 +327,8 @@ private fun receiveFileIfValidSize(file: CIFile, receiveFile: (Long) -> Unit) { receiveFile(file.fileId) } else { AlertManager.shared.showAlertMsg( - generalGetString(R.string.large_file), - String.format(generalGetString(R.string.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol))) + generalGetString(MR.strings.large_file), + String.format(generalGetString(MR.strings.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol))) ) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/ChatItemView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/ChatItemView.kt index 582d50b489..6f4946064f 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/ChatItemView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/ChatItemView.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.* import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -26,6 +26,7 @@ import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.* import chat.simplex.app.views.helpers.* import com.google.accompanist.permissions.rememberPermissionState +import chat.simplex.res.MR import kotlinx.datetime.Clock // TODO refactor so that FramedItemView can show all CIContent items if they're deleted (see Swift code) @@ -69,10 +70,10 @@ fun ChatItemView( val onClick = { when (cItem.meta.itemStatus) { is CIStatus.SndErrorAuth -> { - showMsgDeliveryErrorAlert(generalGetString(R.string.message_delivery_error_desc)) + showMsgDeliveryErrorAlert(generalGetString(MR.strings.message_delivery_error_desc)) } is CIStatus.SndError -> { - showMsgDeliveryErrorAlert(generalGetString(R.string.unknown_error) + ": ${cItem.meta.itemStatus.agentError}") + showMsgDeliveryErrorAlert(generalGetString(MR.strings.unknown_error) + ": ${cItem.meta.itemStatus.agentError}") } else -> {} } @@ -116,17 +117,17 @@ fun ChatItemView( fun deleteMessageQuestionText(): String { return if (fullDeleteAllowed) { - generalGetString(R.string.delete_message_cannot_be_undone_warning) + generalGetString(MR.strings.delete_message_cannot_be_undone_warning) } else { - generalGetString(R.string.delete_message_mark_deleted_warning) + generalGetString(MR.strings.delete_message_mark_deleted_warning) } } fun moderateMessageQuestionText(): String { return if (fullDeleteAllowed) { - generalGetString(R.string.moderate_message_will_be_deleted_warning) + generalGetString(MR.strings.moderate_message_will_be_deleted_warning) } else { - generalGetString(R.string.moderate_message_will_be_marked_warning) + generalGetString(MR.strings.moderate_message_will_be_marked_warning) } } @@ -163,7 +164,7 @@ fun ChatItemView( MsgReactionsMenu() } if (cItem.meta.itemDeleted == null && !live) { - ItemAction(stringResource(R.string.reply_verb), painterResource(R.drawable.ic_reply), onClick = { + ItemAction(stringResource(MR.strings.reply_verb), painterResource(R.drawable.ic_reply), onClick = { if (composeState.value.editing) { composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem), useLinkPreviews = useLinkPreviews) } else { @@ -172,7 +173,7 @@ fun ChatItemView( showMenu.value = false }) } - ItemAction(stringResource(R.string.share_verb), painterResource(R.drawable.ic_share), onClick = { + ItemAction(stringResource(MR.strings.share_verb), painterResource(R.drawable.ic_share), onClick = { val filePath = getLoadedFilePath(cItem.file) when { filePath != null -> shareFile(cItem.text, filePath) @@ -180,7 +181,7 @@ fun ChatItemView( } showMenu.value = false }) - ItemAction(stringResource(R.string.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = { + ItemAction(stringResource(MR.strings.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = { copyText(cItem.content.text) showMenu.value = false }) @@ -188,7 +189,7 @@ fun ChatItemView( val filePath = getLoadedFilePath(cItem.file) if (filePath != null) { val writePermissionState = rememberPermissionState(permission = Manifest.permission.WRITE_EXTERNAL_STORAGE) - ItemAction(stringResource(R.string.save_verb), painterResource(R.drawable.ic_download), onClick = { + ItemAction(stringResource(MR.strings.save_verb), painterResource(R.drawable.ic_download), onClick = { when (cItem.content.msgContent) { is MsgContent.MCImage -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R || writePermissionState.hasPermission) { @@ -205,14 +206,14 @@ fun ChatItemView( } } if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice && !live) { - ItemAction(stringResource(R.string.edit_verb), painterResource(R.drawable.ic_edit_filled), onClick = { + ItemAction(stringResource(MR.strings.edit_verb), painterResource(R.drawable.ic_edit_filled), onClick = { composeState.value = ComposeState(editingItem = cItem, useLinkPreviews = useLinkPreviews) showMenu.value = false }) } if (cItem.meta.itemDeleted != null && revealed.value) { ItemAction( - stringResource(R.string.hide_verb), + stringResource(MR.strings.hide_verb), painterResource(R.drawable.ic_visibility_off), onClick = { revealed.value = false @@ -239,7 +240,7 @@ fun ChatItemView( DefaultDropdownMenu(showMenu) { if (!cItem.isDeletedContent) { ItemAction( - stringResource(R.string.reveal_verb), + stringResource(MR.strings.reveal_verb), painterResource(R.drawable.ic_visibility), onClick = { revealed.value = true @@ -289,7 +290,7 @@ fun ChatItemView( fun ModeratedItem() { MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember) DefaultDropdownMenu(showMenu) { - DeleteItemAction(cItem, showMenu, questionText = generalGetString(R.string.delete_message_cannot_be_undone_warning), deleteMessage) + DeleteItemAction(cItem, showMenu, questionText = generalGetString(MR.strings.delete_message_cannot_be_undone_warning), deleteMessage) } } @@ -358,7 +359,7 @@ fun ItemInfoAction( showMenu: MutableState ) { ItemAction( - stringResource(R.string.info_menu), + stringResource(MR.strings.info_menu), painterResource(R.drawable.ic_info), onClick = { showItemDetails(cInfo, cItem) @@ -376,7 +377,7 @@ fun DeleteItemAction( deleteMessage: (Long, CIDeleteMode) -> Unit ) { ItemAction( - stringResource(R.string.delete_verb), + stringResource(MR.strings.delete_verb), painterResource(R.drawable.ic_delete), onClick = { showMenu.value = false @@ -394,7 +395,7 @@ fun ModerateItemAction( deleteMessage: (Long, CIDeleteMode) -> Unit ) { ItemAction( - stringResource(R.string.moderate_verb), + stringResource(MR.strings.moderate_verb), painterResource(R.drawable.ic_flag), onClick = { showMenu.value = false @@ -458,7 +459,7 @@ fun cancelFileAlertDialog(fileId: Long, cancelFile: (Long) -> Unit, cancelAction fun deleteMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteMessage: (Long, CIDeleteMode) -> Unit) { AlertManager.shared.showAlertDialogButtons( - title = generalGetString(R.string.delete_message__question), + title = generalGetString(MR.strings.delete_message__question), text = questionText, buttons = { Row( @@ -470,13 +471,13 @@ fun deleteMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteMes TextButton(onClick = { deleteMessage(chatItem.id, CIDeleteMode.cidmInternal) AlertManager.shared.hideAlert() - }) { Text(stringResource(R.string.for_me_only), color = MaterialTheme.colors.error) } + }) { Text(stringResource(MR.strings.for_me_only), color = MaterialTheme.colors.error) } if (chatItem.meta.editable) { Spacer(Modifier.padding(horizontal = 4.dp)) TextButton(onClick = { deleteMessage(chatItem.id, CIDeleteMode.cidmBroadcast) AlertManager.shared.hideAlert() - }) { Text(stringResource(R.string.for_everybody), color = MaterialTheme.colors.error) } + }) { Text(stringResource(MR.strings.for_everybody), color = MaterialTheme.colors.error) } } } } @@ -485,9 +486,9 @@ fun deleteMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteMes fun moderateMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteMessage: (Long, CIDeleteMode) -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_member_message__question), + title = generalGetString(MR.strings.delete_member_message__question), text = questionText, - confirmText = generalGetString(R.string.delete_verb), + confirmText = generalGetString(MR.strings.delete_verb), destructive = true, onConfirm = { deleteMessage(chatItem.id, CIDeleteMode.cidmBroadcast) @@ -497,7 +498,7 @@ fun moderateMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteM private fun showMsgDeliveryErrorAlert(description: String) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.message_delivery_error_title), + title = generalGetString(MR.strings.message_delivery_error_title), text = description, ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/FramedItemView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/FramedItemView.kt index d81b7943bc..52044a87f8 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/FramedItemView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/FramedItemView.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.* import androidx.compose.ui.platform.UriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.style.TextOverflow @@ -25,6 +25,7 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.datetime.Clock import kotlin.math.min @@ -118,7 +119,7 @@ fun FramedItemView( val imageBitmap = base64ToBitmap(qi.content.image).asImageBitmap() Image( imageBitmap, - contentDescription = stringResource(R.string.image_descr), + contentDescription = stringResource(MR.strings.image_descr), contentScale = ContentScale.Crop, modifier = Modifier.size(68.dp).clipToBounds() ) @@ -130,7 +131,7 @@ fun FramedItemView( val imageBitmap = base64ToBitmap(qi.content.image).asImageBitmap() Image( imageBitmap, - contentDescription = stringResource(R.string.video_descr), + contentDescription = stringResource(MR.strings.video_descr), contentScale = ContentScale.Crop, modifier = Modifier.size(68.dp).clipToBounds() ) @@ -141,7 +142,7 @@ fun FramedItemView( } Icon( if (qi.content is MsgContent.MCFile) painterResource(R.drawable.ic_draft_filled) else painterResource(R.drawable.ic_mic_filled), - if (qi.content is MsgContent.MCFile) stringResource(R.string.icon_descr_file) else stringResource(R.string.voice_message), + if (qi.content is MsgContent.MCFile) stringResource(MR.strings.icon_descr_file) else stringResource(MR.strings.voice_message), Modifier .padding(top = 6.dp, end = 4.dp) .size(22.dp), @@ -181,12 +182,12 @@ fun FramedItemView( PriorityLayout(Modifier, CHAT_IMAGE_LAYOUT_ID) { if (ci.meta.itemDeleted != null) { if (ci.meta.itemDeleted is CIDeleted.Moderated) { - FramedItemHeader(String.format(stringResource(R.string.moderated_item_description), ci.meta.itemDeleted.byGroupMember.chatViewName), true, painterResource(R.drawable.ic_flag)) + FramedItemHeader(String.format(stringResource(MR.strings.moderated_item_description), ci.meta.itemDeleted.byGroupMember.chatViewName), true, painterResource(R.drawable.ic_flag)) } else { - FramedItemHeader(stringResource(R.string.marked_deleted_description), true, painterResource(R.drawable.ic_delete)) + FramedItemHeader(stringResource(MR.strings.marked_deleted_description), true, painterResource(R.drawable.ic_delete)) } } else if (ci.meta.isLive) { - FramedItemHeader(stringResource(R.string.live), false) + FramedItemHeader(stringResource(MR.strings.live), false) } ci.quotedItem?.let { ciQuoteView(it) } if (ci.file == null && ci.formattedText == null && !ci.meta.isLive && isShortEmoji(ci.content.text)) { diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/ImageFullScreenView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/ImageFullScreenView.kt index a0279d0220..9cfaa3481f 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/ImageFullScreenView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/ImageFullScreenView.kt @@ -19,7 +19,7 @@ import androidx.compose.ui.input.pointer.* import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.* -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.* import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.isVisible @@ -35,6 +35,7 @@ import coil.size.Size import com.google.accompanist.pager.* import com.google.android.exoplayer2.ui.AspectRatioFrameLayout import com.google.android.exoplayer2.ui.StyledPlayerView +import chat.simplex.res.MR import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch import kotlin.math.absoluteValue @@ -159,7 +160,7 @@ fun ImageFullScreenView(imageProvider: () -> ImageGalleryProvider, close: () -> placeholder = BitmapPainter(imageBitmap.asImageBitmap()), // show original image while it's still loading by coil imageLoader = imageLoader ), - contentDescription = stringResource(R.string.image_descr), + contentDescription = stringResource(MR.strings.image_descr), contentScale = ContentScale.Fit, modifier = modifier, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/IntegrityErrorItemView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/IntegrityErrorItemView.kt index e1ddd3b3e7..77a0219ca4 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/IntegrityErrorItemView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/IntegrityErrorItemView.kt @@ -23,6 +23,7 @@ import chat.simplex.app.ui.theme.CurrentColors import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.helpers.AlertManager import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR @Composable fun IntegrityErrorItemView(msgError: MsgErrorType, ci: ChatItem, timedMessagesTTL: Int?, showMember: Boolean = false) { @@ -30,21 +31,21 @@ fun IntegrityErrorItemView(msgError: MsgErrorType, ci: ChatItem, timedMessagesTT when (msgError) { is MsgErrorType.MsgSkipped -> AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.alert_title_skipped_messages), - text = generalGetString(R.string.alert_text_skipped_messages_it_can_happen_when) + title = generalGetString(MR.strings.alert_title_skipped_messages), + text = generalGetString(MR.strings.alert_text_skipped_messages_it_can_happen_when) ) is MsgErrorType.MsgBadHash -> AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.alert_title_msg_bad_hash), - text = generalGetString(R.string.alert_text_msg_bad_hash) + "\n" + - generalGetString(R.string.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" + - generalGetString(R.string.alert_text_fragment_please_report_to_developers) + title = generalGetString(MR.strings.alert_title_msg_bad_hash), + text = generalGetString(MR.strings.alert_text_msg_bad_hash) + "\n" + + generalGetString(MR.strings.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" + + generalGetString(MR.strings.alert_text_fragment_please_report_to_developers) ) is MsgErrorType.MsgBadId, is MsgErrorType.MsgDuplicate -> AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.alert_title_msg_bad_id), - text = generalGetString(R.string.alert_text_msg_bad_id) + "\n" + - generalGetString(R.string.alert_text_fragment_please_report_to_developers) + title = generalGetString(MR.strings.alert_title_msg_bad_id), + text = generalGetString(MR.strings.alert_text_msg_bad_id) + "\n" + + generalGetString(MR.strings.alert_text_fragment_please_report_to_developers) ) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/MarkedDeletedItemView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/MarkedDeletedItemView.kt index 937d007517..22192a3692 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/MarkedDeletedItemView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chat/item/MarkedDeletedItemView.kt @@ -19,6 +19,7 @@ import chat.simplex.app.model.CIDeleted import chat.simplex.app.model.ChatItem import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR import kotlinx.datetime.Clock @Composable @@ -35,9 +36,9 @@ fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, showMember: Bool ) { Box(Modifier.weight(1f, false)) { if (ci.meta.itemDeleted is CIDeleted.Moderated) { - MarkedDeletedText(String.format(generalGetString(R.string.moderated_item_description), ci.meta.itemDeleted.byGroupMember.chatViewName)) + MarkedDeletedText(String.format(generalGetString(MR.strings.moderated_item_description), ci.meta.itemDeleted.byGroupMember.chatViewName)) } else { - MarkedDeletedText(generalGetString(R.string.marked_deleted_description)) + MarkedDeletedText(generalGetString(MR.strings.marked_deleted_description)) } } CIMetaView(ci, timedMessagesTTL) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatHelpView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatHelpView.kt index 7e933413a4..20a3ef44ed 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatHelpView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatHelpView.kt @@ -8,7 +8,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview @@ -20,6 +20,7 @@ import chat.simplex.app.views.helpers.annotatedStringResource import chat.simplex.app.views.onboarding.ReadableTextWithLink import chat.simplex.app.views.usersettings.MarkdownHelpView import chat.simplex.app.views.usersettings.simplexTeamUri +import chat.simplex.res.MR val bold = SpanStyle(fontWeight = FontWeight.Bold) @@ -28,14 +29,14 @@ fun ChatHelpView(addContact: (() -> Unit)? = null) { Column( verticalArrangement = Arrangement.spacedBy(10.dp) ) { - Text(stringResource(R.string.thank_you_for_installing_simplex), lineHeight = 22.sp) - ReadableTextWithLink(R.string.you_can_connect_to_simplex_chat_founder, simplexTeamUri) + Text(stringResource(MR.strings.thank_you_for_installing_simplex), lineHeight = 22.sp) + ReadableTextWithLink(MR.strings.you_can_connect_to_simplex_chat_founder, simplexTeamUri) Column( Modifier.padding(top = 24.dp), verticalArrangement = Arrangement.spacedBy(10.dp) ) { Text( - stringResource(R.string.to_start_a_new_chat_help_header), + stringResource(MR.strings.to_start_a_new_chat_help_header), style = MaterialTheme.typography.h2, lineHeight = 22.sp ) @@ -43,33 +44,33 @@ fun ChatHelpView(addContact: (() -> Unit)? = null) { verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - Text(stringResource(R.string.chat_help_tap_button)) + Text(stringResource(MR.strings.chat_help_tap_button)) Icon( painterResource(R.drawable.ic_person_add), - stringResource(R.string.add_contact), + stringResource(MR.strings.add_contact), modifier = if (addContact != null) Modifier.clickable(onClick = addContact) else Modifier, ) - Text(stringResource(R.string.above_then_preposition_continuation)) + Text(stringResource(MR.strings.above_then_preposition_continuation)) } - Text(annotatedStringResource(R.string.add_new_contact_to_create_one_time_QR_code), lineHeight = 22.sp) - Text(annotatedStringResource(R.string.scan_QR_code_to_connect_to_contact_who_shows_QR_code), lineHeight = 22.sp) + Text(annotatedStringResource(MR.strings.add_new_contact_to_create_one_time_QR_code), lineHeight = 22.sp) + Text(annotatedStringResource(MR.strings.scan_QR_code_to_connect_to_contact_who_shows_QR_code), lineHeight = 22.sp) } Column( Modifier.padding(top = 24.dp), verticalArrangement = Arrangement.spacedBy(10.dp) ) { - Text(stringResource(R.string.to_connect_via_link_title), style = MaterialTheme.typography.h2) - Text(stringResource(R.string.if_you_received_simplex_invitation_link_you_can_open_in_browser), lineHeight = 22.sp) - Text(annotatedStringResource(R.string.desktop_scan_QR_code_from_app_via_scan_QR_code), lineHeight = 22.sp) - Text(annotatedStringResource(R.string.mobile_tap_open_in_mobile_app_then_tap_connect_in_app), lineHeight = 22.sp) + Text(stringResource(MR.strings.to_connect_via_link_title), style = MaterialTheme.typography.h2) + Text(stringResource(MR.strings.if_you_received_simplex_invitation_link_you_can_open_in_browser), lineHeight = 22.sp) + Text(annotatedStringResource(MR.strings.desktop_scan_QR_code_from_app_via_scan_QR_code), lineHeight = 22.sp) + Text(annotatedStringResource(MR.strings.mobile_tap_open_in_mobile_app_then_tap_connect_in_app), lineHeight = 22.sp) } Column( Modifier.padding(vertical = 24.dp), verticalArrangement = Arrangement.spacedBy(10.dp) ) { - Text(stringResource(R.string.markdown_in_messages), style = MaterialTheme.typography.h2) + Text(stringResource(MR.strings.markdown_in_messages), style = MaterialTheme.typography.h2) MarkdownHelpView() } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt index dc9aaca3b8..46a0bd1866 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt @@ -10,7 +10,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -26,6 +26,7 @@ import chat.simplex.app.views.chat.item.InvalidJSONView import chat.simplex.app.views.chat.item.ItemAction import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.ContactConnectionInfoView +import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.datetime.Clock @@ -190,7 +191,7 @@ fun GroupMenuItems(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, showM @Composable fun MarkReadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState) { ItemAction( - stringResource(R.string.mark_read), + stringResource(MR.strings.mark_read), painterResource(R.drawable.ic_check), onClick = { markChatRead(chat, chatModel) @@ -203,7 +204,7 @@ fun MarkReadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState< @Composable fun MarkUnreadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState) { ItemAction( - stringResource(R.string.mark_unread), + stringResource(MR.strings.mark_unread), painterResource(R.drawable.ic_mark_chat_unread), onClick = { markChatUnread(chat, chatModel) @@ -215,7 +216,7 @@ fun MarkUnreadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableStat @Composable fun ToggleFavoritesChatAction(chat: Chat, chatModel: ChatModel, favorite: Boolean, showMenu: MutableState) { ItemAction( - if (favorite) stringResource(R.string.unfavorite_chat) else stringResource(R.string.favorite_chat), + if (favorite) stringResource(MR.strings.unfavorite_chat) else stringResource(MR.strings.favorite_chat), if (favorite) painterResource(R.drawable.ic_star_off) else painterResource(R.drawable.ic_star), onClick = { toggleChatFavorite(chat, !favorite, chatModel) @@ -227,7 +228,7 @@ fun ToggleFavoritesChatAction(chat: Chat, chatModel: ChatModel, favorite: Boolea @Composable fun ToggleNotificationsChatAction(chat: Chat, chatModel: ChatModel, ntfsEnabled: Boolean, showMenu: MutableState) { ItemAction( - if (ntfsEnabled) stringResource(R.string.mute_chat) else stringResource(R.string.unmute_chat), + if (ntfsEnabled) stringResource(MR.strings.mute_chat) else stringResource(MR.strings.unmute_chat), if (ntfsEnabled) painterResource(R.drawable.ic_notifications_off) else painterResource(R.drawable.ic_notifications), onClick = { toggleNotifications(chat, !ntfsEnabled, chatModel) @@ -239,7 +240,7 @@ fun ToggleNotificationsChatAction(chat: Chat, chatModel: ChatModel, ntfsEnabled: @Composable fun ClearChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState) { ItemAction( - stringResource(R.string.clear_chat_menu_action), + stringResource(MR.strings.clear_chat_menu_action), painterResource(R.drawable.ic_settings_backup_restore), onClick = { clearChatDialog(chat.chatInfo, chatModel) @@ -252,7 +253,7 @@ fun ClearChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState) { ItemAction( - stringResource(R.string.delete_contact_menu_action), + stringResource(MR.strings.delete_contact_menu_action), painterResource(R.drawable.ic_delete), onClick = { deleteContactDialog(chat.chatInfo, chatModel) @@ -265,7 +266,7 @@ fun DeleteContactAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState @Composable fun DeleteGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState) { ItemAction( - stringResource(R.string.delete_group_menu_action), + stringResource(MR.strings.delete_group_menu_action), painterResource(R.drawable.ic_delete), onClick = { deleteGroupDialog(chat.chatInfo, groupInfo, chatModel) @@ -279,7 +280,7 @@ fun DeleteGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, sh fun JoinGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState) { val joinGroup: () -> Unit = { withApi { chatModel.controller.apiJoinGroup(groupInfo.groupId) } } ItemAction( - if (chat.chatInfo.incognito) stringResource(R.string.join_group_incognito_button) else stringResource(R.string.join_group_button), + if (chat.chatInfo.incognito) stringResource(MR.strings.join_group_incognito_button) else stringResource(MR.strings.join_group_button), if (chat.chatInfo.incognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_login), color = if (chat.chatInfo.incognito) Indigo else MaterialTheme.colors.onBackground, onClick = { @@ -292,7 +293,7 @@ fun JoinGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, show @Composable fun LeaveGroupAction(groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState) { ItemAction( - stringResource(R.string.leave_group_button), + stringResource(MR.strings.leave_group_button), painterResource(R.drawable.ic_logout), onClick = { leaveGroupDialog(groupInfo, chatModel) @@ -305,7 +306,7 @@ fun LeaveGroupAction(groupInfo: GroupInfo, chatModel: ChatModel, showMenu: Mutab @Composable fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatModel, showMenu: MutableState) { ItemAction( - if (chatModel.incognito.value) stringResource(R.string.accept_contact_incognito_button) else stringResource(R.string.accept_contact_button), + if (chatModel.incognito.value) stringResource(MR.strings.accept_contact_incognito_button) else stringResource(MR.strings.accept_contact_button), if (chatModel.incognito.value) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_check), color = if (chatModel.incognito.value) Indigo else MaterialTheme.colors.onBackground, onClick = { @@ -314,7 +315,7 @@ fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatMo } ) ItemAction( - stringResource(R.string.reject_contact_button), + stringResource(MR.strings.reject_contact_button), painterResource(R.drawable.ic_close), onClick = { rejectContactRequest(chatInfo, chatModel) @@ -327,7 +328,7 @@ fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatMo @Composable fun ContactConnectionMenuItems(chatInfo: ChatInfo.ContactConnection, chatModel: ChatModel, showMenu: MutableState) { ItemAction( - stringResource(R.string.set_contact_name), + stringResource(MR.strings.set_contact_name), painterResource(R.drawable.ic_edit), onClick = { ModalManager.shared.showModalCloseable(true) { close -> @@ -337,7 +338,7 @@ fun ContactConnectionMenuItems(chatInfo: ChatInfo.ContactConnection, chatModel: }, ) ItemAction( - stringResource(R.string.delete_verb), + stringResource(MR.strings.delete_verb), painterResource(R.drawable.ic_delete), onClick = { deleteContactConnectionAlert(chatInfo.contactConnection, chatModel) {} @@ -357,7 +358,7 @@ private fun InvalidDataView() { .weight(1F) ) { Text( - stringResource(R.string.invalid_data), + stringResource(MR.strings.invalid_data), maxLines = 1, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.h3, @@ -414,11 +415,11 @@ fun markChatUnread(chat: Chat, chatModel: ChatModel) { fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.accept_connection_request__question), - text = generalGetString(R.string.if_you_choose_to_reject_the_sender_will_not_be_notified), - confirmText = if (chatModel.incognito.value) generalGetString(R.string.accept_contact_incognito_button) else generalGetString(R.string.accept_contact_button), + title = generalGetString(MR.strings.accept_connection_request__question), + text = generalGetString(MR.strings.if_you_choose_to_reject_the_sender_will_not_be_notified), + confirmText = if (chatModel.incognito.value) generalGetString(MR.strings.accept_contact_incognito_button) else generalGetString(MR.strings.accept_contact_button), onConfirm = { acceptContactRequest(contactRequest.apiId, contactRequest, true, chatModel) }, - dismissText = generalGetString(R.string.reject_contact_button), + dismissText = generalGetString(MR.strings.reject_contact_button), onDismiss = { rejectContactRequest(contactRequest, chatModel) } ) } @@ -443,12 +444,12 @@ fun rejectContactRequest(contactRequest: ChatInfo.ContactRequest, chatModel: Cha fun contactConnectionAlertDialog(connection: PendingContactConnection, chatModel: ChatModel) { AlertManager.shared.showAlertDialogButtons( title = generalGetString( - if (connection.initiated) R.string.you_invited_your_contact - else R.string.you_accepted_connection + if (connection.initiated) MR.strings.you_invited_your_contact + else MR.strings.you_accepted_connection ), text = generalGetString( - if (connection.viaContactUri) R.string.you_will_be_connected_when_your_connection_request_is_accepted - else R.string.you_will_be_connected_when_your_contacts_device_is_online + if (connection.viaContactUri) MR.strings.you_will_be_connected_when_your_connection_request_is_accepted + else MR.strings.you_will_be_connected_when_your_contacts_device_is_online ), buttons = { Row( @@ -461,11 +462,11 @@ fun contactConnectionAlertDialog(connection: PendingContactConnection, chatModel AlertManager.shared.hideAlert() deleteContactConnectionAlert(connection, chatModel) {} }) { - Text(stringResource(R.string.delete_verb)) + Text(stringResource(MR.strings.delete_verb)) } Spacer(Modifier.padding(horizontal = 4.dp)) TextButton(onClick = { AlertManager.shared.hideAlert() }) { - Text(stringResource(R.string.ok)) + Text(stringResource(MR.strings.ok)) } } } @@ -474,12 +475,12 @@ fun contactConnectionAlertDialog(connection: PendingContactConnection, chatModel fun deleteContactConnectionAlert(connection: PendingContactConnection, chatModel: ChatModel, onSuccess: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_pending_connection__question), + title = generalGetString(MR.strings.delete_pending_connection__question), text = generalGetString( - if (connection.initiated) R.string.contact_you_shared_link_with_wont_be_able_to_connect - else R.string.connection_you_accepted_will_be_cancelled + if (connection.initiated) MR.strings.contact_you_shared_link_with_wont_be_able_to_connect + else MR.strings.connection_you_accepted_will_be_cancelled ), - confirmText = generalGetString(R.string.delete_verb), + confirmText = generalGetString(MR.strings.delete_verb), onConfirm = { withApi { AlertManager.shared.hideAlert() @@ -495,9 +496,9 @@ fun deleteContactConnectionAlert(connection: PendingContactConnection, chatModel fun pendingContactAlertDialog(chatInfo: ChatInfo, chatModel: ChatModel) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.alert_title_contact_connection_pending), - text = generalGetString(R.string.alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry), - confirmText = generalGetString(R.string.button_delete_contact), + title = generalGetString(MR.strings.alert_title_contact_connection_pending), + text = generalGetString(MR.strings.alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry), + confirmText = generalGetString(MR.strings.button_delete_contact), onConfirm = { withApi { val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId) @@ -508,26 +509,26 @@ fun pendingContactAlertDialog(chatInfo: ChatInfo, chatModel: ChatModel) { } }, destructive = true, - dismissText = generalGetString(R.string.cancel_verb), + dismissText = generalGetString(MR.strings.cancel_verb), ) } fun acceptGroupInvitationAlertDialog(groupInfo: GroupInfo, chatModel: ChatModel) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.join_group_question), - text = generalGetString(R.string.you_are_invited_to_group_join_to_connect_with_group_members), - confirmText = if (groupInfo.membership.memberIncognito) generalGetString(R.string.join_group_incognito_button) else generalGetString(R.string.join_group_button), + title = generalGetString(MR.strings.join_group_question), + text = generalGetString(MR.strings.you_are_invited_to_group_join_to_connect_with_group_members), + confirmText = if (groupInfo.membership.memberIncognito) generalGetString(MR.strings.join_group_incognito_button) else generalGetString(MR.strings.join_group_button), onConfirm = { withApi { chatModel.controller.apiJoinGroup(groupInfo.groupId) } }, - dismissText = generalGetString(R.string.delete_verb), + dismissText = generalGetString(MR.strings.delete_verb), onDismiss = { deleteGroup(groupInfo, chatModel) } ) } fun cantInviteIncognitoAlert() { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.alert_title_cant_invite_contacts), - text = generalGetString(R.string.alert_title_cant_invite_contacts_descr), - confirmText = generalGetString(R.string.ok), + title = generalGetString(MR.strings.alert_title_cant_invite_contacts), + text = generalGetString(MR.strings.alert_title_cant_invite_contacts_descr), + confirmText = generalGetString(MR.strings.ok), ) } @@ -544,8 +545,8 @@ fun deleteGroup(groupInfo: GroupInfo, chatModel: ChatModel) { fun groupInvitationAcceptedAlert() { AlertManager.shared.showAlertMsg( - generalGetString(R.string.joining_group), - generalGetString(R.string.youve_accepted_group_invitation_connecting_to_inviting_group_member) + generalGetString(MR.strings.joining_group), + generalGetString(MR.strings.youve_accepted_group_invitation_connecting_to_inviting_group_member) ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt index f18142c690..11db16e9d6 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt @@ -14,7 +14,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.* import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale @@ -31,12 +31,13 @@ import chat.simplex.app.views.onboarding.WhatsNewView import chat.simplex.app.views.onboarding.shouldShowWhatsNew import chat.simplex.app.views.usersettings.SettingsView import chat.simplex.app.views.usersettings.simplexTeamUri +import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch @Composable -fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity) -> Unit, stopped: Boolean) { +fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit, stopped: Boolean) { val newChatSheetState by rememberSaveable(stateSaver = AnimatedViewState.saver()) { mutableStateOf(MutableStateFlow(AnimatedViewState.GONE)) } val userPickerState by rememberSaveable(stateSaver = AnimatedViewState.saver()) { mutableStateOf(MutableStateFlow(AnimatedViewState.GONE)) } val showNewChatSheet = { @@ -88,7 +89,7 @@ fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity) backgroundColor = if (!stopped) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, contentColor = Color.White ) { - Icon(if (!newChatSheetState.collectAsState().value.isVisible()) painterResource(R.drawable.ic_edit_filled) else painterResource(R.drawable.ic_close), stringResource(R.string.add_contact_or_create_group)) + Icon(if (!newChatSheetState.collectAsState().value.isVisible()) painterResource(R.drawable.ic_edit_filled) else painterResource(R.drawable.ic_close), stringResource(MR.strings.add_contact_or_create_group)) } } } @@ -105,7 +106,7 @@ fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity) if (!stopped && !newChatSheetState.collectAsState().value.isVisible()) { OnboardingButtons(showNewChatSheet) } - Text(stringResource(R.string.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary) + Text(stringResource(MR.strings.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary) } } } @@ -131,11 +132,11 @@ fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity) private fun OnboardingButtons(openNewChatSheet: () -> Unit) { Column(Modifier.fillMaxSize().padding(DEFAULT_PADDING), horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.Bottom) { val uriHandler = LocalUriHandler.current - ConnectButton(generalGetString(R.string.chat_with_developers)) { + ConnectButton(generalGetString(MR.strings.chat_with_developers)) { uriHandler.openUriCatching(simplexTeamUri) } Spacer(Modifier.height(DEFAULT_PADDING)) - ConnectButton(generalGetString(R.string.tap_to_start_new_chat), openNewChatSheet) + ConnectButton(generalGetString(MR.strings.tap_to_start_new_chat), openNewChatSheet) val color = MaterialTheme.colors.primaryVariant Canvas(modifier = Modifier.width(40.dp).height(10.dp), onDraw = { val trianglePath = Path().apply { @@ -180,7 +181,7 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user if (chatModel.chats.size > 0) { barButtons.add { IconButton({ showSearch = true }) { - Icon(painterResource(R.drawable.ic_search_500), stringResource(android.R.string.search_go).capitalize(Locale.current), tint = MaterialTheme.colors.primary) + Icon(painterResource(R.drawable.ic_search_500), stringResource(MR.strings.search_verb).capitalize(Locale.current), tint = MaterialTheme.colors.primary) } } } @@ -188,13 +189,13 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user barButtons.add { IconButton(onClick = { AlertManager.shared.showAlertMsg( - generalGetString(R.string.chat_is_stopped_indication), - generalGetString(R.string.you_can_start_chat_via_setting_or_by_restarting_the_app) + generalGetString(MR.strings.chat_is_stopped_indication), + generalGetString(MR.strings.you_can_start_chat_via_setting_or_by_restarting_the_app) ) }) { Icon( painterResource(R.drawable.ic_report_filled), - generalGetString(R.string.chat_is_stopped_indication), + generalGetString(MR.strings.chat_is_stopped_indication), tint = Color.Red, ) } @@ -226,13 +227,13 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user if (chatModel.incognito.value) { Icon( painterResource(R.drawable.ic_theater_comedy_filled), - stringResource(R.string.incognito), + stringResource(MR.strings.incognito), tint = Indigo, modifier = Modifier.padding(10.dp).size(26.dp) ) } Text( - stringResource(R.string.your_chats), + stringResource(MR.strings.your_chats), color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.SemiBold, ) @@ -328,7 +329,7 @@ private fun ChatList(chatModel: ChatModel, search: String) { } if (chats.isEmpty() && !chatModel.chats.isEmpty()) { Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Text(generalGetString(R.string.no_filtered_chats), color = MaterialTheme.colors.secondary) + Text(generalGetString(MR.strings.no_filtered_chats), color = MaterialTheme.colors.secondary) } } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt index 4726cc825b..9059ce8be7 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow @@ -26,6 +26,7 @@ import chat.simplex.app.views.chat.ComposePreview import chat.simplex.app.views.chat.ComposeState import chat.simplex.app.views.chat.item.MarkdownText import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun ChatPreviewView( @@ -44,7 +45,7 @@ fun ChatPreviewView( fun groupInactiveIcon() { Icon( painterResource(R.drawable.ic_cancel_filled), - stringResource(R.string.icon_descr_group_inactive), + stringResource(MR.strings.icon_descr_group_inactive), Modifier.size(18.dp).background(MaterialTheme.colors.background, CircleShape), tint = MaterialTheme.colors.secondary ) @@ -143,7 +144,7 @@ fun ChatPreviewView( val (text: CharSequence, inlineTextContent) = when { chatModelDraftChatId == chat.id && chatModelDraft != null -> remember(chatModelDraft) { messageDraft(chatModelDraft) } ci.meta.itemDeleted == null -> ci.text to null - else -> generalGetString(R.string.marked_deleted_description) to null + else -> generalGetString(MR.strings.marked_deleted_description) to null } val formattedText = when { chatModelDraftChatId == chat.id && chatModelDraft != null -> null @@ -170,12 +171,12 @@ fun ChatPreviewView( when (cInfo) { is ChatInfo.Direct -> if (!cInfo.ready) { - Text(stringResource(R.string.contact_connection_pending), color = MaterialTheme.colors.secondary) + Text(stringResource(MR.strings.contact_connection_pending), color = MaterialTheme.colors.secondary) } is ChatInfo.Group -> when (cInfo.groupInfo.membership.memberStatus) { GroupMemberStatus.MemInvited -> Text(groupInvitationPreviewText(chatModelIncognito, currentUserProfileDisplayName, cInfo.groupInfo)) - GroupMemberStatus.MemAccepted -> Text(stringResource(R.string.group_connection_pending), color = MaterialTheme.colors.secondary) + GroupMemberStatus.MemAccepted -> Text(stringResource(MR.strings.group_connection_pending), color = MaterialTheme.colors.secondary) else -> {} } else -> {} @@ -237,7 +238,7 @@ fun ChatPreviewView( ) { Icon( painterResource(R.drawable.ic_notifications_off_filled), - contentDescription = generalGetString(R.string.notifications), + contentDescription = generalGetString(MR.strings.notifications), tint = MaterialTheme.colors.secondary, modifier = Modifier .padding(horizontal = 3.dp) @@ -252,7 +253,7 @@ fun ChatPreviewView( ) { Icon( painterResource(R.drawable.ic_star_filled), - contentDescription = generalGetString(R.string.favorite_chat), + contentDescription = generalGetString(MR.strings.favorite_chat), tint = MaterialTheme.colors.secondary, modifier = Modifier .padding(horizontal = 3.dp) @@ -276,16 +277,16 @@ fun ChatPreviewView( @Composable private fun groupInvitationPreviewText(chatModelIncognito: Boolean, currentUserProfileDisplayName: String?, groupInfo: GroupInfo): String { return if (groupInfo.membership.memberIncognito) - String.format(stringResource(R.string.group_preview_join_as), groupInfo.membership.memberProfile.displayName) + String.format(stringResource(MR.strings.group_preview_join_as), groupInfo.membership.memberProfile.displayName) else if (chatModelIncognito) - String.format(stringResource(R.string.group_preview_join_as), currentUserProfileDisplayName ?: "") + String.format(stringResource(MR.strings.group_preview_join_as), currentUserProfileDisplayName ?: "") else - stringResource(R.string.group_preview_you_are_invited) + stringResource(MR.strings.group_preview_you_are_invited) } @Composable fun unreadCountStr(n: Int): String { - return if (n < 1000) "$n" else "${n / 1000}" + stringResource(R.string.thousand_abbreviation) + return if (n < 1000) "$n" else "${n / 1000}" + stringResource(MR.strings.thousand_abbreviation) } @Composable diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ContactRequestView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ContactRequestView.kt index 936d3d2590..8d95226730 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ContactRequestView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ContactRequestView.kt @@ -6,7 +6,7 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -15,6 +15,7 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.ChatInfoImage +import chat.simplex.res.MR @Composable fun ContactRequestView(chatModelIncognito: Boolean, contactRequest: ChatInfo.ContactRequest) { @@ -34,7 +35,7 @@ fun ContactRequestView(chatModelIncognito: Boolean, contactRequest: ChatInfo.Con color = if (chatModelIncognito) Indigo else MaterialTheme.colors.primary ) val height = with(LocalDensity.current) { 46.sp.toDp() } - Text(stringResource(R.string.contact_wants_to_connect_with_you), Modifier.heightIn(min = height), maxLines = 2, color = if (isInDarkTheme()) MessagePreviewDark else MessagePreviewLight) + Text(stringResource(MR.strings.contact_wants_to_connect_with_you), Modifier.heightIn(min = height), maxLines = 2, color = if (isInDarkTheme()) MessagePreviewDark else MessagePreviewLight) } val ts = getTimestampText(contactRequest.contactRequest.updatedAt) Column( diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ShareListView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ShareListView.kt index 1f74929065..19593dd032 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ShareListView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/ShareListView.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale @@ -21,6 +21,7 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.flow.MutableStateFlow @Composable @@ -52,7 +53,7 @@ fun ShareListView(chatModel: ChatModel, stopped: Boolean) { @Composable private fun EmptyList() { Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Text(stringResource(R.string.you_have_no_chats), color = MaterialTheme.colors.secondary) + Text(stringResource(MR.strings.you_have_no_chats), color = MaterialTheme.colors.secondary) } } @@ -82,7 +83,7 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState if (chatModel.chats.size >= 8) { barButtons.add { IconButton({ showSearch = true }) { - Icon(painterResource(R.drawable.ic_search_500), stringResource(android.R.string.search_go).capitalize(Locale.current), tint = MaterialTheme.colors.primary) + Icon(painterResource(R.drawable.ic_search_500), stringResource(MR.strings.search_verb).capitalize(Locale.current), tint = MaterialTheme.colors.primary) } } } @@ -90,13 +91,13 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState barButtons.add { IconButton(onClick = { AlertManager.shared.showAlertMsg( - generalGetString(R.string.chat_is_stopped_indication), - generalGetString(R.string.you_can_start_chat_via_setting_or_by_restarting_the_app) + generalGetString(MR.strings.chat_is_stopped_indication), + generalGetString(MR.strings.you_can_start_chat_via_setting_or_by_restarting_the_app) ) }) { Icon( painterResource(R.drawable.ic_report_filled), - generalGetString(R.string.chat_is_stopped_indication), + generalGetString(MR.strings.chat_is_stopped_indication), tint = Color.Red, ) } @@ -109,10 +110,10 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState Row(verticalAlignment = Alignment.CenterVertically) { Text( when (chatModel.sharedContent.value) { - is SharedContent.Text -> stringResource(R.string.share_message) - is SharedContent.Media -> stringResource(R.string.share_image) - is SharedContent.File -> stringResource(R.string.share_file) - else -> stringResource(R.string.share_message) + is SharedContent.Text -> stringResource(MR.strings.share_message) + is SharedContent.Media -> stringResource(MR.strings.share_image) + is SharedContent.File -> stringResource(MR.strings.share_file) + else -> stringResource(MR.strings.share_message) }, color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.SemiBold, @@ -120,7 +121,7 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState if (chatModel.incognito.value) { Icon( painterResource(R.drawable.ic_theater_comedy_filled), - stringResource(R.string.incognito), + stringResource(MR.strings.incognito), tint = Indigo, modifier = Modifier.padding(10.dp).size(26.dp) ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/UserPicker.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/UserPicker.kt index 31d6e96efa..0c74769e55 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/UserPicker.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/chatlist/UserPicker.kt @@ -26,6 +26,7 @@ import chat.simplex.app.TAG import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch @@ -217,7 +218,7 @@ fun UserProfileRow(u: User) { @Composable private fun SettingsPickerItem(onClick: () -> Unit) { SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) { - val text = generalGetString(R.string.settings_section_title_settings).lowercase().capitalize(Locale.current) + val text = generalGetString(MR.strings.settings_section_title_settings).lowercase().capitalize(Locale.current) Icon(painterResource(R.drawable.ic_settings), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) Text( @@ -230,7 +231,7 @@ private fun SettingsPickerItem(onClick: () -> Unit) { @Composable private fun CancelPickerItem(onClick: () -> Unit) { SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) { - val text = generalGetString(R.string.cancel_verb) + val text = generalGetString(MR.strings.cancel_verb) Icon(painterResource(R.drawable.ic_close), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground) Spacer(Modifier.width(DEFAULT_PADDING + 6.dp)) Text( diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/ChatArchiveView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/ChatArchiveView.kt index 6bafc207c1..7c2cb32506 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/ChatArchiveView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/ChatArchiveView.kt @@ -18,7 +18,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import chat.simplex.app.* import chat.simplex.app.R @@ -26,6 +26,7 @@ import chat.simplex.app.model.ChatModel import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.* +import chat.simplex.res.MR import kotlinx.datetime.* import java.io.BufferedOutputStream import java.io.File @@ -56,17 +57,17 @@ fun ChatArchiveLayout( Modifier.fillMaxWidth(), ) { AppBarTitle(title) - SectionView(stringResource(R.string.chat_archive_section)) { + SectionView(stringResource(MR.strings.chat_archive_section)) { SettingsActionItem( painterResource(R.drawable.ic_ios_share), - stringResource(R.string.save_archive), + stringResource(MR.strings.save_archive), saveArchive, textColor = MaterialTheme.colors.primary, iconColor = MaterialTheme.colors.primary, ) SettingsActionItem( painterResource(R.drawable.ic_delete), - stringResource(R.string.delete_archive), + stringResource(MR.strings.delete_archive), deleteArchiveAlert, textColor = Color.Red, iconColor = Color.Red, @@ -74,7 +75,7 @@ fun ChatArchiveLayout( } val archiveTs = SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US).format(Date.from(archiveTime.toJavaInstant())) SectionTextFooter( - String.format(generalGetString(R.string.archive_created_on_ts), archiveTs) + String.format(generalGetString(MR.strings.archive_created_on_ts), archiveTs) ) SectionBottomSpacer() } @@ -93,11 +94,11 @@ private fun rememberSaveArchiveLauncher(chatArchivePath: String): ManagedActivit val outputStream = BufferedOutputStream(stream) File(chatArchivePath).inputStream().use { it.copyTo(outputStream) } outputStream.close() - Toast.makeText(cxt, generalGetString(R.string.file_saved), Toast.LENGTH_SHORT).show() + Toast.makeText(cxt, generalGetString(MR.strings.file_saved), Toast.LENGTH_SHORT).show() } } } catch (e: Error) { - Toast.makeText(cxt, generalGetString(R.string.error_saving_file), Toast.LENGTH_SHORT).show() + Toast.makeText(cxt, generalGetString(MR.strings.error_saving_file), Toast.LENGTH_SHORT).show() Log.e(TAG, "rememberSaveArchiveLauncher error saving archive $e") } } @@ -105,8 +106,8 @@ private fun rememberSaveArchiveLauncher(chatArchivePath: String): ManagedActivit private fun deleteArchiveAlert(m: ChatModel, archivePath: String) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_chat_archive_question), - confirmText = generalGetString(R.string.delete_verb), + title = generalGetString(MR.strings.delete_chat_archive_question), + confirmText = generalGetString(MR.strings.delete_verb), onConfirm = { val fileDeleted = File(archivePath).delete() if (fileDeleted) { diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseEncryptionView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseEncryptionView.kt index 642d855ac1..156c51b52d 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseEncryptionView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseEncryptionView.kt @@ -19,7 +19,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.* @@ -30,6 +30,7 @@ import chat.simplex.app.SimplexApp import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.datetime.Clock import kotlin.math.log2 @@ -71,14 +72,14 @@ fun DatabaseEncryptionView(m: ChatModel) { sqliteError is SQLiteError.ErrorNotADatabase -> { operationEnded(m, progressIndicator) { AlertManager.shared.showAlertMsg( - generalGetString(R.string.wrong_passphrase_title), - generalGetString(R.string.enter_correct_current_passphrase) + generalGetString(MR.strings.wrong_passphrase_title), + generalGetString(MR.strings.enter_correct_current_passphrase) ) } } error != null -> { operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_encrypting_database), + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_encrypting_database), "failed to set storage encryption: ${error.responseType} ${error.details}" ) } @@ -91,13 +92,13 @@ fun DatabaseEncryptionView(m: ChatModel) { } resetFormAfterEncryption(m, initialRandomDBPassphrase, currentKey, newKey, confirmNewKey, storedKey, useKeychain.value) operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.database_encrypted)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.database_encrypted)) } } } } catch (e: Exception) { operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_encrypting_database), e.stackTraceToString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_encrypting_database), e.stackTraceToString()) } } } @@ -136,16 +137,16 @@ fun DatabaseEncryptionLayout( Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.database_passphrase)) + AppBarTitle(stringResource(MR.strings.database_passphrase)) SectionView(null) { SavePassphraseSetting(useKeychain.value, initialRandomDBPassphrase.value, storedKey.value, progressIndicator.value) { checked -> if (checked) { setUseKeychain(true, useKeychain, prefs) } else if (storedKey.value) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.remove_passphrase_from_keychain), - text = generalGetString(R.string.notifications_will_be_hidden) + "\n" + storeSecurelyDanger(), - confirmText = generalGetString(R.string.remove_passphrase), + title = generalGetString(MR.strings.remove_passphrase_from_keychain), + text = generalGetString(MR.strings.notifications_will_be_hidden) + "\n" + storeSecurelyDanger(), + confirmText = generalGetString(MR.strings.remove_passphrase), onConfirm = { DatabaseUtils.ksDatabasePassword.remove() setUseKeychain(false, useKeychain, prefs) @@ -161,7 +162,7 @@ fun DatabaseEncryptionLayout( if (!initialRandomDBPassphrase.value && chatDbEncrypted == true) { PassphraseField( currentKey, - generalGetString(R.string.current_passphrase), + generalGetString(MR.strings.current_passphrase), modifier = Modifier.padding(horizontal = DEFAULT_PADDING), isValid = ::validKey, keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), @@ -170,7 +171,7 @@ fun DatabaseEncryptionLayout( PassphraseField( newKey, - generalGetString(R.string.new_passphrase), + generalGetString(MR.strings.new_passphrase), modifier = Modifier.padding(horizontal = DEFAULT_PADDING), showStrength = true, isValid = ::validKey, @@ -201,7 +202,7 @@ fun DatabaseEncryptionLayout( PassphraseField( confirmNewKey, - generalGetString(R.string.confirm_new_passphrase), + generalGetString(MR.strings.confirm_new_passphrase), modifier = Modifier.padding(horizontal = DEFAULT_PADDING), isValid = { confirmNewKey.value == "" || newKey.value == confirmNewKey.value }, keyboardActions = KeyboardActions(onDone = { @@ -211,27 +212,27 @@ fun DatabaseEncryptionLayout( ) SectionItemViewSpaceBetween(onClickUpdate, disabled = disabled, minHeight = TextFieldDefaults.MinHeight) { - Text(generalGetString(R.string.update_database_passphrase), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(generalGetString(MR.strings.update_database_passphrase), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } } Column { if (chatDbEncrypted == false) { - SectionTextFooter(generalGetString(R.string.database_is_not_encrypted)) + SectionTextFooter(generalGetString(MR.strings.database_is_not_encrypted)) } else if (useKeychain.value) { if (storedKey.value) { - SectionTextFooter(generalGetString(R.string.keychain_is_storing_securely)) + SectionTextFooter(generalGetString(MR.strings.keychain_is_storing_securely)) if (initialRandomDBPassphrase.value) { - SectionTextFooter(generalGetString(R.string.encrypted_with_random_passphrase)) + SectionTextFooter(generalGetString(MR.strings.encrypted_with_random_passphrase)) } else { - SectionTextFooter(generalGetString(R.string.impossible_to_recover_passphrase)) + SectionTextFooter(generalGetString(MR.strings.impossible_to_recover_passphrase)) } } else { - SectionTextFooter(generalGetString(R.string.keychain_allows_to_receive_ntfs)) + SectionTextFooter(generalGetString(MR.strings.keychain_allows_to_receive_ntfs)) } } else { - SectionTextFooter(generalGetString(R.string.you_have_to_enter_passphrase_every_time)) - SectionTextFooter(generalGetString(R.string.impossible_to_recover_passphrase)) + SectionTextFooter(generalGetString(MR.strings.you_have_to_enter_passphrase_every_time)) + SectionTextFooter(generalGetString(MR.strings.impossible_to_recover_passphrase)) } } SectionBottomSpacer() @@ -240,9 +241,9 @@ fun DatabaseEncryptionLayout( fun encryptDatabaseSavedAlert(onConfirm: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.encrypt_database_question), - text = generalGetString(R.string.database_will_be_encrypted_and_passphrase_stored) + "\n" + storeSecurelySaved(), - confirmText = generalGetString(R.string.encrypt_database), + title = generalGetString(MR.strings.encrypt_database_question), + text = generalGetString(MR.strings.database_will_be_encrypted_and_passphrase_stored) + "\n" + storeSecurelySaved(), + confirmText = generalGetString(MR.strings.encrypt_database), onConfirm = onConfirm, destructive = true, ) @@ -250,9 +251,9 @@ fun encryptDatabaseSavedAlert(onConfirm: () -> Unit) { fun encryptDatabaseAlert(onConfirm: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.encrypt_database_question), - text = generalGetString(R.string.database_will_be_encrypted) +"\n" + storeSecurelyDanger(), - confirmText = generalGetString(R.string.encrypt_database), + title = generalGetString(MR.strings.encrypt_database_question), + text = generalGetString(MR.strings.database_will_be_encrypted) +"\n" + storeSecurelyDanger(), + confirmText = generalGetString(MR.strings.encrypt_database), onConfirm = onConfirm, destructive = true, ) @@ -260,9 +261,9 @@ fun encryptDatabaseAlert(onConfirm: () -> Unit) { fun changeDatabaseKeySavedAlert(onConfirm: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.change_database_passphrase_question), - text = generalGetString(R.string.database_encryption_will_be_updated) + "\n" + storeSecurelySaved(), - confirmText = generalGetString(R.string.update_database), + title = generalGetString(MR.strings.change_database_passphrase_question), + text = generalGetString(MR.strings.database_encryption_will_be_updated) + "\n" + storeSecurelySaved(), + confirmText = generalGetString(MR.strings.update_database), onConfirm = onConfirm, destructive = false, ) @@ -270,9 +271,9 @@ fun changeDatabaseKeySavedAlert(onConfirm: () -> Unit) { fun changeDatabaseKeyAlert(onConfirm: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.change_database_passphrase_question), - text = generalGetString(R.string.database_passphrase_will_be_updated) + "\n" + storeSecurelyDanger(), - confirmText = generalGetString(R.string.update_database), + title = generalGetString(MR.strings.change_database_passphrase_question), + text = generalGetString(MR.strings.database_passphrase_will_be_updated) + "\n" + storeSecurelyDanger(), + confirmText = generalGetString(MR.strings.update_database), onConfirm = onConfirm, destructive = true, ) @@ -291,12 +292,12 @@ fun SavePassphraseSetting( Row(verticalAlignment = Alignment.CenterVertically) { Icon( if (storedKey) painterResource(R.drawable.ic_vpn_key_filled) else painterResource(R.drawable.ic_vpn_key_off_filled), - stringResource(R.string.save_passphrase_in_keychain), + stringResource(MR.strings.save_passphrase_in_keychain), tint = if (storedKey) SimplexGreen else MaterialTheme.colors.secondary ) Spacer(Modifier.padding(horizontal = 4.dp)) Text( - stringResource(R.string.save_passphrase_in_keychain), + stringResource(MR.strings.save_passphrase_in_keychain), Modifier.padding(end = 24.dp), color = Color.Unspecified ) @@ -333,9 +334,9 @@ fun setUseKeychain(value: Boolean, useKeychain: MutableState, prefs: Ap prefs.storeDBPassphrase.set(value) } -fun storeSecurelySaved() = generalGetString(R.string.store_passphrase_securely) +fun storeSecurelySaved() = generalGetString(MR.strings.store_passphrase_securely) -fun storeSecurelyDanger() = generalGetString(R.string.store_passphrase_securely_without_recover) +fun storeSecurelyDanger() = generalGetString(MR.strings.store_passphrase_securely_without_recover) private fun operationEnded(m: ChatModel, progressIndicator: MutableState, alert: () -> Unit) { m.chatDbChanged.value = true diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseErrorView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseErrorView.kt index a8192e3d89..1dd06cbc78 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseErrorView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseErrorView.kt @@ -5,7 +5,6 @@ import SectionSpacer import SectionView import android.content.Context import android.util.Log -import androidx.annotation.StringRes import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardActions @@ -25,6 +24,8 @@ import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.AppVersionText import chat.simplex.app.views.usersettings.NotificationsMode +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource import kotlinx.coroutines.* import kotlinx.datetime.Clock import java.io.File @@ -59,7 +60,7 @@ fun DatabaseErrorView( } @Composable - fun DatabaseErrorDetails(@StringRes title: Int, content: @Composable ColumnScope.() -> Unit) { + fun DatabaseErrorDetails(title: StringResource, content: @Composable ColumnScope.() -> Unit) { Text( generalGetString(title), Modifier.padding(start = DEFAULT_PADDING, top = DEFAULT_PADDING, bottom = DEFAULT_PADDING), @@ -70,12 +71,12 @@ fun DatabaseErrorView( @Composable fun FileNameText(dbFile: String) { - Text(String.format(generalGetString(R.string.file_with_path), dbFile.split("/").lastOrNull() ?: dbFile)) + Text(String.format(generalGetString(MR.strings.file_with_path), dbFile.split("/").lastOrNull() ?: dbFile)) } @Composable fun MigrationsText(ms: List) { - Text(String.format(generalGetString(R.string.database_migrations), ms.joinToString(", "))) + Text(String.format(generalGetString(MR.strings.database_migrations), ms.joinToString(", "))) } Column( @@ -86,8 +87,8 @@ fun DatabaseErrorView( when (val status = chatDbStatus.value) { is DBMigrationResult.ErrorNotADatabase -> if (useKeychain && !storedDBKey.isNullOrEmpty()) { - DatabaseErrorDetails(R.string.wrong_passphrase) { - Text(generalGetString(R.string.passphrase_is_different)) + DatabaseErrorDetails(MR.strings.wrong_passphrase) { + Text(generalGetString(MR.strings.passphrase_is_different)) DatabaseKeyField(dbKey, buttonEnabled) { saveAndRunChatOnClick() } @@ -96,8 +97,8 @@ fun DatabaseErrorView( FileNameText(status.dbFile) } } else { - DatabaseErrorDetails(R.string.encrypted_database) { - Text(generalGetString(R.string.database_passphrase_is_required)) + DatabaseErrorDetails(MR.strings.encrypted_database) { + Text(generalGetString(MR.strings.database_passphrase_is_required)) if (useKeychain) { DatabaseKeyField(dbKey, buttonEnabled, ::saveAndRunChatOnClick) SaveAndOpenButton(buttonEnabled, ::saveAndRunChatOnClick) @@ -109,9 +110,9 @@ fun DatabaseErrorView( } is DBMigrationResult.ErrorMigration -> when (val err = status.migrationError) { is MigrationError.Upgrade -> - DatabaseErrorDetails(R.string.database_upgrade) { + DatabaseErrorDetails(MR.strings.database_upgrade) { TextButton({ callRunChat(confirmMigrations = MigrationConfirmation.YesUp) }, Modifier.align(Alignment.CenterHorizontally), enabled = !progressIndicator.value) { - Text(generalGetString(R.string.upgrade_and_open_chat)) + Text(generalGetString(MR.strings.upgrade_and_open_chat)) } Spacer(Modifier.height(20.dp)) FileNameText(status.dbFile) @@ -119,51 +120,51 @@ fun DatabaseErrorView( AppVersionText() } is MigrationError.Downgrade -> - DatabaseErrorDetails(R.string.database_downgrade) { + DatabaseErrorDetails(MR.strings.database_downgrade) { TextButton({ callRunChat(confirmMigrations = MigrationConfirmation.YesUpDown) }, Modifier.align(Alignment.CenterHorizontally), enabled = !progressIndicator.value) { - Text(generalGetString(R.string.downgrade_and_open_chat)) + Text(generalGetString(MR.strings.downgrade_and_open_chat)) } Spacer(Modifier.height(20.dp)) - Text(generalGetString(R.string.database_downgrade_warning), fontWeight = FontWeight.Bold) + Text(generalGetString(MR.strings.database_downgrade_warning), fontWeight = FontWeight.Bold) FileNameText(status.dbFile) MigrationsText(err.downMigrations) AppVersionText() } is MigrationError.Error -> - DatabaseErrorDetails(R.string.incompatible_database_version) { + DatabaseErrorDetails(MR.strings.incompatible_database_version) { FileNameText(status.dbFile) - Text(String.format(generalGetString(R.string.error_with_info), mtrErrorDescription(err.mtrError))) + Text(String.format(generalGetString(MR.strings.error_with_info), mtrErrorDescription(err.mtrError))) } } is DBMigrationResult.ErrorSQL -> - DatabaseErrorDetails(R.string.database_error) { + DatabaseErrorDetails(MR.strings.database_error) { FileNameText(status.dbFile) - Text(String.format(generalGetString(R.string.error_with_info), status.migrationSQLError)) + Text(String.format(generalGetString(MR.strings.error_with_info), status.migrationSQLError)) } is DBMigrationResult.ErrorKeychain -> - DatabaseErrorDetails(R.string.keychain_error) { - Text(generalGetString(R.string.cannot_access_keychain)) + DatabaseErrorDetails(MR.strings.keychain_error) { + Text(generalGetString(MR.strings.cannot_access_keychain)) } is DBMigrationResult.InvalidConfirmation -> - DatabaseErrorDetails(R.string.invalid_migration_confirmation) { + DatabaseErrorDetails(MR.strings.invalid_migration_confirmation) { // this can only happen if incorrect parameter is passed } is DBMigrationResult.Unknown -> - DatabaseErrorDetails(R.string.database_error) { - Text(String.format(generalGetString(R.string.unknown_database_error_with_info), status.json)) + DatabaseErrorDetails(MR.strings.database_error) { + Text(String.format(generalGetString(MR.strings.unknown_database_error_with_info), status.json)) } is DBMigrationResult.OK -> {} null -> {} } if (restoreDbFromBackup.value) { SectionSpacer() - Text(generalGetString(R.string.database_backup_can_be_restored)) + Text(generalGetString(MR.strings.database_backup_can_be_restored)) Spacer(Modifier.size(DEFAULT_PADDING)) RestoreDbButton { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.restore_database_alert_title), - text = generalGetString(R.string.restore_database_alert_desc), - confirmText = generalGetString(R.string.restore_database_alert_confirm), + title = generalGetString(MR.strings.restore_database_alert_title), + text = generalGetString(MR.strings.restore_database_alert_desc), + confirmText = generalGetString(MR.strings.restore_database_alert_confirm), onConfirm = { restoreDb(restoreDbFromBackup, appPreferences) }, destructive = true, ) @@ -212,15 +213,15 @@ private fun runChat( } } is DBMigrationResult.ErrorNotADatabase -> - AlertManager.shared.showAlertMsg(generalGetString(R.string.wrong_passphrase_title), generalGetString(R.string.enter_correct_passphrase)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.wrong_passphrase_title), generalGetString(MR.strings.enter_correct_passphrase)) is DBMigrationResult.ErrorSQL -> - AlertManager.shared.showAlertMsg(generalGetString(R.string.database_error), status.migrationSQLError) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.database_error), status.migrationSQLError) is DBMigrationResult.ErrorKeychain -> - AlertManager.shared.showAlertMsg(generalGetString(R.string.keychain_error)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.keychain_error)) is DBMigrationResult.Unknown -> - AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), status.json) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), status.json) is DBMigrationResult.InvalidConfirmation -> - AlertManager.shared.showAlertMsg(generalGetString(R.string.invalid_migration_confirmation)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.invalid_migration_confirmation)) is DBMigrationResult.ErrorMigration -> {} null -> {} } @@ -249,23 +250,23 @@ private fun restoreDb(restoreDbFromBackup: MutableState, prefs: AppPref restoreDbFromBackup.value = false prefs.encryptionStartedAt.set(null) } catch (e: Exception) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.database_restore_error), e.stackTraceToString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.database_restore_error), e.stackTraceToString()) } } private fun mtrErrorDescription(err: MTRError): String = when (err) { is MTRError.NoDown -> - String.format(generalGetString(R.string.mtr_error_no_down_migration), err.dbMigrations.joinToString(", ")) + String.format(generalGetString(MR.strings.mtr_error_no_down_migration), err.dbMigrations.joinToString(", ")) is MTRError.Different -> - String.format(generalGetString(R.string.mtr_error_different), err.appMigration, err.dbMigration) + String.format(generalGetString(MR.strings.mtr_error_different), err.appMigration, err.dbMigration) } @Composable private fun DatabaseKeyField(text: MutableState, enabled: Boolean, onClick: (() -> Unit)? = null) { PassphraseField( text, - generalGetString(R.string.enter_passphrase), + generalGetString(MR.strings.enter_passphrase), isValid = ::validKey, keyboardActions = KeyboardActions(onDone = if (enabled) { { onClick?.invoke() } @@ -277,21 +278,21 @@ private fun DatabaseKeyField(text: MutableState, enabled: Boolean, onCli @Composable private fun ColumnScope.SaveAndOpenButton(enabled: Boolean, onClick: () -> Unit) { TextButton(onClick, Modifier.align(Alignment.CenterHorizontally), enabled = enabled) { - Text(generalGetString(R.string.save_passphrase_and_open_chat)) + Text(generalGetString(MR.strings.save_passphrase_and_open_chat)) } } @Composable private fun ColumnScope.OpenChatButton(enabled: Boolean, onClick: () -> Unit) { TextButton(onClick, Modifier.align(Alignment.CenterHorizontally), enabled = enabled) { - Text(generalGetString(R.string.open_chat)) + Text(generalGetString(MR.strings.open_chat)) } } @Composable private fun ColumnScope.RestoreDbButton(onClick: () -> Unit) { TextButton(onClick, Modifier.align(Alignment.CenterHorizontally)) { - Text(generalGetString(R.string.restore_database), color = MaterialTheme.colors.error) + Text(generalGetString(MR.strings.restore_database), color = MaterialTheme.colors.error) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseView.kt index 41b19cb60c..89e685d8c4 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/database/DatabaseView.kt @@ -23,7 +23,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview @@ -35,6 +35,7 @@ import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.* +import chat.simplex.res.MR import kotlinx.coroutines.* import kotlinx.datetime.* import org.apache.commons.io.IOUtils @@ -151,15 +152,15 @@ fun DatabaseLayout( Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.your_chat_database)) + AppBarTitle(stringResource(MR.strings.your_chat_database)) - SectionView(stringResource(R.string.messages_section_title).uppercase()) { + SectionView(stringResource(MR.strings.messages_section_title).uppercase()) { TtlOptions(chatItemTTL, enabled = rememberUpdatedState(!stopped && !progressIndicator), onChatItemTTLSelected) } SectionTextFooter( remember(currentUser?.displayName) { buildAnnotatedString { - append(generalGetString(R.string.messages_section_description) + " ") + append(generalGetString(MR.strings.messages_section_description) + " ") withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append(currentUser?.displayName ?: "") } @@ -169,17 +170,17 @@ fun DatabaseLayout( ) SectionDividerSpaced(maxTopPadding = true) - SectionView(stringResource(R.string.run_chat_section)) { + SectionView(stringResource(MR.strings.run_chat_section)) { RunChatSetting(runChat, stopped, startChat, stopChatAlert) } SectionDividerSpaced() - SectionView(stringResource(R.string.chat_database_section)) { + SectionView(stringResource(MR.strings.chat_database_section)) { val unencrypted = chatDbEncrypted == false SettingsActionItem( if (unencrypted) painterResource(R.drawable.ic_lock_open) else if (useKeyChain) painterResource(R.drawable.ic_vpn_key_filled) else painterResource(R.drawable.ic_lock), - stringResource(R.string.database_passphrase), + stringResource(MR.strings.database_passphrase), click = showSettingsModal() { DatabaseEncryptionView(it) }, iconColor = if (unencrypted) WarningOrange else MaterialTheme.colors.secondary, disabled = operationsDisabled @@ -188,7 +189,7 @@ fun DatabaseLayout( SectionDividerSpaced(maxBottomPadding = false) SettingsActionItem( painterResource(R.drawable.ic_ios_share), - stringResource(R.string.export_database), + stringResource(MR.strings.export_database), click = { if (initialRandomDBPassphrase.get()) { exportProhibitedAlert() @@ -202,7 +203,7 @@ fun DatabaseLayout( ) SettingsActionItem( painterResource(R.drawable.ic_download), - stringResource(R.string.import_database), + stringResource(MR.strings.import_database), { importArchiveLauncher.launch("application/zip") }, textColor = Color.Red, iconColor = Color.Red, @@ -222,7 +223,7 @@ fun DatabaseLayout( } SettingsActionItem( painterResource(R.drawable.ic_delete_forever), - stringResource(R.string.delete_database), + stringResource(MR.strings.delete_database), deleteChatAlert, textColor = Color.Red, iconColor = Color.Red, @@ -231,21 +232,21 @@ fun DatabaseLayout( } SectionTextFooter( if (stopped) { - stringResource(R.string.you_must_use_the_most_recent_version_of_database) + stringResource(MR.strings.you_must_use_the_most_recent_version_of_database) } else { - stringResource(R.string.stop_chat_to_enable_database_actions) + stringResource(MR.strings.stop_chat_to_enable_database_actions) } ) SectionDividerSpaced(maxTopPadding = true) - SectionView(stringResource(R.string.files_and_media_section).uppercase()) { + SectionView(stringResource(MR.strings.files_and_media_section).uppercase()) { val deleteFilesDisabled = operationsDisabled || appFilesCountAndSize.value.first == 0 SectionItemView( deleteAppFilesAndMedia, disabled = deleteFilesDisabled ) { Text( - stringResource(if (users.size > 1) R.string.delete_files_and_media_for_all_users else R.string.delete_files_and_media_all), + stringResource(if (users.size > 1) MR.strings.delete_files_and_media_for_all_users else MR.strings.delete_files_and_media_all), color = if (deleteFilesDisabled) MaterialTheme.colors.secondary else Color.Red ) } @@ -253,9 +254,9 @@ fun DatabaseLayout( val (count, size) = appFilesCountAndSize.value SectionTextFooter( if (count == 0) { - stringResource(R.string.no_received_app_files) + stringResource(MR.strings.no_received_app_files) } else { - String.format(stringResource(R.string.total_files_count_and_size), count, formatBytes(size)) + String.format(stringResource(MR.strings.total_files_count_and_size), count, formatBytes(size)) } ) SectionBottomSpacer() @@ -268,7 +269,7 @@ private fun AppDataBackupPreference(privacyFullBackup: SharedPreference painterResource(R.drawable.ic_backup), iconColor = MaterialTheme.colors.secondary, pref = privacyFullBackup, - text = stringResource(R.string.full_backup) + text = stringResource(MR.strings.full_backup) ) { if (initialRandomDBPassphrase.get()) { exportProhibitedAlert() @@ -285,9 +286,9 @@ private fun setChatItemTTLAlert( appFilesCountAndSize: MutableState>, ) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.enable_automatic_deletion_question), - text = generalGetString(R.string.enable_automatic_deletion_message), - confirmText = generalGetString(R.string.delete_messages), + title = generalGetString(MR.strings.enable_automatic_deletion_question), + text = generalGetString(MR.strings.enable_automatic_deletion_message), + confirmText = generalGetString(MR.strings.delete_messages), onConfirm = { setCiTTL(m, selectedChatItemTTL, progressIndicator, appFilesCountAndSize) }, onDismiss = { selectedChatItemTTL.value = m.chatItemTTL.value }, destructive = true, @@ -303,16 +304,16 @@ private fun TtlOptions(current: State, enabled: State, onS } all.map { when (it) { - is ChatItemTTL.None -> it to generalGetString(R.string.chat_item_ttl_none) - is ChatItemTTL.Day -> it to generalGetString(R.string.chat_item_ttl_day) - is ChatItemTTL.Week -> it to generalGetString(R.string.chat_item_ttl_week) - is ChatItemTTL.Month -> it to generalGetString(R.string.chat_item_ttl_month) - is ChatItemTTL.Seconds -> it to String.format(generalGetString(R.string.chat_item_ttl_seconds), it.secs) + is ChatItemTTL.None -> it to generalGetString(MR.strings.chat_item_ttl_none) + is ChatItemTTL.Day -> it to generalGetString(MR.strings.chat_item_ttl_day) + is ChatItemTTL.Week -> it to generalGetString(MR.strings.chat_item_ttl_week) + is ChatItemTTL.Month -> it to generalGetString(MR.strings.chat_item_ttl_month) + is ChatItemTTL.Seconds -> it to String.format(generalGetString(MR.strings.chat_item_ttl_seconds), it.secs) } } } ExposedDropDownSettingRow( - generalGetString(R.string.delete_messages_after), + generalGetString(MR.strings.delete_messages_after), values, current, icon = null, @@ -328,7 +329,7 @@ fun RunChatSetting( startChat: () -> Unit, stopChatAlert: () -> Unit ) { - val chatRunningText = if (stopped) stringResource(R.string.chat_is_stopped) else stringResource(R.string.chat_is_running) + val chatRunningText = if (stopped) stringResource(MR.strings.chat_is_stopped) else stringResource(MR.strings.chat_is_running) SettingsActionItemWithContent( icon = if (stopped) painterResource(R.drawable.ic_report_filled) else painterResource(R.drawable.ic_play_arrow_filled), text = chatRunningText, @@ -349,7 +350,7 @@ fun RunChatSetting( @Composable fun chatArchiveTitle(chatArchiveTime: Instant, chatLastStart: Instant): String { - return stringResource(if (chatArchiveTime < chatLastStart) R.string.old_database_archive else R.string.new_database_archive) + return stringResource(if (chatArchiveTime < chatLastStart) MR.strings.old_database_archive else MR.strings.new_database_archive) } private fun startChat(m: ChatModel, runChat: MutableState, chatLastStart: MutableState, chatDbChanged: MutableState) { @@ -381,16 +382,16 @@ private fun startChat(m: ChatModel, runChat: MutableState, chatLastSta } } catch (e: Error) { runChat.value = false - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_starting_chat), e.toString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_starting_chat), e.toString()) } } } private fun stopChatAlert(m: ChatModel, runChat: MutableState) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.stop_chat_question), - text = generalGetString(R.string.stop_chat_to_export_import_or_delete_chat_database), - confirmText = generalGetString(R.string.stop_chat_confirmation), + title = generalGetString(MR.strings.stop_chat_question), + text = generalGetString(MR.strings.stop_chat_to_export_import_or_delete_chat_database), + confirmText = generalGetString(MR.strings.stop_chat_confirmation), onConfirm = { authStopChat(m, runChat) }, onDismiss = { runChat.value = true } ) @@ -398,16 +399,16 @@ private fun stopChatAlert(m: ChatModel, runChat: MutableState) { private fun exportProhibitedAlert() { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.set_password_to_export), - text = generalGetString(R.string.set_password_to_export_desc), + title = generalGetString(MR.strings.set_password_to_export), + text = generalGetString(MR.strings.set_password_to_export_desc), ) } private fun authStopChat(m: ChatModel, runChat: MutableState) { if (m.controller.appPrefs.performLA.get()) { authenticate( - generalGetString(R.string.auth_stop_chat), - generalGetString(R.string.auth_log_in_using_credential), + generalGetString(MR.strings.auth_stop_chat), + generalGetString(MR.strings.auth_log_in_using_credential), completed = { laResult -> when (laResult) { LAResult.Success, is LAResult.Unavailable -> { @@ -436,7 +437,7 @@ private fun stopChat(m: ChatModel, runChat: MutableState) { MessagesFetcherWorker.cancelAll() } catch (e: Error) { runChat.value = true - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_stopping_chat), e.toString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_stopping_chat), e.toString()) } } } @@ -468,7 +469,7 @@ private fun exportArchive( saveArchiveLauncher.launch(archiveFile.substringAfterLast("/")) progressIndicator.value = false } catch (e: Error) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_exporting_chat_database), e.toString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_exporting_chat_database), e.toString()) progressIndicator.value = false } } @@ -524,14 +525,14 @@ private fun rememberSaveArchiveLauncher(chatArchiveFile: MutableState): val outputStream = BufferedOutputStream(stream) File(filePath).inputStream().use { it.copyTo(outputStream) } outputStream.close() - Toast.makeText(cxt, generalGetString(R.string.file_saved), Toast.LENGTH_SHORT).show() + Toast.makeText(cxt, generalGetString(MR.strings.file_saved), Toast.LENGTH_SHORT).show() } } else { - Toast.makeText(cxt, generalGetString(R.string.file_not_found), Toast.LENGTH_SHORT).show() + Toast.makeText(cxt, generalGetString(MR.strings.file_not_found), Toast.LENGTH_SHORT).show() } } } catch (e: Error) { - Toast.makeText(cxt, generalGetString(R.string.error_saving_file), Toast.LENGTH_SHORT).show() + Toast.makeText(cxt, generalGetString(MR.strings.error_saving_file), Toast.LENGTH_SHORT).show() Log.e(TAG, "rememberSaveArchiveLauncher error saving archive $e") } finally { chatArchiveFile.value = null @@ -546,9 +547,9 @@ private fun importArchiveAlert( progressIndicator: MutableState ) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.import_database_question), - text = generalGetString(R.string.your_current_chat_database_will_be_deleted_and_replaced_with_the_imported_one), - confirmText = generalGetString(R.string.import_database_confirmation), + title = generalGetString(MR.strings.import_database_question), + text = generalGetString(MR.strings.your_current_chat_database_will_be_deleted_and_replaced_with_the_imported_one), + confirmText = generalGetString(MR.strings.import_database_confirmation), onConfirm = { importArchive(m, importedArchiveUri, appFilesCountAndSize, progressIndicator) }, destructive = true, ) @@ -573,21 +574,21 @@ private fun importArchive( appFilesCountAndSize.value = directoryFileCountAndSize(getAppFilesDirectory()) if (archiveErrors.isEmpty()) { operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_imported), text = generalGetString(R.string.restart_the_app_to_use_imported_chat_database)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_imported), text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database)) } } else { operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_imported), text = generalGetString(R.string.restart_the_app_to_use_imported_chat_database) + "\n" + generalGetString(R.string.non_fatal_errors_occured_during_import)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_imported), text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database) + "\n" + generalGetString(MR.strings.non_fatal_errors_occured_during_import)) } } } catch (e: Error) { operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_importing_database), e.toString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_importing_database), e.toString()) } } } catch (e: Error) { operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_deleting_database), e.toString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_deleting_database), e.toString()) } } finally { File(archivePath).delete() @@ -617,9 +618,9 @@ private fun saveArchiveFromUri(importedArchiveUri: Uri): String? { private fun deleteChatAlert(m: ChatModel, progressIndicator: MutableState) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_chat_profile_question), - text = generalGetString(R.string.delete_chat_profile_action_cannot_be_undone_warning), - confirmText = generalGetString(R.string.delete_verb), + title = generalGetString(MR.strings.delete_chat_profile_question), + text = generalGetString(MR.strings.delete_chat_profile_action_cannot_be_undone_warning), + confirmText = generalGetString(MR.strings.delete_verb), onConfirm = { deleteChat(m, progressIndicator) }, destructive = true, ) @@ -631,11 +632,11 @@ private fun deleteChat(m: ChatModel, progressIndicator: MutableState) { try { deleteChatAsync(m) operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_deleted), generalGetString(R.string.restart_the_app_to_create_a_new_chat_profile)) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_deleted), generalGetString(MR.strings.restart_the_app_to_create_a_new_chat_profile)) } } catch (e: Error) { operationEnded(m, progressIndicator) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_deleting_database), e.toString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_deleting_database), e.toString()) } } } @@ -659,7 +660,7 @@ private fun setCiTTL( // Rollback to model's value chatItemTTL.value = m.chatItemTTL.value afterSetCiTTL(m, progressIndicator, appFilesCountAndSize) - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_changing_message_deletion), e.stackTraceToString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_changing_message_deletion), e.stackTraceToString()) } } } @@ -683,9 +684,9 @@ private fun afterSetCiTTL( private fun deleteFilesAndMediaAlert(appFilesCountAndSize: MutableState>) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_files_and_media_question), - text = generalGetString(R.string.delete_files_and_media_desc), - confirmText = generalGetString(R.string.delete_verb), + title = generalGetString(MR.strings.delete_files_and_media_question), + text = generalGetString(MR.strings.delete_files_and_media_desc), + confirmText = generalGetString(MR.strings.delete_verb), onConfirm = { deleteFiles(appFilesCountAndSize) }, destructive = true ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt index f4895c22ce..9295fcd46e 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/AlertManager.kt @@ -17,6 +17,8 @@ import androidx.compose.ui.window.Dialog import chat.simplex.app.R import chat.simplex.app.TAG import chat.simplex.app.ui.theme.* +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource class AlertManager { var alertViews = mutableStateListOf<(@Composable () -> Unit)>() @@ -78,9 +80,9 @@ class AlertManager { fun showAlertDialog( title: String, text: String? = null, - confirmText: String = generalGetString(R.string.ok), + confirmText: String = generalGetString(MR.strings.ok), onConfirm: (() -> Unit)? = null, - dismissText: String = generalGetString(R.string.cancel_verb), + dismissText: String = generalGetString(MR.strings.cancel_verb), onDismiss: (() -> Unit)? = null, onDismissRequest: (() -> Unit)? = null, destructive: Boolean = false @@ -113,9 +115,9 @@ class AlertManager { fun showAlertDialogStacked( title: String, text: String? = null, - confirmText: String = generalGetString(R.string.ok), + confirmText: String = generalGetString(MR.strings.ok), onConfirm: (() -> Unit)? = null, - dismissText: String = generalGetString(R.string.cancel_verb), + dismissText: String = generalGetString(MR.strings.cancel_verb), onDismiss: (() -> Unit)? = null, onDismissRequest: (() -> Unit)? = null, destructive: Boolean = false @@ -147,7 +149,7 @@ class AlertManager { fun showAlertMsg( title: String, text: String? = null, - confirmText: String = generalGetString(R.string.ok) + confirmText: String = generalGetString(MR.strings.ok) ) { showAlert { AlertDialog( @@ -169,9 +171,9 @@ class AlertManager { } } fun showAlertMsg( - title: Int, - text: Int? = null, - confirmText: Int = R.string.ok, + title: StringResource, + text: StringResource? = null, + confirmText: StringResource = MR.strings.ok, ) = showAlertMsg(generalGetString(title), if (text != null) generalGetString(text) else null, generalGetString(confirmText)) @Composable diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ChatInfoImage.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ChatInfoImage.kt index d8463d94a7..e5c03f654e 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ChatInfoImage.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ChatInfoImage.kt @@ -11,13 +11,14 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.* import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.ChatInfo import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.res.MR @Composable fun ChatInfoImage(chatInfo: ChatInfo, size: Dp, iconColor: Color = MaterialTheme.colors.secondaryVariant) { @@ -31,7 +32,7 @@ fun ChatInfoImage(chatInfo: ChatInfo, size: Dp, iconColor: Color = MaterialTheme fun IncognitoImage(size: Dp, iconColor: Color = MaterialTheme.colors.secondaryVariant) { Box(Modifier.size(size)) { Icon( - painterResource(R.drawable.ic_theater_comedy_filled), stringResource(R.string.incognito), + painterResource(R.drawable.ic_theater_comedy_filled), stringResource(MR.strings.incognito), modifier = Modifier.size(size).padding(size / 12), iconColor ) @@ -55,14 +56,14 @@ fun ProfileImage( if (iconToReplace != null) { Icon( iconToReplace, - contentDescription = stringResource(R.string.icon_descr_profile_image_placeholder), + contentDescription = stringResource(MR.strings.icon_descr_profile_image_placeholder), tint = color, modifier = Modifier.fillMaxSize() ) } else { Icon( painterResource(icon), - contentDescription = stringResource(R.string.icon_descr_profile_image_placeholder), + contentDescription = stringResource(MR.strings.icon_descr_profile_image_placeholder), tint = color, modifier = Modifier.fillMaxSize() ) @@ -71,7 +72,7 @@ fun ProfileImage( val imageBitmap = base64ToBitmap(image).asImageBitmap() Image( imageBitmap, - stringResource(R.string.image_descr_profile_image), + stringResource(MR.strings.image_descr_profile_image), contentScale = ContentScale.Crop, modifier = Modifier.size(size).padding(size / 12).clip(CircleShape) ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ChooseAttachmentView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ChooseAttachmentView.kt index 5ca600a0b3..edbee83186 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ChooseAttachmentView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ChooseAttachmentView.kt @@ -9,10 +9,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.views.newchat.ActionButton +import chat.simplex.res.MR sealed class AttachmentOption { object CameraPhoto: AttachmentOption() @@ -40,19 +41,19 @@ fun ChooseAttachmentView( .padding(horizontal = 8.dp, vertical = 30.dp), horizontalArrangement = Arrangement.SpaceEvenly ) { - ActionButton(Modifier.fillMaxWidth(0.25f), null, stringResource(R.string.use_camera_button), icon = painterResource(R.drawable.ic_camera_enhance)) { + ActionButton(Modifier.fillMaxWidth(0.25f), null, stringResource(MR.strings.use_camera_button), icon = painterResource(R.drawable.ic_camera_enhance)) { attachmentOption.value = AttachmentOption.CameraPhoto hide() } - ActionButton(Modifier.fillMaxWidth(0.33f), null, stringResource(R.string.gallery_image_button), icon = painterResource(R.drawable.ic_add_photo)) { + ActionButton(Modifier.fillMaxWidth(0.33f), null, stringResource(MR.strings.gallery_image_button), icon = painterResource(R.drawable.ic_add_photo)) { attachmentOption.value = AttachmentOption.GalleryImage hide() } - ActionButton(Modifier.fillMaxWidth(0.50f), null, stringResource(R.string.gallery_video_button), icon = painterResource(R.drawable.ic_smart_display)) { + ActionButton(Modifier.fillMaxWidth(0.50f), null, stringResource(MR.strings.gallery_video_button), icon = painterResource(R.drawable.ic_smart_display)) { attachmentOption.value = AttachmentOption.GalleryVideo hide() } - ActionButton(Modifier.fillMaxWidth(1f), null, stringResource(R.string.choose_file), icon = painterResource(R.drawable.ic_note_add)) { + ActionButton(Modifier.fillMaxWidth(1f), null, stringResource(MR.strings.choose_file), icon = painterResource(R.drawable.ic_note_add)) { attachmentOption.value = AttachmentOption.File hide() } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/CustomTimePicker.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/CustomTimePicker.kt index 97a72dfe6f..c659353082 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/CustomTimePicker.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/CustomTimePicker.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.window.Dialog import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.DEFAULT_PADDING +import chat.simplex.res.MR import com.sd.lib.compose.wheel_picker.* @Composable @@ -174,7 +175,7 @@ fun CustomTimePickerDialog( ) Icon( painterResource(R.drawable.ic_close), - generalGetString(R.string.icon_descr_close_button), + generalGetString(MR.strings.icon_descr_close_button), tint = MaterialTheme.colors.secondary, modifier = Modifier .size(25.dp) @@ -238,7 +239,7 @@ fun DropdownCustomTimePickerSettingRow( values.value.map { sel: DropdownSelection -> when (sel) { is DropdownSelection.DropdownValue -> sel to timeText(sel.value) - DropdownSelection.Custom -> sel to generalGetString(R.string.custom_time_picker_custom) + DropdownSelection.Custom -> sel to generalGetString(MR.strings.custom_time_picker_custom) } }, dropdownSelection, diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt index 81cad18f5c..ad2465acc7 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/DefaultTopAppBar.kt @@ -9,9 +9,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.* import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.ui.theme.* +import chat.simplex.res.MR @Composable fun DefaultTopAppBar( @@ -47,7 +48,7 @@ fun DefaultTopAppBar( fun NavigationButtonBack(onButtonClicked: (() -> Unit)?) { IconButton(onButtonClicked ?: {}, enabled = onButtonClicked != null) { Icon( - painterResource(R.drawable.ic_arrow_back_ios_new), stringResource(R.string.back), tint = if (onButtonClicked != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary + painterResource(R.drawable.ic_arrow_back_ios_new), stringResource(MR.strings.back), tint = if (onButtonClicked != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary ) } } @@ -56,7 +57,7 @@ fun NavigationButtonBack(onButtonClicked: (() -> Unit)?) { fun ShareButton(onButtonClicked: () -> Unit) { IconButton(onButtonClicked) { Icon( - painterResource(R.drawable.ic_share), stringResource(R.string.share_verb), tint = MaterialTheme.colors.primary + painterResource(R.drawable.ic_share), stringResource(MR.strings.share_verb), tint = MaterialTheme.colors.primary ) } } @@ -66,7 +67,7 @@ fun NavigationButtonMenu(onButtonClicked: () -> Unit) { IconButton(onClick = onButtonClicked) { Icon( painterResource(R.drawable.ic_menu), - stringResource(R.string.icon_descr_settings), + stringResource(MR.strings.icon_descr_settings), tint = MaterialTheme.colors.primary, ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ExposedDropDownSettingRow.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ExposedDropDownSettingRow.kt index b39b36e365..9f06a9affd 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ExposedDropDownSettingRow.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ExposedDropDownSettingRow.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.ui.theme.* import chat.simplex.app.views.usersettings.SettingsActionItemWithContent +import chat.simplex.res.MR @Composable fun ExposedDropDownSettingRow( @@ -51,7 +52,7 @@ fun ExposedDropDownSettingRow( Spacer(Modifier.size(12.dp)) Icon( if (!expanded.value) painterResource(R.drawable.ic_expand_more) else painterResource(R.drawable.ic_expand_less), - generalGetString(R.string.icon_descr_more_button), + generalGetString(MR.strings.icon_descr_more_button), tint = MaterialTheme.colors.secondary ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt index 0ea74b4b5f..d35c24817d 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt @@ -24,7 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat import androidx.core.content.FileProvider @@ -33,6 +33,7 @@ import chat.simplex.app.R import chat.simplex.app.model.json import chat.simplex.app.views.chat.PickFromGallery import chat.simplex.app.views.newchat.ActionButton +import chat.simplex.res.MR import kotlinx.serialization.builtins.* import java.io.ByteArrayOutputStream import java.io.File @@ -228,7 +229,7 @@ fun GetImageBottomSheet( cameraLauncher.launchWithFallback() hideBottomSheet() } else { - Toast.makeText(context, generalGetString(R.string.toast_permission_denied), Toast.LENGTH_SHORT).show() + Toast.makeText(context, generalGetString(MR.strings.toast_permission_denied), Toast.LENGTH_SHORT).show() } } @@ -246,7 +247,7 @@ fun GetImageBottomSheet( .padding(horizontal = 8.dp, vertical = 30.dp), horizontalArrangement = Arrangement.SpaceEvenly ) { - ActionButton(null, stringResource(R.string.use_camera_button), icon = painterResource(R.drawable.ic_photo_camera)) { + ActionButton(null, stringResource(MR.strings.use_camera_button), icon = painterResource(R.drawable.ic_photo_camera)) { when (PackageManager.PERMISSION_GRANTED) { ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) -> { cameraLauncher.launchWithFallback() @@ -257,7 +258,7 @@ fun GetImageBottomSheet( } } } - ActionButton(null, stringResource(R.string.from_gallery_button), icon = painterResource(R.drawable.ic_image)) { + ActionButton(null, stringResource(MR.strings.from_gallery_button), icon = painterResource(R.drawable.ic_image)) { try { galleryLauncher.launch(0) } catch (e: ActivityNotFoundException) { diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/LinkPreviews.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/LinkPreviews.kt index 8634f92831..e13dd83145 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/LinkPreviews.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/LinkPreviews.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -21,6 +21,7 @@ import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.LinkPreview import chat.simplex.app.ui.theme.* +import chat.simplex.res.MR import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.jsoup.Jsoup @@ -98,7 +99,7 @@ fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit, cancel val imageBitmap = base64ToBitmap(linkPreview.image).asImageBitmap() Image( imageBitmap, - stringResource(R.string.image_descr_link_preview), + stringResource(MR.strings.image_descr_link_preview), modifier = Modifier.width(80.dp).height(60.dp).padding(end = 8.dp) ) Column(Modifier.fillMaxWidth().weight(1F)) { @@ -113,7 +114,7 @@ fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit, cancel IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) { Icon( painterResource(R.drawable.ic_close), - contentDescription = stringResource(R.string.icon_descr_cancel_link_preview), + contentDescription = stringResource(MR.strings.icon_descr_cancel_link_preview), tint = MaterialTheme.colors.primary, modifier = Modifier.padding(10.dp) ) @@ -127,7 +128,7 @@ fun ChatItemLinkView(linkPreview: LinkPreview) { Column { Image( base64ToBitmap(linkPreview.image).asImageBitmap(), - stringResource(R.string.image_descr_link_preview), + stringResource(MR.strings.image_descr_link_preview), modifier = Modifier.fillMaxWidth(), contentScale = ContentScale.FillWidth, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/LocalAuthentication.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/LocalAuthentication.kt index ed406c32fd..b6edae0e8f 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/LocalAuthentication.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/LocalAuthentication.kt @@ -16,6 +16,7 @@ import chat.simplex.app.SimplexApp import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword import chat.simplex.app.views.localauth.LocalAuthView import chat.simplex.app.views.usersettings.LAMode +import chat.simplex.res.MR sealed class LAResult { object Success: LAResult() @@ -32,7 +33,7 @@ data class LocalAuthRequest ( val completed: (LAResult) -> Unit ) { companion object { - val sample = LocalAuthRequest(generalGetString(R.string.la_enter_app_passcode), generalGetString(R.string.la_authenticate), "", selfDestruct = false) { } + val sample = LocalAuthRequest(generalGetString(MR.strings.la_enter_app_passcode), generalGetString(MR.strings.la_authenticate), "", selfDestruct = false) { } } } @@ -54,11 +55,11 @@ fun authenticate( else -> completed(LAResult.Unavailable()) } LAMode.PASSCODE -> { - val password = ksAppPassword.get() ?: return completed(LAResult.Unavailable(generalGetString(R.string.la_no_app_password))) + val password = ksAppPassword.get() ?: return completed(LAResult.Unavailable(generalGetString(MR.strings.la_no_app_password))) ModalManager.shared.showPasscodeCustomModal { close -> BackHandler { close() - completed(LAResult.Error(generalGetString(R.string.authentication_cancelled))) + completed(LAResult.Error(generalGetString(MR.strings.authentication_cancelled))) } Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { LocalAuthView(SimplexApp.context.chatModel, LocalAuthRequest(promptTitle, promptSubtitle, password, selfDestruct && SimplexApp.context.chatModel.controller.appPrefs.selfDestruct.get()) { @@ -120,28 +121,28 @@ private fun authenticateWithBiometricManager( } fun laTurnedOnAlert() = AlertManager.shared.showAlertMsg( - generalGetString(R.string.auth_simplex_lock_turned_on), - generalGetString(R.string.auth_you_will_be_required_to_authenticate_when_you_start_or_resume) + generalGetString(MR.strings.auth_simplex_lock_turned_on), + generalGetString(MR.strings.auth_you_will_be_required_to_authenticate_when_you_start_or_resume) ) fun laPasscodeNotSetAlert() = AlertManager.shared.showAlertMsg( - generalGetString(R.string.lock_not_enabled), - generalGetString(R.string.you_can_turn_on_lock) + generalGetString(MR.strings.lock_not_enabled), + generalGetString(MR.strings.you_can_turn_on_lock) ) fun laFailedAlert() { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.la_auth_failed), - text = generalGetString(R.string.la_could_not_be_verified) + title = generalGetString(MR.strings.la_auth_failed), + text = generalGetString(MR.strings.la_could_not_be_verified) ) } fun laUnavailableInstructionAlert() = AlertManager.shared.showAlertMsg( - generalGetString(R.string.auth_unavailable), - generalGetString(R.string.auth_device_authentication_is_not_enabled_you_can_turn_on_in_settings_once_enabled) + generalGetString(MR.strings.auth_unavailable), + generalGetString(MR.strings.auth_device_authentication_is_not_enabled_you_can_turn_on_in_settings_once_enabled) ) fun laUnavailableTurningOffAlert() = AlertManager.shared.showAlertMsg( - generalGetString(R.string.auth_unavailable), - generalGetString(R.string.auth_device_authentication_is_disabled_turning_off) + generalGetString(MR.strings.auth_unavailable), + generalGetString(MR.strings.auth_device_authentication_is_disabled_turning_off) ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ModalView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ModalView.kt index 64c2d7fc47..8fe2e05d92 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ModalView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/ModalView.kt @@ -13,7 +13,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.intl.Locale import chat.simplex.app.TAG diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/RecAndPlay.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/RecAndPlay.kt index e902f3dc37..01387dd963 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/RecAndPlay.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/RecAndPlay.kt @@ -13,6 +13,7 @@ import chat.simplex.app.* import chat.simplex.app.R import chat.simplex.app.model.ChatItem import chat.simplex.app.views.helpers.AudioPlayer.duration +import chat.simplex.res.MR import kotlinx.coroutines.* import java.io.* @@ -162,13 +163,13 @@ object AudioPlayer { player.setDataSource(filePath) }.onFailure { Log.e(TAG, it.stackTraceToString()) - AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), it.message) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), it.message) return null } runCatching { player.prepare() }.onFailure { // Can happen when audio file is broken Log.e(TAG, it.stackTraceToString()) - AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), it.message) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), it.message) return null } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/SearchTextField.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/SearchTextField.kt index 5b299d3855..2855cd75a5 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/SearchTextField.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/SearchTextField.kt @@ -18,13 +18,14 @@ import androidx.compose.ui.graphics.* import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.* import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R +import chat.simplex.res.MR import kotlinx.coroutines.delay @OptIn(ExperimentalComposeUiApi::class) @@ -33,7 +34,7 @@ fun SearchTextField( modifier: Modifier, alwaysVisible: Boolean, searchText: MutableState = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }, - placeholder: String = stringResource(android.R.string.search_go), + placeholder: String = stringResource(MR.strings.search_verb), onValueChange: (String) -> Unit ) { val focusRequester = remember { FocusRequester() } @@ -103,7 +104,7 @@ fun SearchTextField( searchText.value = TextFieldValue(""); onValueChange("") }) { - Icon(painterResource(R.drawable.ic_close), stringResource(R.string.icon_descr_close_button), tint = MaterialTheme.colors.primary,) + Icon(painterResource(R.drawable.ic_close), stringResource(MR.strings.icon_descr_close_button), tint = MaterialTheme.colors.primary,) } }} else null, singleLine = true, diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/Share.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/Share.kt index 0affca2e34..10ef455a48 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/Share.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/Share.kt @@ -15,6 +15,7 @@ import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import chat.simplex.app.* import chat.simplex.app.model.CIFile +import chat.simplex.res.MR import java.io.BufferedOutputStream import java.io.File @@ -80,10 +81,10 @@ fun rememberSaveFileLauncher(ciFile: CIFile?): ManagedActivityResultLauncher").substringBeforeLast("

") } -fun Resources.getText(@StringRes id: Int, vararg args: Any): CharSequence { +fun Resources.getText(id: StringResource, vararg args: Any): CharSequence { val escapedArgs = args.map { if (it is Spanned) it.toHtmlWithoutParagraphs() else it }.toTypedArray() @@ -121,13 +120,16 @@ fun Resources.getText(@StringRes id: Int, vararg args: Any): CharSequence { return HtmlCompat.fromHtml(formattedHtml, HtmlCompat.FROM_HTML_MODE_LEGACY) } +fun escapedHtmlToAnnotatedString(text: String, density: Density): AnnotatedString { + return spannableStringToAnnotatedString(HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY), density) +} + @Composable -fun annotatedStringResource(@StringRes id: Int): AnnotatedString { - val resources = resources() +fun annotatedStringResource(id: StringResource): AnnotatedString { val density = LocalDensity.current return remember(id) { - val text = resources.getText(id) - spannableStringToAnnotatedString(text, density) + val text = id.getString(SimplexApp.context) + escapedHtmlToAnnotatedString(text, density) } } @@ -362,8 +364,8 @@ fun getBitmapFromUri(uri: Uri, withAlertOnException: Boolean = true): Bitmap? { Log.e(TAG, "Unable to decode the image: ${e.stackTraceToString()}") if (withAlertOnException) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.image_decoding_exception_title), - text = generalGetString(R.string.image_decoding_exception_desc) + title = generalGetString(MR.strings.image_decoding_exception_title), + text = generalGetString(MR.strings.image_decoding_exception_desc) ) } null @@ -381,8 +383,8 @@ fun getDrawableFromUri(uri: Uri, withAlertOnException: Boolean = true): Drawable } catch (e: android.graphics.ImageDecoder.DecodeException) { if (withAlertOnException) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.image_decoding_exception_title), - text = generalGetString(R.string.image_decoding_exception_desc) + title = generalGetString(MR.strings.image_decoding_exception_title), + text = generalGetString(MR.strings.image_decoding_exception_desc) ) } Log.e(TAG, "Error while decoding drawable: ${e.stackTraceToString()}") @@ -400,8 +402,8 @@ fun getThemeFromUri(uri: Uri, withAlertOnException: Boolean = true): ThemeOverri }.onFailure { if (withAlertOnException) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.import_theme_error), - text = generalGetString(R.string.import_theme_error_desc), + title = generalGetString(MR.strings.import_theme_error), + text = generalGetString(MR.strings.import_theme_error_desc), ) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/VideoPlayer.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/VideoPlayer.kt index 25f5d6aacf..fcaa6158df 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/VideoPlayer.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/helpers/VideoPlayer.kt @@ -15,6 +15,7 @@ import com.google.android.exoplayer2.audio.AudioAttributes import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.upstream.DefaultDataSource import com.google.android.exoplayer2.upstream.DefaultHttpDataSource +import chat.simplex.res.MR import kotlinx.coroutines.* import java.io.File @@ -125,7 +126,7 @@ class VideoPlayer private constructor( player.setMediaSource(source, seek ?: 0L) }.onFailure { Log.e(TAG, it.stackTraceToString()) - AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), it.message) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), it.message) brokenVideo.value = true return false } @@ -134,7 +135,7 @@ class VideoPlayer private constructor( runCatching { player.prepare() }.onFailure { // Can happen when video file is broken Log.e(TAG, it.stackTraceToString()) - AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), it.message) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), it.message) brokenVideo.value = true return false } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/LocalAuthView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/LocalAuthView.kt index e972ad8620..9187c85d9b 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/LocalAuthView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/LocalAuthView.kt @@ -4,7 +4,7 @@ import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.* import chat.simplex.app.model.* import chat.simplex.app.views.database.deleteChatAsync @@ -13,12 +13,13 @@ import chat.simplex.app.views.helpers.* import chat.simplex.app.views.helpers.DatabaseUtils.ksSelfDestructPassword import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword import chat.simplex.app.views.onboarding.OnboardingStage +import chat.simplex.res.MR import kotlinx.coroutines.delay @Composable fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) { val passcode = rememberSaveable { mutableStateOf("") } - PasscodeView(passcode, authRequest.title ?: stringResource(R.string.la_enter_app_passcode), authRequest.reason, stringResource(R.string.submit_passcode), + PasscodeView(passcode, authRequest.title ?: stringResource(MR.strings.la_enter_app_passcode), authRequest.reason, stringResource(MR.strings.submit_passcode), submit = { val sdPassword = ksSelfDestructPassword.get() if (sdPassword == passcode.value && authRequest.selfDestruct) { @@ -26,12 +27,12 @@ fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) { authRequest.completed(r) } } else { - val r: LAResult = if (passcode.value == authRequest.password) LAResult.Success else LAResult.Error(generalGetString(R.string.incorrect_passcode)) + val r: LAResult = if (passcode.value == authRequest.password) LAResult.Success else LAResult.Error(generalGetString(MR.strings.incorrect_passcode)) authRequest.completed(r) } }, cancel = { - authRequest.completed(LAResult.Error(generalGetString(R.string.authentication_cancelled))) + authRequest.completed(LAResult.Error(generalGetString(MR.strings.authentication_cancelled))) }) } @@ -74,7 +75,7 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: ( AlertManager.shared.hideAlert() completed(LAResult.Success) } catch (e: Exception) { - completed(LAResult.Error(generalGetString(R.string.incorrect_passcode))) + completed(LAResult.Error(generalGetString(MR.strings.incorrect_passcode))) } } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/PasscodeView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/PasscodeView.kt index 0aec5dc344..9a190d2750 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/PasscodeView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/PasscodeView.kt @@ -14,6 +14,7 @@ import chat.simplex.app.R import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.SimpleButton import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun PasscodeView( @@ -39,7 +40,7 @@ fun PasscodeView( } PasscodeEntry(passcode, true) Row { - SimpleButton(generalGetString(R.string.cancel_verb), icon = painterResource(R.drawable.ic_close), click = cancel) + SimpleButton(generalGetString(MR.strings.cancel_verb), icon = painterResource(R.drawable.ic_close), click = cancel) Spacer(Modifier.size(20.dp)) SimpleButton(submitLabel, icon = painterResource(R.drawable.ic_done_filled), disabled = submitEnabled?.invoke(passcode.value) == false || passcode.value.length < 4, click = submit) } @@ -82,7 +83,7 @@ fun PasscodeView( Modifier.padding(start = 30.dp).height(s * 3), verticalArrangement = Arrangement.SpaceEvenly ) { - SimpleButton(generalGetString(R.string.cancel_verb), icon = painterResource(R.drawable.ic_close), click = cancel) + SimpleButton(generalGetString(MR.strings.cancel_verb), icon = painterResource(R.drawable.ic_close), click = cancel) SimpleButton(submitLabel, icon = painterResource(R.drawable.ic_done_filled), disabled = submitEnabled?.invoke(passcode.value) == false || passcode.value.length < 4, click = submit) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/SetAppPasscodeView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/SetAppPasscodeView.kt index d7214a4143..5bac848f76 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/SetAppPasscodeView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/localauth/SetAppPasscodeView.kt @@ -7,11 +7,12 @@ import chat.simplex.app.R import chat.simplex.app.views.helpers.DatabaseUtils import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR @Composable fun SetAppPasscodeView( passcodeKeychain: DatabaseUtils.KeyStoreItem = ksAppPassword, - title: String = generalGetString(R.string.new_passcode), + title: String = generalGetString(MR.strings.new_passcode), reason: String? = null, submit: () -> Unit, cancel: () -> Unit, @@ -35,8 +36,8 @@ fun SetAppPasscodeView( if (confirming) { SetPasswordView( - generalGetString(R.string.confirm_passcode), - generalGetString(R.string.confirm_verb), + generalGetString(MR.strings.confirm_passcode), + generalGetString(MR.strings.confirm_verb), submitEnabled = { pwd -> pwd == enteredPassword } ) { if (passcode.value == enteredPassword) { @@ -48,7 +49,7 @@ fun SetAppPasscodeView( } } } else { - SetPasswordView(title, generalGetString(R.string.save_verb)) { + SetPasswordView(title, generalGetString(MR.strings.save_verb)) { enteredPassword = passcode.value passcode.value = "" confirming = true diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddContactLearnMore.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddContactLearnMore.kt index 3442e8833e..dd1963921d 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddContactLearnMore.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddContactLearnMore.kt @@ -4,20 +4,21 @@ import androidx.compose.foundation.* import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.R import chat.simplex.app.views.helpers.AppBarTitle import chat.simplex.app.views.onboarding.ReadableText import chat.simplex.app.views.onboarding.ReadableTextWithLink +import chat.simplex.res.MR @Composable fun AddContactLearnMore() { Column( Modifier.verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.one_time_link)) - ReadableText(R.string.scan_qr_to_connect_to_contact) - ReadableText(R.string.if_you_cant_meet_in_person) - ReadableTextWithLink(R.string.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends") + AppBarTitle(stringResource(MR.strings.one_time_link)) + ReadableText(MR.strings.scan_qr_to_connect_to_contact) + ReadableText(MR.strings.if_you_cant_meet_in_person) + ReadableTextWithLink(MR.strings.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends") } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt index cc5117bb9a..45478c3cdc 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -20,6 +20,7 @@ import chat.simplex.app.R import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.SettingsActionItem +import chat.simplex.res.MR @Composable fun AddContactView(connReqInvitation: String, connIncognito: Boolean) { @@ -49,11 +50,11 @@ fun AddContactLayout(connReq: String, connIncognito: Boolean, share: () -> Unit, .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.SpaceBetween, ) { - AppBarTitle(stringResource(R.string.add_contact)) + AppBarTitle(stringResource(MR.strings.add_contact)) OneTimeLinkProfileText(connIncognito) SectionSpacer() - SectionView(stringResource(R.string.one_time_link_short).uppercase()) { + SectionView(stringResource(MR.strings.one_time_link_short).uppercase()) { OneTimeLinkSection(connReq, share, learnMore) } SectionBottomSpacer() @@ -66,8 +67,8 @@ fun OneTimeLinkProfileText(connIncognito: Boolean) { InfoAboutIncognito( connIncognito, true, - generalGetString(R.string.incognito_random_profile_description), - generalGetString(R.string.your_profile_will_be_sent) + generalGetString(MR.strings.incognito_random_profile_description), + generalGetString(MR.strings.your_profile_will_be_sent) ) } } @@ -98,7 +99,7 @@ fun ColumnScope.OneTimeLinkSection(connReq: String, share: () -> Unit, learnMore fun ShareLinkButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_share), - stringResource(R.string.share_invitation_link), + stringResource(MR.strings.share_invitation_link), onClick, iconColor = MaterialTheme.colors.primary, textColor = MaterialTheme.colors.primary, @@ -109,7 +110,7 @@ fun ShareLinkButton(onClick: () -> Unit) { fun OneTimeLinkLearnMoreButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_info), - stringResource(R.string.learn_more), + stringResource(MR.strings.learn_more), onClick, ) } @@ -126,7 +127,7 @@ fun InfoAboutIncognito(chatModelIncognito: Boolean, supportedIncognito: Boolean ) { Icon( if (supportedIncognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_info), - stringResource(R.string.incognito), + stringResource(MR.strings.incognito), tint = if (supportedIncognito) Indigo else WarningOrange, modifier = Modifier.padding(end = 10.dp).size(20.dp) ) @@ -142,7 +143,7 @@ fun InfoAboutIncognito(chatModelIncognito: Boolean, supportedIncognito: Boolean ) { Icon( painterResource(R.drawable.ic_info), - stringResource(R.string.incognito), + stringResource(MR.strings.incognito), tint = MaterialTheme.colors.secondary, modifier = Modifier.padding(end = 10.dp).size(20.dp) ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt index b166d07bf1..d0ffd05eb7 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/AddGroupView.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -31,6 +31,7 @@ import chat.simplex.app.views.usersettings.DeleteImageButton import chat.simplex.app.views.usersettings.EditImageButton import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsWithImePadding +import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -88,8 +89,8 @@ fun AddGroupLayout(createGroup: (GroupProfile) -> Unit, close: () -> Unit) { .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING) ) { - AppBarTitle(stringResource(R.string.create_secret_group_title)) - ReadableText(R.string.group_is_decentralized, TextAlign.Center) + AppBarTitle(stringResource(MR.strings.create_secret_group_title)) + ReadableText(MR.strings.group_is_decentralized, TextAlign.Center) Box( Modifier .fillMaxWidth() @@ -108,13 +109,13 @@ fun AddGroupLayout(createGroup: (GroupProfile) -> Unit, close: () -> Unit) { } Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Text( - stringResource(R.string.group_display_name_field), + stringResource(MR.strings.group_display_name_field), fontSize = 16.sp ) if (!isValidDisplayName(displayName.value)) { Spacer(Modifier.size(DEFAULT_PADDING_HALF)) Text( - stringResource(R.string.no_spaces), + stringResource(MR.strings.no_spaces), fontSize = 16.sp, color = Color.Red ) @@ -123,7 +124,7 @@ fun AddGroupLayout(createGroup: (GroupProfile) -> Unit, close: () -> Unit) { ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester) Spacer(Modifier.height(DEFAULT_PADDING)) Text( - stringResource(R.string.group_full_name_field), + stringResource(MR.strings.group_full_name_field), fontSize = 16.sp, modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF) ) @@ -161,8 +162,8 @@ fun CreateGroupButton(color: Color, modifier: Modifier) { ) { Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) { Row(modifier, verticalAlignment = Alignment.CenterVertically) { - Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = color, fontWeight = FontWeight.Bold) - Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = color) + Text(stringResource(MR.strings.create_profile_button), style = MaterialTheme.typography.caption, color = color, fontWeight = FontWeight.Bold) + Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(MR.strings.create_profile_button), tint = color) } } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ConnectViaLinkView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ConnectViaLinkView.kt index 18a149eb52..4fae906866 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ConnectViaLinkView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ConnectViaLinkView.kt @@ -6,10 +6,11 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.ChatModel +import chat.simplex.res.MR enum class ConnectViaLinkTab { SCAN, PASTE @@ -24,8 +25,8 @@ fun ConnectViaLinkView(m: ChatModel, close: () -> Unit) { } val tabTitles = ConnectViaLinkTab.values().map { when (it) { - ConnectViaLinkTab.SCAN -> stringResource(R.string.scan_QR_code) - ConnectViaLinkTab.PASTE -> stringResource(R.string.paste_the_link_you_received) + ConnectViaLinkTab.SCAN -> stringResource(MR.strings.scan_QR_code) + ConnectViaLinkTab.PASTE -> stringResource(MR.strings.paste_the_link_you_received) } } Column( diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt index 50ad56a5eb..0cd72e0472 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ContactConnectionInfoView.kt @@ -12,7 +12,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import chat.simplex.app.R import chat.simplex.app.model.* @@ -21,6 +21,7 @@ import chat.simplex.app.views.chat.LocalAliasEditor import chat.simplex.app.views.chatlist.deleteContactConnectionAlert import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.SettingsActionItem +import chat.simplex.res.MR @Composable fun ContactConnectionInfoView( @@ -84,16 +85,16 @@ private fun ContactConnectionInfoLayout( ) { AppBarTitle( stringResource( - if (contactConnection.initiated) R.string.you_invited_your_contact - else R.string.you_accepted_connection + if (contactConnection.initiated) MR.strings.you_invited_your_contact + else MR.strings.you_accepted_connection ) ) Text( stringResource( if (contactConnection.viaContactUri) - if (contactConnection.groupLinkId != null) R.string.you_will_be_connected_when_group_host_device_is_online - else R.string.you_will_be_connected_when_your_connection_request_is_accepted - else R.string.you_will_be_connected_when_your_contacts_device_is_online + if (contactConnection.groupLinkId != null) MR.strings.you_will_be_connected_when_group_host_device_is_online + else MR.strings.you_will_be_connected_when_your_connection_request_is_accepted + else MR.strings.you_will_be_connected_when_your_contacts_device_is_online ), Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING) ) @@ -123,7 +124,7 @@ private fun ContactConnectionInfoLayout( fun DeleteButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_delete), - stringResource(R.string.delete_verb), + stringResource(MR.strings.delete_verb), click = onClick, textColor = Color.Red, iconColor = Color.Red, diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/CreateLinkView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/CreateLinkView.kt index 61a236936b..633b72720f 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/CreateLinkView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/CreateLinkView.kt @@ -7,7 +7,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.ChatModel @@ -15,6 +15,7 @@ import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.views.helpers.ModalManager import chat.simplex.app.views.helpers.withApi import chat.simplex.app.views.usersettings.UserAddressView +import chat.simplex.res.MR enum class CreateLinkTab { ONE_TIME, LONG_TERM @@ -43,9 +44,9 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) { } val tabTitles = CreateLinkTab.values().map { when { - it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() -> stringResource(R.string.create_one_time_link) - it == CreateLinkTab.ONE_TIME -> stringResource(R.string.one_time_link) - it == CreateLinkTab.LONG_TERM -> stringResource(R.string.your_simplex_contact_address) + it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() -> stringResource(MR.strings.create_one_time_link) + it == CreateLinkTab.ONE_TIME -> stringResource(MR.strings.one_time_link) + it == CreateLinkTab.LONG_TERM -> stringResource(MR.strings.your_simplex_contact_address) else -> "" } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/NewChatSheet.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/NewChatSheet.kt index 0808229e69..573348847d 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/NewChatSheet.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/NewChatSheet.kt @@ -17,7 +17,7 @@ import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.* import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -28,6 +28,7 @@ import chat.simplex.app.R import chat.simplex.app.model.ChatModel import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -55,7 +56,7 @@ fun NewChatSheet(chatModel: ChatModel, newChatSheetState: StateFlow Unit) { @@ -46,17 +47,17 @@ fun PasteToConnectView(chatModel: ChatModel, close: () -> Unit) { } if (linkType == ConnectionLinkType.GROUP) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.connect_via_group_link), - text = generalGetString(R.string.you_will_join_group), - confirmText = generalGetString(R.string.connect_via_link_verb), + title = generalGetString(MR.strings.connect_via_group_link), + text = generalGetString(MR.strings.you_will_join_group), + confirmText = generalGetString(MR.strings.connect_via_link_verb), onConfirm = { withApi { action() } } ) } else action() } } catch (e: RuntimeException) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.invalid_connection_link), - text = generalGetString(R.string.this_string_is_not_a_connection_link) + title = generalGetString(MR.strings.invalid_connection_link), + text = generalGetString(MR.strings.this_string_is_not_a_connection_link) ) } }, @@ -74,14 +75,14 @@ fun PasteToConnectLayout( Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.SpaceBetween, ) { - AppBarTitle(stringResource(R.string.connect_via_link), false) - Text(stringResource(R.string.paste_connection_link_below_to_connect)) + AppBarTitle(stringResource(MR.strings.connect_via_link), false) + Text(stringResource(MR.strings.paste_connection_link_below_to_connect)) InfoAboutIncognito( chatModelIncognito, true, - generalGetString(R.string.incognito_random_profile_from_contact_description), - generalGetString(R.string.profile_will_be_sent_to_contact_sending_link) + generalGetString(MR.strings.incognito_random_profile_from_contact_description), + generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link) ) Box(Modifier.padding(top = DEFAULT_PADDING, bottom = 6.dp)) { @@ -93,21 +94,21 @@ fun PasteToConnectLayout( horizontalArrangement = Arrangement.Start, ) { if (connectionLink.value == "") { - SimpleButton(text = stringResource(R.string.paste_button), icon = painterResource(R.drawable.ic_content_paste)) { + SimpleButton(text = stringResource(MR.strings.paste_button), icon = painterResource(R.drawable.ic_content_paste)) { pasteFromClipboard() } } else { - SimpleButton(text = stringResource(R.string.clear_verb), icon = painterResource(R.drawable.ic_close)) { + SimpleButton(text = stringResource(MR.strings.clear_verb), icon = painterResource(R.drawable.ic_close)) { connectionLink.value = "" } } Spacer(Modifier.weight(1f).fillMaxWidth()) - SimpleButton(text = stringResource(R.string.connect_button), icon = painterResource(R.drawable.ic_link)) { + SimpleButton(text = stringResource(MR.strings.connect_button), icon = painterResource(R.drawable.ic_link)) { connectViaLink(connectionLink.value) } } - Text(annotatedStringResource(R.string.you_can_also_connect_by_clicking_the_link)) + Text(annotatedStringResource(MR.strings.you_can_also_connect_by_clicking_the_link)) SectionBottomSpacer() } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/QRCode.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/QRCode.kt index 62c1f4f72e..c3830bd91b 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/QRCode.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/QRCode.kt @@ -7,7 +7,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.* import androidx.compose.ui.platform.* -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.core.graphics.* import androidx.core.graphics.drawable.toBitmap @@ -18,6 +18,7 @@ import chat.simplex.app.R import chat.simplex.app.SimplexApp import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.launch @Composable @@ -38,7 +39,7 @@ fun QRCode( } Image( bitmap = qr, - contentDescription = stringResource(R.string.image_descr_qr_code), + contentDescription = stringResource(MR.strings.image_descr_qr_code), modifier .clickable { scope.launch { diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ScanToConnectView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ScanToConnectView.kt index d1210c8e16..2bbef58cf8 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ScanToConnectView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/newchat/ScanToConnectView.kt @@ -12,7 +12,7 @@ import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -25,6 +25,7 @@ import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.helpers.* import com.google.accompanist.permissions.rememberPermissionState +import chat.simplex.res.MR import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -49,17 +50,17 @@ fun ScanToConnectView(chatModel: ChatModel, close: () -> Unit) { } if (linkType == ConnectionLinkType.GROUP) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.connect_via_group_link), - text = generalGetString(R.string.you_will_join_group), - confirmText = generalGetString(R.string.connect_via_link_verb), + title = generalGetString(MR.strings.connect_via_group_link), + text = generalGetString(MR.strings.you_will_join_group), + confirmText = generalGetString(MR.strings.connect_via_link_verb), onConfirm = { withApi { action() } } ) } else action() } } catch (e: RuntimeException) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.invalid_QR_code), - text = generalGetString(R.string.this_QR_code_is_not_a_link) + title = generalGetString(MR.strings.invalid_QR_code), + text = generalGetString(MR.strings.this_QR_code_is_not_a_link) ) } } @@ -97,8 +98,8 @@ fun withUriAction(uri: Uri, run: suspend (ConnectionLinkType) -> Unit) { withApi { run(type) } } else { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.invalid_contact_link), - text = generalGetString(R.string.this_link_is_not_a_valid_connection_link) + title = generalGetString(MR.strings.invalid_contact_link), + text = generalGetString(MR.strings.this_link_is_not_a_valid_connection_link) ) } } @@ -107,12 +108,12 @@ suspend fun connectViaUri(chatModel: ChatModel, action: ConnectionLinkType, uri: val r = chatModel.controller.apiConnect(uri.toString()) if (r) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.connection_request_sent), + title = generalGetString(MR.strings.connection_request_sent), text = when (action) { - ConnectionLinkType.CONTACT -> generalGetString(R.string.you_will_be_connected_when_your_connection_request_is_accepted) - ConnectionLinkType.INVITATION -> generalGetString(R.string.you_will_be_connected_when_your_contacts_device_is_online) - ConnectionLinkType.GROUP -> generalGetString(R.string.you_will_be_connected_when_group_host_device_is_online) + ConnectionLinkType.CONTACT -> generalGetString(MR.strings.you_will_be_connected_when_your_connection_request_is_accepted) + ConnectionLinkType.INVITATION -> generalGetString(MR.strings.you_will_be_connected_when_your_contacts_device_is_online) + ConnectionLinkType.GROUP -> generalGetString(MR.strings.you_will_be_connected_when_group_host_device_is_online) } ) } @@ -125,12 +126,12 @@ fun ConnectContactLayout(chatModelIncognito: Boolean, qrCodeScanner: @Composable Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.spacedBy(12.dp) ) { - AppBarTitle(stringResource(R.string.scan_QR_code), false) + AppBarTitle(stringResource(MR.strings.scan_QR_code), false) InfoAboutIncognito( chatModelIncognito, true, - generalGetString(R.string.incognito_random_profile_description), - generalGetString(R.string.your_profile_will_be_sent) + generalGetString(MR.strings.incognito_random_profile_description), + generalGetString(MR.strings.your_profile_will_be_sent) ) Box( Modifier @@ -139,7 +140,7 @@ fun ConnectContactLayout(chatModelIncognito: Boolean, qrCodeScanner: @Composable .padding(bottom = 12.dp) ) { qrCodeScanner() } Text( - annotatedStringResource(R.string.if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link), + annotatedStringResource(MR.strings.if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link), lineHeight = 22.sp ) SectionBottomSpacer() diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/CreateSimpleXAddress.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/CreateSimpleXAddress.kt index f536039542..ef3be86653 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/CreateSimpleXAddress.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/CreateSimpleXAddress.kt @@ -10,7 +10,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import chat.simplex.app.* @@ -20,6 +20,7 @@ import chat.simplex.app.model.UserContactLinkRec import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.QRCode +import chat.simplex.res.MR @Composable fun CreateSimpleXAddress(m: ChatModel) { @@ -31,8 +32,8 @@ fun CreateSimpleXAddress(m: ChatModel) { share = { address: String -> shareText(address) }, sendEmail = { address -> sendEmail( - generalGetString(R.string.email_invite_subject), - generalGetString(R.string.email_invite_body).format(address.connReqContact) + generalGetString(MR.strings.email_invite_subject), + generalGetString(MR.strings.email_invite_body).format(address.connReqContact) ) }, createAddress = { @@ -76,7 +77,7 @@ private fun CreateSimpleXAddressLayout( Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING), horizontalAlignment = Alignment.CenterHorizontally, ) { - AppBarTitle(stringResource(R.string.simplex_address)) + AppBarTitle(stringResource(MR.strings.simplex_address)) Spacer(Modifier.weight(1f)) @@ -89,7 +90,7 @@ private fun CreateSimpleXAddressLayout( ContinueButton(nextStep) } else { CreateAddressButton(createAddress) - TextBelowButton(stringResource(R.string.your_contacts_will_see_it)) + TextBelowButton(stringResource(MR.strings.your_contacts_will_see_it)) Spacer(Modifier.weight(1f)) SkipButton(nextStep) } @@ -100,7 +101,7 @@ private fun CreateSimpleXAddressLayout( @Composable private fun CreateAddressButton(onClick: () -> Unit) { TextButton(onClick) { - Text(stringResource(R.string.create_simplex_address), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary) + Text(stringResource(MR.strings.create_simplex_address), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary) } } @@ -108,10 +109,10 @@ private fun CreateAddressButton(onClick: () -> Unit) { fun ShareAddressButton(onClick: () -> Unit) { SimpleButtonFrame(onClick) { Icon( - painterResource(R.drawable.ic_share_filled), generalGetString(R.string.share_verb), tint = MaterialTheme.colors.primary, + painterResource(R.drawable.ic_share_filled), generalGetString(MR.strings.share_verb), tint = MaterialTheme.colors.primary, modifier = Modifier.padding(end = 8.dp).size(18.dp) ) - Text(stringResource(R.string.share_verb), style = MaterialTheme.typography.caption, color = MaterialTheme.colors.primary) + Text(stringResource(MR.strings.share_verb), style = MaterialTheme.typography.caption, color = MaterialTheme.colors.primary) } } @@ -119,22 +120,22 @@ fun ShareAddressButton(onClick: () -> Unit) { fun ShareViaEmailButton(onClick: () -> Unit) { SimpleButtonFrame(onClick) { Icon( - painterResource(R.drawable.ic_mail), generalGetString(R.string.share_verb), tint = MaterialTheme.colors.primary, + painterResource(R.drawable.ic_mail), generalGetString(MR.strings.share_verb), tint = MaterialTheme.colors.primary, modifier = Modifier.padding(end = 8.dp).size(30.dp) ) - Text(stringResource(R.string.invite_friends), style = MaterialTheme.typography.h6, color = MaterialTheme.colors.primary) + Text(stringResource(MR.strings.invite_friends), style = MaterialTheme.typography.h6, color = MaterialTheme.colors.primary) } } @Composable private fun ContinueButton(onClick: () -> Unit) { - SimpleButtonIconEnded(stringResource(R.string.continue_to_next_step), painterResource(R.drawable.ic_chevron_right), click = onClick) + SimpleButtonIconEnded(stringResource(MR.strings.continue_to_next_step), painterResource(R.drawable.ic_chevron_right), click = onClick) } @Composable private fun SkipButton(onClick: () -> Unit) { - SimpleButtonIconEnded(stringResource(R.string.dont_create_address), painterResource(R.drawable.ic_chevron_right), click = onClick) - TextBelowButton(stringResource(R.string.you_can_create_it_later)) + SimpleButtonIconEnded(stringResource(MR.strings.dont_create_address), painterResource(R.drawable.ic_chevron_right), click = onClick) + TextBelowButton(stringResource(MR.strings.you_can_create_it_later)) } @Composable diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/HowItWorks.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/HowItWorks.kt index e87254ac74..c8bc7b5edf 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/HowItWorks.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/HowItWorks.kt @@ -1,7 +1,6 @@ package chat.simplex.app.views.onboarding import android.content.res.Configuration -import androidx.annotation.StringRes import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.material.* @@ -9,18 +8,19 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import chat.simplex.app.R import chat.simplex.app.SimplexApp import chat.simplex.app.model.User import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.item.MarkdownText import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource +import dev.icerock.moko.resources.compose.stringResource @Composable fun HowItWorks(user: User?, onboardingStage: MutableState? = null) { @@ -28,15 +28,15 @@ fun HowItWorks(user: User?, onboardingStage: MutableState? = n .fillMaxWidth() .padding(horizontal = DEFAULT_PADDING), ) { - AppBarTitle(stringResource(R.string.how_simplex_works), false) - ReadableText(R.string.many_people_asked_how_can_it_deliver) - ReadableText(R.string.to_protect_privacy_simplex_has_ids_for_queues) - ReadableText(R.string.you_control_servers_to_receive_your_contacts_to_send) - ReadableText(R.string.only_client_devices_store_contacts_groups_e2e_encrypted_messages) + AppBarTitle(stringResource(MR.strings.how_simplex_works), false) + ReadableText(MR.strings.many_people_asked_how_can_it_deliver) + ReadableText(MR.strings.to_protect_privacy_simplex_has_ids_for_queues) + ReadableText(MR.strings.you_control_servers_to_receive_your_contacts_to_send) + ReadableText(MR.strings.only_client_devices_store_contacts_groups_e2e_encrypted_messages) if (onboardingStage == null) { - ReadableTextWithLink(R.string.read_more_in_github_with_link, "https://github.com/simplex-chat/simplex-chat#readme") + ReadableTextWithLink(MR.strings.read_more_in_github_with_link, "https://github.com/simplex-chat/simplex-chat#readme") } else { - ReadableText(R.string.read_more_in_github) + ReadableText(MR.strings.read_more_in_github) } Spacer(Modifier.fillMaxHeight().weight(1f)) @@ -51,12 +51,12 @@ fun HowItWorks(user: User?, onboardingStage: MutableState? = n } @Composable -fun ReadableText(@StringRes stringResId: Int, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp), style: TextStyle = LocalTextStyle.current) { +fun ReadableText(stringResId: StringResource, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp), style: TextStyle = LocalTextStyle.current) { Text(annotatedStringResource(stringResId), modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp, style = style) } @Composable -fun ReadableTextWithLink(@StringRes stringResId: Int, link: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) { +fun ReadableTextWithLink(stringResId: StringResource, link: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) { val annotated = annotatedStringResource(stringResId) val primary = MaterialTheme.colors.primary // This replaces links in text highlighted with specific color, e.g. SimplexBlue diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/SetNotificationsMode.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/SetNotificationsMode.kt index ebb934ec75..9f3b87194e 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/SetNotificationsMode.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/SetNotificationsMode.kt @@ -2,7 +2,6 @@ package chat.simplex.app.views.onboarding import android.Manifest import android.os.Build -import androidx.annotation.StringRes import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape @@ -11,7 +10,7 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -25,6 +24,8 @@ import chat.simplex.app.views.helpers.* import chat.simplex.app.views.usersettings.NotificationsMode import chat.simplex.app.views.usersettings.changeNotificationsMode import com.google.accompanist.permissions.rememberPermissionState +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource @Composable fun SetNotificationsMode(m: ChatModel) { @@ -35,18 +36,18 @@ fun SetNotificationsMode(m: ChatModel) { .padding(vertical = 14.dp) ) { //CloseSheetBar(null) - AppBarTitle(stringResource(R.string.onboarding_notifications_mode_title)) + AppBarTitle(stringResource(MR.strings.onboarding_notifications_mode_title)) val currentMode = rememberSaveable { mutableStateOf(NotificationsMode.default) } Column(Modifier.padding(horizontal = DEFAULT_PADDING * 1f)) { - Text(stringResource(R.string.onboarding_notifications_mode_subtitle), Modifier.fillMaxWidth(), textAlign = TextAlign.Center) + Text(stringResource(MR.strings.onboarding_notifications_mode_subtitle), Modifier.fillMaxWidth(), textAlign = TextAlign.Center) Spacer(Modifier.height(DEFAULT_PADDING * 2f)) - NotificationButton(currentMode, NotificationsMode.OFF, R.string.onboarding_notifications_mode_off, R.string.onboarding_notifications_mode_off_desc) - NotificationButton(currentMode, NotificationsMode.PERIODIC, R.string.onboarding_notifications_mode_periodic, R.string.onboarding_notifications_mode_periodic_desc) - NotificationButton(currentMode, NotificationsMode.SERVICE, R.string.onboarding_notifications_mode_service, R.string.onboarding_notifications_mode_service_desc) + NotificationButton(currentMode, NotificationsMode.OFF, MR.strings.onboarding_notifications_mode_off, MR.strings.onboarding_notifications_mode_off_desc) + NotificationButton(currentMode, NotificationsMode.PERIODIC, MR.strings.onboarding_notifications_mode_periodic, MR.strings.onboarding_notifications_mode_periodic_desc) + NotificationButton(currentMode, NotificationsMode.SERVICE, MR.strings.onboarding_notifications_mode_service, MR.strings.onboarding_notifications_mode_service_desc) } Spacer(Modifier.fillMaxHeight().weight(1f)) Box(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), contentAlignment = Alignment.Center) { - OnboardingActionButton(R.string.use_chat, OnboardingStage.OnboardingComplete, m.onboardingStage, false) { + OnboardingActionButton(MR.strings.use_chat, OnboardingStage.OnboardingComplete, m.onboardingStage, false) { changeNotificationsMode(currentMode.value, m) } } @@ -74,7 +75,7 @@ fun SetNotificationsModeAdditions() { } @Composable -private fun NotificationButton(currentMode: MutableState, mode: NotificationsMode, @StringRes title: Int, @StringRes description: Int) { +private fun NotificationButton(currentMode: MutableState, mode: NotificationsMode, title: StringResource, description: StringResource) { TextButton( onClick = { currentMode.value = mode }, border = BorderStroke(1.dp, color = if (currentMode.value == mode) MaterialTheme.colors.primary else MaterialTheme.colors.secondary.copy(alpha = 0.5f)), diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt index 7324f63421..8b828b0d60 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt @@ -1,7 +1,6 @@ package chat.simplex.app.views.onboarding import android.content.res.Configuration -import androidx.annotation.StringRes import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape @@ -12,7 +11,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -23,6 +22,8 @@ import chat.simplex.app.model.ChatModel import chat.simplex.app.model.User import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.ModalManager +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource @Composable fun SimpleXInfo(chatModel: ChatModel, onboarding: Boolean = true) { @@ -49,11 +50,11 @@ fun SimpleXInfoLayout( SimpleXLogo() } - Text(stringResource(R.string.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 48.dp).padding(horizontal = 36.dp), textAlign = TextAlign.Center) + Text(stringResource(MR.strings.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 48.dp).padding(horizontal = 36.dp), textAlign = TextAlign.Center) - InfoRow(painterResource(R.drawable.privacy), R.string.privacy_redefined, R.string.first_platform_without_user_ids, width = 80.dp) - InfoRow(painterResource(R.drawable.shield), R.string.immune_to_spam_and_abuse, R.string.people_can_connect_only_via_links_you_share) - InfoRow(painterResource(if (isInDarkTheme()) R.drawable.decentralized_light else R.drawable.decentralized), R.string.decentralized, R.string.opensource_protocol_and_code_anybody_can_run_servers) + InfoRow(painterResource(R.drawable.privacy), MR.strings.privacy_redefined, MR.strings.first_platform_without_user_ids, width = 80.dp) + InfoRow(painterResource(R.drawable.shield), MR.strings.immune_to_spam_and_abuse, MR.strings.people_can_connect_only_via_links_you_share) + InfoRow(painterResource(if (isInDarkTheme()) R.drawable.decentralized_light else R.drawable.decentralized), MR.strings.decentralized, MR.strings.opensource_protocol_and_code_anybody_can_run_servers) Spacer(Modifier.fillMaxHeight().weight(1f)) @@ -69,7 +70,7 @@ fun SimpleXInfoLayout( .fillMaxWidth() .padding(bottom = DEFAULT_PADDING.times(1.5f), top = DEFAULT_PADDING), contentAlignment = Alignment.Center ) { - SimpleButtonDecorated(text = stringResource(R.string.how_it_works), icon = painterResource(R.drawable.ic_info), + SimpleButtonDecorated(text = stringResource(MR.strings.how_it_works), icon = painterResource(R.drawable.ic_info), click = showModal { HowItWorks(user, onboardingStage) }) } } @@ -79,7 +80,7 @@ fun SimpleXInfoLayout( fun SimpleXLogo() { Image( painter = painterResource(if (isInDarkTheme()) R.drawable.logo_light else R.drawable.logo), - contentDescription = stringResource(R.string.image_descr_simplex_logo), + contentDescription = stringResource(MR.strings.image_descr_simplex_logo), modifier = Modifier .padding(vertical = DEFAULT_PADDING) .fillMaxWidth(0.60f) @@ -87,7 +88,7 @@ fun SimpleXLogo() { } @Composable -private fun InfoRow(icon: Painter, @StringRes titleId: Int, @StringRes textId: Int, width: Dp = 76.dp) { +private fun InfoRow(icon: Painter, titleId: StringResource, textId: StringResource, width: Dp = 76.dp) { Row(Modifier.padding(bottom = 27.dp), verticalAlignment = Alignment.Top) { Image(icon, contentDescription = null, modifier = Modifier .width(width) @@ -102,15 +103,15 @@ private fun InfoRow(icon: Painter, @StringRes titleId: Int, @StringRes textId: I @Composable fun OnboardingActionButton(user: User?, onboardingStage: MutableState, onclick: (() -> Unit)? = null) { if (user == null) { - OnboardingActionButton(R.string.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, onboardingStage, true, onclick) + OnboardingActionButton(MR.strings.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, onboardingStage, true, onclick) } else { - OnboardingActionButton(R.string.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, onboardingStage, true, onclick) + OnboardingActionButton(MR.strings.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, onboardingStage, true, onclick) } } @Composable fun OnboardingActionButton( - @StringRes labelId: Int, + labelId: StringResource, onboarding: OnboardingStage?, onboardingStage: MutableState, border: Boolean, diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/WhatsNewView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/WhatsNewView.kt index b67f668f9e..7cf67763a0 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/WhatsNewView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/onboarding/WhatsNewView.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -26,13 +27,15 @@ import chat.simplex.app.R import chat.simplex.app.model.ChatModel import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource @Composable fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) { val currentVersion = remember { mutableStateOf(versionDescriptions.lastIndex) } @Composable - fun featureDescription(icon: Painter, titleId: Int, descrId: Int, link: String?) { + fun featureDescription(icon: Painter, titleId: StringResource, descrId: StringResource, link: String?) { @Composable fun linkButton(link: String) { val uriHandler = LocalUriHandler.current @@ -115,7 +118,7 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) { .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(DEFAULT_PADDING.times(0.75f)) ) { - AppBarTitle(String.format(generalGetString(R.string.new_in_version), v.version), bottomPadding = DEFAULT_PADDING) + AppBarTitle(String.format(generalGetString(MR.strings.new_in_version), v.version), bottomPadding = DEFAULT_PADDING) v.features.forEach { feature -> featureDescription(painterResource(feature.icon), feature.titleId, feature.descrId, feature.link) @@ -124,9 +127,9 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) { val uriHandler = LocalUriHandler.current if (v.post != null) { Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(top = DEFAULT_PADDING.div(4))) { - Text(stringResource(R.string.whats_new_read_more), color = MaterialTheme.colors.primary, + Text(stringResource(MR.strings.whats_new_read_more), color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openUriCatching(v.post) }) - Icon(painterResource(R.drawable.ic_open_in_new), stringResource(R.string.whats_new_read_more), tint = MaterialTheme.colors.primary) + Icon(painterResource(R.drawable.ic_open_in_new), stringResource(MR.strings.whats_new_read_more), tint = MaterialTheme.colors.primary) } } @@ -136,7 +139,7 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) { Modifier.fillMaxWidth(), contentAlignment = Alignment.Center ) { Text( - generalGetString(R.string.ok), + generalGetString(MR.strings.ok), modifier = Modifier.clickable(onClick = close), style = MaterialTheme.typography.h3, color = MaterialTheme.colors.primary @@ -154,8 +157,8 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) { private data class FeatureDescription( val icon: Int, - val titleId: Int, - val descrId: Int, + val titleId: StringResource, + val descrId: StringResource, val link: String? = null ) @@ -172,19 +175,19 @@ private val versionDescriptions: List = listOf( features = listOf( FeatureDescription( icon = R.drawable.ic_verified_user, - titleId = R.string.v4_2_security_assessment, - descrId = R.string.v4_2_security_assessment_desc, + titleId = MR.strings.v4_2_security_assessment, + descrId = MR.strings.v4_2_security_assessment_desc, link = "https://simplex.chat/blog/20221108-simplex-chat-v4.2-security-audit-new-website.html" ), FeatureDescription( icon = R.drawable.ic_group, - titleId = R.string.v4_2_group_links, - descrId = R.string.v4_2_group_links_desc + titleId = MR.strings.v4_2_group_links, + descrId = MR.strings.v4_2_group_links_desc ), FeatureDescription( icon = R.drawable.ic_check, - titleId = R.string.v4_2_auto_accept_contact_requests, - descrId = R.string.v4_2_auto_accept_contact_requests_desc + titleId = MR.strings.v4_2_auto_accept_contact_requests, + descrId = MR.strings.v4_2_auto_accept_contact_requests_desc ), ) ), @@ -194,23 +197,23 @@ private val versionDescriptions: List = listOf( features = listOf( FeatureDescription( icon = R.drawable.ic_mic, - titleId = R.string.v4_3_voice_messages, - descrId = R.string.v4_3_voice_messages_desc + titleId = MR.strings.v4_3_voice_messages, + descrId = MR.strings.v4_3_voice_messages_desc ), FeatureDescription( icon = R.drawable.ic_delete_forever, - titleId = R.string.v4_3_irreversible_message_deletion, - descrId = R.string.v4_3_irreversible_message_deletion_desc + titleId = MR.strings.v4_3_irreversible_message_deletion, + descrId = MR.strings.v4_3_irreversible_message_deletion_desc ), FeatureDescription( icon = R.drawable.ic_wifi_tethering, - titleId = R.string.v4_3_improved_server_configuration, - descrId = R.string.v4_3_improved_server_configuration_desc + titleId = MR.strings.v4_3_improved_server_configuration, + descrId = MR.strings.v4_3_improved_server_configuration_desc ), FeatureDescription( icon = R.drawable.ic_visibility_off, - titleId = R.string.v4_3_improved_privacy_and_security, - descrId = R.string.v4_3_improved_privacy_and_security_desc + titleId = MR.strings.v4_3_improved_privacy_and_security, + descrId = MR.strings.v4_3_improved_privacy_and_security_desc ), ) ), @@ -220,23 +223,23 @@ private val versionDescriptions: List = listOf( features = listOf( FeatureDescription( icon = R.drawable.ic_timer, - titleId = R.string.v4_4_disappearing_messages, - descrId = R.string.v4_4_disappearing_messages_desc + titleId = MR.strings.v4_4_disappearing_messages, + descrId = MR.strings.v4_4_disappearing_messages_desc ), FeatureDescription( icon = R.drawable.ic_pending, - titleId = R.string.v4_4_live_messages, - descrId = R.string.v4_4_live_messages_desc + titleId = MR.strings.v4_4_live_messages, + descrId = MR.strings.v4_4_live_messages_desc ), FeatureDescription( icon = R.drawable.ic_verified_user, - titleId = R.string.v4_4_verify_connection_security, - descrId = R.string.v4_4_verify_connection_security_desc + titleId = MR.strings.v4_4_verify_connection_security, + descrId = MR.strings.v4_4_verify_connection_security_desc ), FeatureDescription( icon = R.drawable.ic_translate, - titleId = R.string.v4_4_french_interface, - descrId = R.string.v4_4_french_interface_descr + titleId = MR.strings.v4_4_french_interface, + descrId = MR.strings.v4_4_french_interface_descr ) ) ), @@ -246,34 +249,34 @@ private val versionDescriptions: List = listOf( features = listOf( FeatureDescription( icon = R.drawable.ic_manage_accounts, - titleId = R.string.v4_5_multiple_chat_profiles, - descrId = R.string.v4_5_multiple_chat_profiles_descr + titleId = MR.strings.v4_5_multiple_chat_profiles, + descrId = MR.strings.v4_5_multiple_chat_profiles_descr ), FeatureDescription( icon = R.drawable.ic_edit_note, - titleId = R.string.v4_5_message_draft, - descrId = R.string.v4_5_message_draft_descr + titleId = MR.strings.v4_5_message_draft, + descrId = MR.strings.v4_5_message_draft_descr ), FeatureDescription( icon = R.drawable.ic_safety_divider, - titleId = R.string.v4_5_transport_isolation, - descrId = R.string.v4_5_transport_isolation_descr, + titleId = MR.strings.v4_5_transport_isolation, + descrId = MR.strings.v4_5_transport_isolation_descr, link = "https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation" ), FeatureDescription( icon = R.drawable.ic_task, - titleId = R.string.v4_5_private_filenames, - descrId = R.string.v4_5_private_filenames_descr + titleId = MR.strings.v4_5_private_filenames, + descrId = MR.strings.v4_5_private_filenames_descr ), FeatureDescription( icon = R.drawable.ic_battery_2_bar, - titleId = R.string.v4_5_reduced_battery_usage, - descrId = R.string.v4_5_reduced_battery_usage_descr + titleId = MR.strings.v4_5_reduced_battery_usage, + descrId = MR.strings.v4_5_reduced_battery_usage_descr ), FeatureDescription( icon = R.drawable.ic_translate, - titleId = R.string.v4_5_italian_interface, - descrId = R.string.v4_5_italian_interface_descr, + titleId = MR.strings.v4_5_italian_interface, + descrId = MR.strings.v4_5_italian_interface_descr, link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat" ) ) @@ -284,33 +287,33 @@ private val versionDescriptions: List = listOf( features = listOf( FeatureDescription( icon = R.drawable.ic_lock, - titleId = R.string.v4_6_hidden_chat_profiles, - descrId = R.string.v4_6_hidden_chat_profiles_descr + titleId = MR.strings.v4_6_hidden_chat_profiles, + descrId = MR.strings.v4_6_hidden_chat_profiles_descr ), FeatureDescription( icon = R.drawable.ic_flag, - titleId = R.string.v4_6_group_moderation, - descrId = R.string.v4_6_group_moderation_descr + titleId = MR.strings.v4_6_group_moderation, + descrId = MR.strings.v4_6_group_moderation_descr ), FeatureDescription( icon = R.drawable.ic_maps_ugc, - titleId = R.string.v4_6_group_welcome_message, - descrId = R.string.v4_6_group_welcome_message_descr + titleId = MR.strings.v4_6_group_welcome_message, + descrId = MR.strings.v4_6_group_welcome_message_descr ), FeatureDescription( icon = R.drawable.ic_call, - titleId = R.string.v4_6_audio_video_calls, - descrId = R.string.v4_6_audio_video_calls_descr + titleId = MR.strings.v4_6_audio_video_calls, + descrId = MR.strings.v4_6_audio_video_calls_descr ), FeatureDescription( icon = R.drawable.ic_battery_3_bar, - titleId = R.string.v4_6_reduced_battery_usage, - descrId = R.string.v4_6_reduced_battery_usage_descr + titleId = MR.strings.v4_6_reduced_battery_usage, + descrId = MR.strings.v4_6_reduced_battery_usage_descr ), FeatureDescription( icon = R.drawable.ic_translate, - titleId = R.string.v4_6_chinese_spanish_interface, - descrId = R.string.v4_6_chinese_spanish_interface_descr, + titleId = MR.strings.v4_6_chinese_spanish_interface, + descrId = MR.strings.v4_6_chinese_spanish_interface_descr, link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat" ) ) @@ -321,18 +324,18 @@ private val versionDescriptions: List = listOf( features = listOf( FeatureDescription( icon = R.drawable.ic_upload_file, - titleId = R.string.v5_0_large_files_support, - descrId = R.string.v5_0_large_files_support_descr + titleId = MR.strings.v5_0_large_files_support, + descrId = MR.strings.v5_0_large_files_support_descr ), FeatureDescription( icon = R.drawable.ic_lock, - titleId = R.string.v5_0_app_passcode, - descrId = R.string.v5_0_app_passcode_descr + titleId = MR.strings.v5_0_app_passcode, + descrId = MR.strings.v5_0_app_passcode_descr ), FeatureDescription( icon = R.drawable.ic_translate, - titleId = R.string.v5_0_polish_interface, - descrId = R.string.v5_0_polish_interface_descr, + titleId = MR.strings.v5_0_polish_interface, + descrId = MR.strings.v5_0_polish_interface_descr, link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat" ) ) @@ -349,28 +352,28 @@ private val versionDescriptions: List = listOf( features = listOf( FeatureDescription( icon = R.drawable.ic_add_reaction, - titleId = R.string.v5_1_message_reactions, - descrId = R.string.v5_1_message_reactions_descr + titleId = MR.strings.v5_1_message_reactions, + descrId = MR.strings.v5_1_message_reactions_descr ), FeatureDescription( icon = R.drawable.ic_chat, - titleId = R.string.v5_1_better_messages, - descrId = R.string.v5_1_better_messages_descr + titleId = MR.strings.v5_1_better_messages, + descrId = MR.strings.v5_1_better_messages_descr ), FeatureDescription( icon = R.drawable.ic_light_mode, - titleId = R.string.v5_1_custom_themes, - descrId = R.string.v5_1_custom_themes_descr + titleId = MR.strings.v5_1_custom_themes, + descrId = MR.strings.v5_1_custom_themes_descr ), FeatureDescription( icon = R.drawable.ic_lock, - titleId = R.string.v5_1_self_destruct_passcode, - descrId = R.string.v5_1_self_destruct_passcode_descr + titleId = MR.strings.v5_1_self_destruct_passcode, + descrId = MR.strings.v5_1_self_destruct_passcode_descr ), FeatureDescription( icon = R.drawable.ic_translate, - titleId = R.string.v5_1_japanese_portuguese_interface, - descrId = R.string.whats_new_thanks_to_users_contribute_weblate, + titleId = MR.strings.v5_1_japanese_portuguese_interface, + descrId = MR.strings.whats_new_thanks_to_users_contribute_weblate, link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat" ) ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/AdvancedNetworkSettings.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/AdvancedNetworkSettings.kt index 044260ac83..2891861e8b 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/AdvancedNetworkSettings.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/AdvancedNetworkSettings.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -23,6 +23,7 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import java.text.DecimalFormat @Composable @@ -31,6 +32,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) { val currentCfgVal = currentCfg.value // used only on initialization val networkTCPConnectTimeout = remember { mutableStateOf(currentCfgVal.tcpConnectTimeout) } val networkTCPTimeout = remember { mutableStateOf(currentCfgVal.tcpTimeout) } + val networkTCPTimeoutPerKb = remember { mutableStateOf(currentCfgVal.tcpTimeoutPerKb) } val networkSMPPingInterval = remember { mutableStateOf(currentCfgVal.smpPingInterval) } val networkSMPPingCount = remember { mutableStateOf(currentCfgVal.smpPingCount) } val networkEnableKeepAlive = remember { mutableStateOf(currentCfgVal.enableKeepAlive) } @@ -64,6 +66,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) { sessionMode = currentCfg.value.sessionMode, tcpConnectTimeout = networkTCPConnectTimeout.value, tcpTimeout = networkTCPTimeout.value, + tcpTimeoutPerKb = networkTCPTimeoutPerKb.value, tcpKeepAlive = tcpKeepAlive, smpPingInterval = networkSMPPingInterval.value, smpPingCount = networkSMPPingCount.value @@ -73,6 +76,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) { fun updateView(cfg: NetCfg) { networkTCPConnectTimeout.value = cfg.tcpConnectTimeout networkTCPTimeout.value = cfg.tcpTimeout + networkTCPTimeoutPerKb.value = cfg.tcpTimeoutPerKb networkSMPPingInterval.value = cfg.smpPingInterval networkSMPPingCount.value = cfg.smpPingCount networkEnableKeepAlive.value = cfg.enableKeepAlive @@ -104,6 +108,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) { AdvancedNetworkSettingsLayout( networkTCPConnectTimeout, networkTCPTimeout, + networkTCPTimeoutPerKb, networkSMPPingInterval, networkSMPPingCount, networkEnableKeepAlive, @@ -121,6 +126,7 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) { @Composable fun AdvancedNetworkSettingsLayout( networkTCPConnectTimeout: MutableState, networkTCPTimeout: MutableState, + networkTCPTimeoutPerKb: MutableState, networkSMPPingInterval: MutableState, networkSMPPingCount: MutableState, networkEnableKeepAlive: MutableState, @@ -133,39 +139,45 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) { revert: () -> Unit, save: () -> Unit ) { - val secondsLabel = stringResource(R.string.network_option_seconds_label) + val secondsLabel = stringResource(MR.strings.network_option_seconds_label) Column( Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.network_settings_title)) + AppBarTitle(stringResource(MR.strings.network_settings_title)) SectionView { SectionItemView { ResetToDefaultsButton(reset, disabled = resetDisabled) } SectionItemView { TimeoutSettingRow( - stringResource(R.string.network_option_tcp_connection_timeout), networkTCPConnectTimeout, + stringResource(MR.strings.network_option_tcp_connection_timeout), networkTCPConnectTimeout, listOf(2_500000, 5_000000, 7_500000, 10_000000, 15_000000, 20_000000), secondsLabel ) } SectionItemView { TimeoutSettingRow( - stringResource(R.string.network_option_protocol_timeout), networkTCPTimeout, + stringResource(MR.strings.network_option_protocol_timeout), networkTCPTimeout, listOf(1_500000, 3_000000, 5_000000, 7_000000, 10_000000, 15_000000), secondsLabel ) } SectionItemView { TimeoutSettingRow( - stringResource(R.string.network_option_ping_interval), networkSMPPingInterval, + stringResource(MR.strings.network_option_protocol_timeout_per_kb), networkTCPTimeoutPerKb, + listOf(5_000, 10_000, 20_000, 40_000), secondsLabel + ) + } + SectionItemView { + TimeoutSettingRow( + stringResource(MR.strings.network_option_ping_interval), networkSMPPingInterval, listOf(120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000), secondsLabel ) } SectionItemView { IntSettingRow( - stringResource(R.string.network_option_ping_count), networkSMPPingCount, + stringResource(MR.strings.network_option_ping_count), networkSMPPingCount, listOf(1, 2, 3, 5, 8), "" ) } @@ -209,7 +221,7 @@ fun ResetToDefaultsButton(reset: () -> Unit, disabled: Boolean) { verticalAlignment = Alignment.CenterVertically ) { val color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary - Text(stringResource(R.string.network_options_reset_to_defaults), color = color) + Text(stringResource(MR.strings.network_options_reset_to_defaults), color = color) } } @@ -222,7 +234,7 @@ fun EnableKeepAliveSwitch( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { - Text(stringResource(R.string.network_option_enable_tcp_keep_alive)) + Text(stringResource(MR.strings.network_option_enable_tcp_keep_alive)) DefaultSwitch( checked = networkEnableKeepAlive.value, onCheckedChange = { networkEnableKeepAlive.value = it }, @@ -261,7 +273,7 @@ fun IntSettingRow(title: String, selection: MutableState, values: List Spacer(Modifier.size(4.dp)) Icon( if (!expanded.value) painterResource(R.drawable.ic_expand_more) else painterResource(R.drawable.ic_expand_less), - generalGetString(R.string.invite_to_group_button), + generalGetString(MR.strings.invite_to_group_button), modifier = Modifier.padding(start = 8.dp), tint = MaterialTheme.colors.secondary ) @@ -306,15 +318,14 @@ fun TimeoutSettingRow(title: String, selection: MutableState, values: List expanded.value = !expanded.value } ) { - val df = DecimalFormat("#.#") - + val df = DecimalFormat("#.###") Row( Modifier.width(140.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ) { Text( - "${df.format(selection.value / 1_000_000.toDouble())} $label", + "${df.format(selection.value / 1_000_000.0)} $label", maxLines = 1, overflow = TextOverflow.Ellipsis, color = MaterialTheme.colors.secondary @@ -322,7 +333,7 @@ fun TimeoutSettingRow(title: String, selection: MutableState, values: List Spacer(Modifier.size(4.dp)) Icon( if (!expanded.value) painterResource(R.drawable.ic_expand_more) else painterResource(R.drawable.ic_expand_less), - generalGetString(R.string.invite_to_group_button), + generalGetString(MR.strings.invite_to_group_button), modifier = Modifier.padding(start = 8.dp), tint = MaterialTheme.colors.secondary ) @@ -339,7 +350,7 @@ fun TimeoutSettingRow(title: String, selection: MutableState, values: List contentPadding = PaddingValues(horizontal = DEFAULT_PADDING * 1.5f) ) { Text( - "${df.format(selectionOption / 1_000_000.toDouble())} $label", + "${df.format(selectionOption / 1_000_000.0)} $label", maxLines = 1, overflow = TextOverflow.Ellipsis, ) @@ -357,8 +368,8 @@ fun SettingsSectionFooter(revert: () -> Unit, save: () -> Unit, disabled: Boolea horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - FooterButton(painterResource(R.drawable.ic_replay), stringResource(R.string.network_options_revert), revert, disabled) - FooterButton(painterResource(R.drawable.ic_check), stringResource(R.string.network_options_save), save, disabled) + FooterButton(painterResource(R.drawable.ic_replay), stringResource(MR.strings.network_options_revert), revert, disabled) + FooterButton(painterResource(R.drawable.ic_check), stringResource(MR.strings.network_options_save), save, disabled) } } @@ -388,9 +399,9 @@ fun FooterButton(icon: Painter, title: String, action: () -> Unit, disabled: Boo fun showUpdateNetworkSettingsDialog(action: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.update_network_settings_question), - text = generalGetString(R.string.updating_settings_will_reconnect_client_to_all_servers), - confirmText = generalGetString(R.string.update_network_settings_confirmation), + title = generalGetString(MR.strings.update_network_settings_question), + text = generalGetString(MR.strings.updating_settings_will_reconnect_client_to_all_servers), + confirmText = generalGetString(MR.strings.update_network_settings_confirmation), onConfirm = action ) } @@ -402,6 +413,7 @@ fun PreviewAdvancedNetworkSettingsLayout() { AdvancedNetworkSettingsLayout( networkTCPConnectTimeout = remember { mutableStateOf(10_000000) }, networkTCPTimeout = remember { mutableStateOf(10_000000) }, + networkTCPTimeoutPerKb = remember { mutableStateOf(10_000) }, networkSMPPingInterval = remember { mutableStateOf(10_000000) }, networkSMPPingCount = remember { mutableStateOf(3) }, networkEnableKeepAlive = remember { mutableStateOf(true) }, diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Appearance.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Appearance.kt index 5233192e2d..5047818ba3 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Appearance.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Appearance.kt @@ -32,7 +32,7 @@ import androidx.compose.ui.graphics.* import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat @@ -43,6 +43,7 @@ import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import com.godaddy.android.colorpicker.* +import chat.simplex.res.MR import kotlinx.coroutines.delay import kotlinx.serialization.encodeToString import java.io.BufferedOutputStream @@ -100,14 +101,14 @@ fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) -> Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.appearance_settings)) - SectionView(stringResource(R.string.settings_section_title_language), padding = PaddingValues()) { + AppBarTitle(stringResource(MR.strings.appearance_settings)) + SectionView(stringResource(MR.strings.settings_section_title_language), padding = PaddingValues()) { val context = LocalContext.current // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // SectionItemWithValue( -// generalGetString(R.string.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() }, +// generalGetString(MR.strings.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() }, // remember { mutableStateOf("system") }, -// listOf(ValueTitleDesc("system", generalGetString(R.string.change_verb), "")), +// listOf(ValueTitleDesc("system", generalGetString(MR.strings.change_verb), "")), // onSelected = { openSystemLangPicker(context as? Activity ?: return@SectionItemWithValue) } // ) // } else { @@ -130,7 +131,7 @@ fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) -> } SectionDividerSpaced() - SectionView(stringResource(R.string.settings_section_title_icon), padding = PaddingValues(horizontal = DEFAULT_PADDING_HALF)) { + SectionView(stringResource(MR.strings.settings_section_title_icon), padding = PaddingValues(horizontal = DEFAULT_PADDING_HALF)) { LazyRow { items(AppIcon.values().size, { index -> AppIcon.values()[index] }) { index -> val item = AppIcon.values()[index] @@ -155,7 +156,7 @@ fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) -> SectionDividerSpaced(maxTopPadding = true) val currentTheme by CurrentColors.collectAsState() - SectionView(stringResource(R.string.settings_section_title_themes)) { + SectionView(stringResource(MR.strings.settings_section_title_themes)) { val darkTheme = isSystemInDarkTheme() val state = remember { derivedStateOf { currentTheme.name } } ThemeSelector(state) { @@ -167,7 +168,7 @@ fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) -> } } } - SectionItemView(showSettingsModal { _ -> CustomizeThemeView(editColor) }) { Text(stringResource(R.string.customize_theme_title)) } + SectionItemView(showSettingsModal { _ -> CustomizeThemeView(editColor) }) { Text(stringResource(MR.strings.customize_theme_title)) } SectionBottomSpacer() } } @@ -179,51 +180,51 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) { ) { val currentTheme by CurrentColors.collectAsState() - AppBarTitle(stringResource(R.string.customize_theme_title)) + AppBarTitle(stringResource(MR.strings.customize_theme_title)) - SectionView(stringResource(R.string.theme_colors_section_title)) { + SectionView(stringResource(MR.strings.theme_colors_section_title)) { SectionItemViewSpaceBetween({ editColor(ThemeColor.PRIMARY, currentTheme.colors.primary) }) { - val title = generalGetString(R.string.color_primary) + val title = generalGetString(MR.strings.color_primary) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.primary) } SectionItemViewSpaceBetween({ editColor(ThemeColor.PRIMARY_VARIANT, currentTheme.colors.primaryVariant) }) { - val title = generalGetString(R.string.color_primary_variant) + val title = generalGetString(MR.strings.color_primary_variant) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.primaryVariant) } SectionItemViewSpaceBetween({ editColor(ThemeColor.SECONDARY, currentTheme.colors.secondary) }) { - val title = generalGetString(R.string.color_secondary) + val title = generalGetString(MR.strings.color_secondary) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.secondary) } SectionItemViewSpaceBetween({ editColor(ThemeColor.SECONDARY_VARIANT, currentTheme.colors.secondaryVariant) }) { - val title = generalGetString(R.string.color_secondary_variant) + val title = generalGetString(MR.strings.color_secondary_variant) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.secondaryVariant) } SectionItemViewSpaceBetween({ editColor(ThemeColor.BACKGROUND, currentTheme.colors.background) }) { - val title = generalGetString(R.string.color_background) + val title = generalGetString(MR.strings.color_background) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.background) } SectionItemViewSpaceBetween({ editColor(ThemeColor.SURFACE, currentTheme.colors.surface) }) { - val title = generalGetString(R.string.color_surface) + val title = generalGetString(MR.strings.color_surface) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.surface) } SectionItemViewSpaceBetween({ editColor(ThemeColor.TITLE, currentTheme.appColors.title) }) { - val title = generalGetString(R.string.color_title) + val title = generalGetString(MR.strings.color_title) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = currentTheme.appColors.title) } SectionItemViewSpaceBetween({ editColor(ThemeColor.SENT_MESSAGE, currentTheme.appColors.sentMessage) }) { - val title = generalGetString(R.string.color_sent_message) + val title = generalGetString(MR.strings.color_sent_message) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = currentTheme.appColors.sentMessage) } SectionItemViewSpaceBetween({ editColor(ThemeColor.RECEIVED_MESSAGE, currentTheme.appColors.receivedMessage) }) { - val title = generalGetString(R.string.color_received_message) + val title = generalGetString(MR.strings.color_received_message) Text(title) Icon(painterResource(R.drawable.ic_circle_filled), title, tint = currentTheme.appColors.receivedMessage) } @@ -231,7 +232,7 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) { val isInDarkTheme = isInDarkTheme() if (currentTheme.base.hasChangedAnyColor(currentTheme.colors, currentTheme.appColors)) { SectionItemView({ ThemeManager.resetAllThemeColors(darkForSystemTheme = isInDarkTheme) }) { - Text(generalGetString(R.string.reset_color), color = colors.primary) + Text(generalGetString(MR.strings.reset_color), color = colors.primary) } } SectionSpacer() @@ -243,7 +244,7 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) { theme.value = yaml.encodeToString(overrides) exportThemeLauncher.launch("simplex.theme") }) { - Text(generalGetString(R.string.export_theme), color = colors.primary) + Text(generalGetString(MR.strings.export_theme), color = colors.primary) } val importThemeLauncher = rememberGetContentLauncher { uri: Uri? -> @@ -256,7 +257,7 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) { } // Can not limit to YAML mime type since it's unsupported by Android SectionItemView({ importThemeLauncher.launch("*/*") }) { - Text(generalGetString(R.string.import_theme), color = colors.primary) + Text(generalGetString(MR.strings.import_theme), color = colors.primary) } } SectionBottomSpacer() @@ -289,7 +290,7 @@ fun ColorEditor( Modifier.align(Alignment.CenterHorizontally), colors = ButtonDefaults.textButtonColors(contentColor = currentColor) ) { - Text(generalGetString(R.string.save_color)) + Text(generalGetString(MR.strings.save_color)) } } } @@ -312,7 +313,7 @@ fun ColorPicker(initialColor: Color, onColorChanged: (Color) -> Unit) { private fun LangSelector(state: State, onSelected: (String) -> Unit) { // Should be the same as in app/build.gradle's `android.defaultConfig.resConfigs` val supportedLanguages = mapOf( - "system" to generalGetString(R.string.language_system), + "system" to generalGetString(MR.strings.language_system), "en" to "English", "cs" to "Čeština", "de" to "Deutsch", @@ -328,7 +329,7 @@ private fun LangSelector(state: State, onSelected: (String) -> Unit) { ) val values by remember { mutableStateOf(supportedLanguages.map { it.key to it.value }) } ExposedDropDownSettingRow( - generalGetString(R.string.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() }, + generalGetString(MR.strings.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() }, values, state, icon = null, @@ -342,7 +343,7 @@ private fun ThemeSelector(state: State, onSelected: (String) -> Unit) { val darkTheme = isSystemInDarkTheme() val values by remember { mutableStateOf(ThemeManager.allThemes(darkTheme).map { it.second.name to it.third }) } ExposedDropDownSettingRow( - generalGetString(R.string.theme), + generalGetString(MR.strings.theme), values, state, icon = null, @@ -355,12 +356,12 @@ private fun ThemeSelector(state: State, onSelected: (String) -> Unit) { private fun DarkThemeSelector(state: State, onSelected: (String) -> Unit) { val values by remember { val darkThemes = ArrayList>() - darkThemes.add(DefaultTheme.DARK.name to generalGetString(R.string.theme_dark)) - darkThemes.add(DefaultTheme.SIMPLEX.name to generalGetString(R.string.theme_simplex)) + darkThemes.add(DefaultTheme.DARK.name to generalGetString(MR.strings.theme_dark)) + darkThemes.add(DefaultTheme.SIMPLEX.name to generalGetString(MR.strings.theme_simplex)) mutableStateOf(darkThemes.toList()) } ExposedDropDownSettingRow( - generalGetString(R.string.dark_theme), + generalGetString(MR.strings.dark_theme), values, state, icon = null, @@ -388,12 +389,12 @@ private fun rememberSaveThemeLauncher(theme: MutableState): ManagedActi BufferedOutputStream(stream).use { outputStream -> theme.byteInputStream().use { it.copyTo(outputStream) } } - Toast.makeText(cxt, generalGetString(R.string.file_saved), Toast.LENGTH_SHORT).show() + Toast.makeText(cxt, generalGetString(MR.strings.file_saved), Toast.LENGTH_SHORT).show() } } } } catch (e: Error) { - Toast.makeText(cxt, generalGetString(R.string.error_saving_file), Toast.LENGTH_SHORT).show() + Toast.makeText(cxt, generalGetString(MR.strings.error_saving_file), Toast.LENGTH_SHORT).show() Log.e(TAG, "rememberSaveThemeLauncher error saving theme $e") } finally { theme.value = null diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt index ae38a01520..38d6a88eb8 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt @@ -12,11 +12,12 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun CallSettingsView(m: ChatModel, @@ -39,20 +40,20 @@ fun CallSettingsLayout( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - AppBarTitle(stringResource(R.string.your_calls)) + AppBarTitle(stringResource(MR.strings.your_calls)) val lockCallState = remember { mutableStateOf(callOnLockScreen.get()) } - SectionView(stringResource(R.string.settings_section_title_settings)) { - SectionItemView(editIceServers) { Text(stringResource(R.string.webrtc_ice_servers)) } + SectionView(stringResource(MR.strings.settings_section_title_settings)) { + SectionItemView(editIceServers) { Text(stringResource(MR.strings.webrtc_ice_servers)) } val enabled = remember { mutableStateOf(true) } LockscreenOpts(lockCallState, enabled, onSelected = { callOnLockScreen.set(it); lockCallState.value = it }) - SettingsPreferenceItem(null, stringResource(R.string.always_use_relay), webrtcPolicyRelay) + SettingsPreferenceItem(null, stringResource(MR.strings.always_use_relay), webrtcPolicyRelay) } SectionTextFooter( if (remember { webrtcPolicyRelay.state }.value) { - generalGetString(R.string.relay_server_protects_ip) + generalGetString(MR.strings.relay_server_protects_ip) } else { - generalGetString(R.string.relay_server_if_necessary) + generalGetString(MR.strings.relay_server_if_necessary) } ) SectionBottomSpacer() @@ -64,14 +65,14 @@ private fun LockscreenOpts(lockscreenOpts: State, enabled: Sta val values = remember { CallOnLockScreen.values().map { when (it) { - CallOnLockScreen.DISABLE -> it to generalGetString(R.string.no_call_on_lock_screen) - CallOnLockScreen.SHOW -> it to generalGetString(R.string.show_call_on_lock_screen) - CallOnLockScreen.ACCEPT -> it to generalGetString(R.string.accept_call_on_lock_screen) + CallOnLockScreen.DISABLE -> it to generalGetString(MR.strings.no_call_on_lock_screen) + CallOnLockScreen.SHOW -> it to generalGetString(MR.strings.show_call_on_lock_screen) + CallOnLockScreen.ACCEPT -> it to generalGetString(MR.strings.accept_call_on_lock_screen) } } } ExposedDropDownSettingRow( - generalGetString(R.string.call_on_lock_screen), + generalGetString(MR.strings.call_on_lock_screen), values, lockscreenOpts, icon = null, diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Cryptor.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Cryptor.kt index 1c0412cfd9..1099b2fb2d 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Cryptor.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Cryptor.kt @@ -8,6 +8,7 @@ import chat.simplex.app.R import chat.simplex.app.TAG import chat.simplex.app.views.helpers.AlertManager import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR import java.security.KeyStore import javax.crypto.* import javax.crypto.spec.GCMParameterSpec @@ -24,8 +25,8 @@ internal class Cryptor { // Repeated calls will not show the alert again warningShown = true AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.wrong_passphrase), - text = generalGetString(R.string.restore_passphrase_not_found_desc) + title = generalGetString(MR.strings.wrong_passphrase), + text = generalGetString(MR.strings.restore_passphrase_not_found_desc) ) } return null diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/DeveloperView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/DeveloperView.kt index 6a79b807de..5a566ac480 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/DeveloperView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/DeveloperView.kt @@ -11,11 +11,12 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.R import chat.simplex.app.model.ChatModel import chat.simplex.app.views.TerminalView import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun DeveloperView( @@ -25,18 +26,18 @@ fun DeveloperView( ) { Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) { val uriHandler = LocalUriHandler.current - AppBarTitle(stringResource(R.string.settings_developer_tools)) + AppBarTitle(stringResource(MR.strings.settings_developer_tools)) val developerTools = m.controller.appPrefs.developerTools val devTools = remember { developerTools.state } SectionView() { InstallTerminalAppItem(uriHandler) - ChatConsoleItem { withAuth(generalGetString(R.string.auth_open_chat_console), generalGetString(R.string.auth_log_in_using_credential), showCustomModal { it, close -> TerminalView(it, close) })} - SettingsPreferenceItem(painterResource(R.drawable.ic_drive_folder_upload), stringResource(R.string.confirm_database_upgrades), m.controller.appPrefs.confirmDBUpgrades) - SettingsPreferenceItem(painterResource(R.drawable.ic_code), stringResource(R.string.show_developer_options), developerTools) + ChatConsoleItem { withAuth(generalGetString(MR.strings.auth_open_chat_console), generalGetString(MR.strings.auth_log_in_using_credential), showCustomModal { it, close -> TerminalView(it, close) })} + SettingsPreferenceItem(painterResource(R.drawable.ic_drive_folder_upload), stringResource(MR.strings.confirm_database_upgrades), m.controller.appPrefs.confirmDBUpgrades) + SettingsPreferenceItem(painterResource(R.drawable.ic_code), stringResource(MR.strings.show_developer_options), developerTools) } SectionTextFooter( - generalGetString(if (devTools.value) R.string.show_dev_options else R.string.hide_dev_options) + " " + - generalGetString(R.string.developer_options) + generalGetString(if (devTools.value) MR.strings.show_dev_options else MR.strings.hide_dev_options) + " " + + generalGetString(MR.strings.developer_options) ) SectionBottomSpacer() } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/HelpView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/HelpView.kt index 79f0ed3348..2a736bf38a 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/HelpView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/HelpView.kt @@ -7,13 +7,14 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import chat.simplex.app.R import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.chatlist.ChatHelpView import chat.simplex.app.views.helpers.AppBarTitle +import chat.simplex.res.MR @Composable fun HelpView(userDisplayName: String) { @@ -28,7 +29,7 @@ fun HelpLayout(userDisplayName: String) { .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING), ){ - AppBarTitle(String.format(stringResource(R.string.personal_welcome), userDisplayName), false) + AppBarTitle(String.format(stringResource(MR.strings.personal_welcome), userDisplayName), false) ChatHelpView() } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/HiddenProfileView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/HiddenProfileView.kt index 676cbd3600..8c266b8975 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/HiddenProfileView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/HiddenProfileView.kt @@ -13,7 +13,7 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.ChatModel @@ -22,6 +22,7 @@ import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chatlist.UserProfileRow import chat.simplex.app.views.database.PassphraseField import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun HiddenProfileView( @@ -39,7 +40,7 @@ fun HiddenProfileView( close() } catch (e: Exception) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.error_saving_user_password), + title = generalGetString(MR.strings.error_saving_user_password), text = e.stackTraceToString() ) } @@ -58,7 +59,7 @@ private fun HiddenProfileLayout( .fillMaxWidth() .verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.hide_profile)) + AppBarTitle(stringResource(MR.strings.hide_profile)) SectionView(padding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) { UserProfileRow(user) } @@ -69,18 +70,18 @@ private fun HiddenProfileLayout( val passwordValid by remember { derivedStateOf { hidePassword.value == hidePassword.value.trim() } } val confirmValid by remember { derivedStateOf { confirmHidePassword.value == "" || hidePassword.value == confirmHidePassword.value } } val saveDisabled by remember { derivedStateOf { hidePassword.value == "" || !passwordValid || confirmHidePassword.value == "" || !confirmValid } } - SectionView(stringResource(R.string.hidden_profile_password).uppercase()) { + SectionView(stringResource(MR.strings.hidden_profile_password).uppercase()) { SectionItemView { - PassphraseField(hidePassword, generalGetString(R.string.password_to_show), isValid = { passwordValid }, showStrength = true) + PassphraseField(hidePassword, generalGetString(MR.strings.password_to_show), isValid = { passwordValid }, showStrength = true) } SectionItemView { - PassphraseField(confirmHidePassword, stringResource(R.string.confirm_password), isValid = { confirmValid }, dependsOn = hidePassword) + PassphraseField(confirmHidePassword, stringResource(MR.strings.confirm_password), isValid = { confirmValid }, dependsOn = hidePassword) } SectionItemViewSpaceBetween({ saveProfilePassword(hidePassword.value) }, disabled = saveDisabled, minHeight = TextFieldDefaults.MinHeight) { - Text(generalGetString(R.string.save_profile_password), color = if (saveDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(generalGetString(MR.strings.save_profile_password), color = if (saveDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } } - SectionTextFooter(stringResource(R.string.to_reveal_profile_enter_password)) + SectionTextFooter(stringResource(MR.strings.to_reveal_profile_enter_password)) SectionBottomSpacer() } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/IncognitoView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/IncognitoView.kt index e138805270..b7aeb0a802 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/IncognitoView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/IncognitoView.kt @@ -6,12 +6,13 @@ import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.views.helpers.AppBarTitle import chat.simplex.app.views.helpers.generalGetString +import chat.simplex.res.MR @Composable fun IncognitoView() { @@ -21,17 +22,17 @@ fun IncognitoView() { @Composable fun IncognitoLayout() { Column { - AppBarTitle(stringResource(R.string.settings_section_title_incognito)) + AppBarTitle(stringResource(MR.strings.settings_section_title_incognito)) Column( Modifier .verticalScroll(rememberScrollState()) .padding(horizontal = DEFAULT_PADDING), verticalArrangement = Arrangement.spacedBy(20.dp) ) { - Text(generalGetString(R.string.incognito_info_protects)) - Text(generalGetString(R.string.incognito_info_allows)) - Text(generalGetString(R.string.incognito_info_share)) - Text(generalGetString(R.string.incognito_info_find)) + Text(generalGetString(MR.strings.incognito_info_protects)) + Text(generalGetString(MR.strings.incognito_info_allows)) + Text(generalGetString(MR.strings.incognito_info_share)) + Text(generalGetString(MR.strings.incognito_info_find)) SectionBottomSpacer() } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/MarkdownHelpView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/MarkdownHelpView.kt index eb9ab5a0ea..aa405ef15c 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/MarkdownHelpView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/MarkdownHelpView.kt @@ -9,7 +9,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -18,6 +18,7 @@ import chat.simplex.app.model.Format import chat.simplex.app.model.FormatColor import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.ui.theme.SimpleXTheme +import chat.simplex.res.MR @Composable fun MarkdownHelpView() { @@ -25,14 +26,14 @@ fun MarkdownHelpView() { Modifier .fillMaxWidth() ) { - Text(stringResource(R.string.you_can_use_markdown_to_format_messages__prompt)) + Text(stringResource(MR.strings.you_can_use_markdown_to_format_messages__prompt)) Spacer(Modifier.height(DEFAULT_PADDING)) - val bold = stringResource(R.string.bold) - val italic = stringResource(R.string.italic) - val strikethrough = stringResource(R.string.strikethrough) - val equation = stringResource(R.string.a_plus_b) - val colored = stringResource(R.string.colored) - val secret = stringResource(R.string.secret) + val bold = stringResource(MR.strings.bold_text) + val italic = stringResource(MR.strings.italic_text) + val strikethrough = stringResource(MR.strings.strikethrough_text) + val equation = stringResource(MR.strings.a_plus_b) + val colored = stringResource(MR.strings.colored_text) + val secret = stringResource(MR.strings.secret_text) MdFormat("*$bold*", bold, Format.Bold()) MdFormat("_${italic}_", italic, Format.Italic()) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/NetworkAndServers.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/NetworkAndServers.kt index 47c926cdd7..da055fcbee 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/NetworkAndServers.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/NetworkAndServers.kt @@ -16,7 +16,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily @@ -29,6 +29,7 @@ import chat.simplex.app.model.* import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.item.ClickableText import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun NetworkAndServersView( @@ -61,9 +62,9 @@ fun NetworkAndServersView( toggleSocksProxy = { enable -> if (enable) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.network_enable_socks), - text = generalGetString(R.string.network_enable_socks_info).format(proxyPort.value), - confirmText = generalGetString(R.string.confirm_verb), + title = generalGetString(MR.strings.network_enable_socks), + text = generalGetString(MR.strings.network_enable_socks_info).format(proxyPort.value), + confirmText = generalGetString(MR.strings.confirm_verb), onConfirm = { withApi { val conf = NetCfg.proxyDefaults.withHostPort(chatModel.controller.appPrefs.networkProxyHostPort.get()) @@ -76,9 +77,9 @@ fun NetworkAndServersView( ) } else { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.network_disable_socks), - text = generalGetString(R.string.network_disable_socks_info), - confirmText = generalGetString(R.string.confirm_verb), + title = generalGetString(MR.strings.network_disable_socks), + text = generalGetString(MR.strings.network_disable_socks_info), + confirmText = generalGetString(MR.strings.confirm_verb), onConfirm = { withApi { val conf = NetCfg.defaults @@ -96,12 +97,12 @@ fun NetworkAndServersView( val prevValue = onionHosts.value onionHosts.value = it val startsWith = when (it) { - OnionHosts.NEVER -> generalGetString(R.string.network_use_onion_hosts_no_desc_in_alert) - OnionHosts.PREFER -> generalGetString(R.string.network_use_onion_hosts_prefer_desc_in_alert) - OnionHosts.REQUIRED -> generalGetString(R.string.network_use_onion_hosts_required_desc_in_alert) + OnionHosts.NEVER -> generalGetString(MR.strings.network_use_onion_hosts_no_desc_in_alert) + OnionHosts.PREFER -> generalGetString(MR.strings.network_use_onion_hosts_prefer_desc_in_alert) + OnionHosts.REQUIRED -> generalGetString(MR.strings.network_use_onion_hosts_required_desc_in_alert) } showUpdateNetworkSettingsDialog( - title = generalGetString(R.string.update_onion_hosts_settings_question), + title = generalGetString(MR.strings.update_onion_hosts_settings_question), startsWith, onDismiss = { onionHosts.value = prevValue @@ -124,11 +125,11 @@ fun NetworkAndServersView( val prevValue = sessionMode.value sessionMode.value = it val startsWith = when (it) { - TransportSessionMode.User -> generalGetString(R.string.network_session_mode_user_description) - TransportSessionMode.Entity -> generalGetString(R.string.network_session_mode_entity_description) + TransportSessionMode.User -> generalGetString(MR.strings.network_session_mode_user_description) + TransportSessionMode.Entity -> generalGetString(MR.strings.network_session_mode_entity_description) } showUpdateNetworkSettingsDialog( - title = generalGetString(R.string.update_network_session_mode_question), + title = generalGetString(MR.strings.update_network_session_mode_question), startsWith, onDismiss = { sessionMode.value = prevValue } ) { @@ -164,28 +165,28 @@ fun NetworkAndServersView( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - AppBarTitle(stringResource(R.string.network_and_servers)) - SectionView(generalGetString(R.string.settings_section_title_messages)) { - SettingsActionItem(painterResource(R.drawable.ic_dns), stringResource(R.string.smp_servers), showCustomModal { m, close -> ProtocolServersView(m, ServerProtocol.SMP, close) }) + AppBarTitle(stringResource(MR.strings.network_and_servers)) + SectionView(generalGetString(MR.strings.settings_section_title_messages)) { + SettingsActionItem(painterResource(R.drawable.ic_dns), stringResource(MR.strings.smp_servers), showCustomModal { m, close -> ProtocolServersView(m, ServerProtocol.SMP, close) }) - SettingsActionItem(painterResource(R.drawable.ic_dns), stringResource(R.string.xftp_servers), showCustomModal { m, close -> ProtocolServersView(m, ServerProtocol.XFTP, close) }) + SettingsActionItem(painterResource(R.drawable.ic_dns), stringResource(MR.strings.xftp_servers), showCustomModal { m, close -> ProtocolServersView(m, ServerProtocol.XFTP, close) }) UseSocksProxySwitch(networkUseSocksProxy, proxyPort, toggleSocksProxy, showSettingsModal) UseOnionHosts(onionHosts, networkUseSocksProxy, showSettingsModal, useOnion) if (developerTools) { SessionModePicker(sessionMode, showSettingsModal, updateSessionMode) } - SettingsActionItem(painterResource(R.drawable.ic_cable), stringResource(R.string.network_settings), showSettingsModal { AdvancedNetworkSettingsView(it) }) + SettingsActionItem(painterResource(R.drawable.ic_cable), stringResource(MR.strings.network_settings), showSettingsModal { AdvancedNetworkSettingsView(it) }) } if (networkUseSocksProxy.value) { - SectionCustomFooter { Text(annotatedStringResource(R.string.disable_onion_hosts_when_not_supported)) } + SectionCustomFooter { Text(annotatedStringResource(MR.strings.disable_onion_hosts_when_not_supported)) } Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 32.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp)) } else { Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 24.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp)) } - SectionView(generalGetString(R.string.settings_section_title_calls)) { - SettingsActionItem(painterResource(R.drawable.ic_electrical_services), stringResource(R.string.webrtc_ice_servers), showModal { RTCServersView(it) }) + SectionView(generalGetString(MR.strings.settings_section_title_calls)) { + SettingsActionItem(painterResource(R.drawable.ic_electrical_services), stringResource(MR.strings.webrtc_ice_servers), showModal { RTCServersView(it) }) } SectionBottomSpacer() } @@ -209,15 +210,15 @@ fun UseSocksProxySwitch( ) { Icon( painterResource(R.drawable.ic_settings_ethernet), - stringResource(R.string.network_socks_toggle_use_socks_proxy), + stringResource(MR.strings.network_socks_toggle_use_socks_proxy), tint = MaterialTheme.colors.secondary ) TextIconSpaced(false) val text = buildAnnotatedString { - append(generalGetString(R.string.network_socks_toggle_use_socks_proxy) + " (") + append(generalGetString(MR.strings.network_socks_toggle_use_socks_proxy) + " (") val style = SpanStyle(color = MaterialTheme.colors.primary) - withAnnotation(tag = "PORT", annotation = generalGetString(R.string.network_proxy_port).format(proxyPort.value)) { - withStyle(style) { append(generalGetString(R.string.network_proxy_port).format(proxyPort.value)) } + withAnnotation(tag = "PORT", annotation = generalGetString(MR.strings.network_proxy_port).format(proxyPort.value)) { + withStyle(style) { append(generalGetString(MR.strings.network_proxy_port).format(proxyPort.value)) } } append(")") } @@ -250,7 +251,7 @@ fun SockProxySettings(m: ChatModel) { .verticalScroll(rememberScrollState()) ) { val defaultHostPort = remember { "localhost:9050" } - AppBarTitle(generalGetString(R.string.network_socks_proxy_settings)) + AppBarTitle(generalGetString(MR.strings.network_socks_proxy_settings)) val hostPort by remember { m.controller.appPrefs.networkProxyHostPort.state } val hostUnsaved = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue(hostPort?.split(":")?.firstOrNull() ?: "localhost")) @@ -289,7 +290,7 @@ fun SockProxySettings(m: ChatModel) { SectionItemView { DefaultConfigurableTextField( hostUnsaved, - stringResource(R.string.host_verb), + stringResource(MR.strings.host_verb), modifier = Modifier, isValid = ::validHost, keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), @@ -299,7 +300,7 @@ fun SockProxySettings(m: ChatModel) { SectionItemView { DefaultConfigurableTextField( portUnsaved, - stringResource(R.string.port_verb), + stringResource(MR.strings.port_verb), modifier = Modifier, isValid = ::validPort, keyboardActions = KeyboardActions(onDone = { defaultKeyboardAction(ImeAction.Done); save() }), @@ -336,9 +337,9 @@ private fun UseOnionHosts( val values = remember { OnionHosts.values().map { when (it) { - OnionHosts.NEVER -> ValueTitleDesc(OnionHosts.NEVER, generalGetString(R.string.network_use_onion_hosts_no), generalGetString(R.string.network_use_onion_hosts_no_desc)) - OnionHosts.PREFER -> ValueTitleDesc(OnionHosts.PREFER, generalGetString(R.string.network_use_onion_hosts_prefer), generalGetString(R.string.network_use_onion_hosts_prefer_desc)) - OnionHosts.REQUIRED -> ValueTitleDesc(OnionHosts.REQUIRED, generalGetString(R.string.network_use_onion_hosts_required), generalGetString(R.string.network_use_onion_hosts_required_desc)) + OnionHosts.NEVER -> ValueTitleDesc(OnionHosts.NEVER, generalGetString(MR.strings.network_use_onion_hosts_no), generalGetString(MR.strings.network_use_onion_hosts_no_desc)) + OnionHosts.PREFER -> ValueTitleDesc(OnionHosts.PREFER, generalGetString(MR.strings.network_use_onion_hosts_prefer), generalGetString(MR.strings.network_use_onion_hosts_prefer_desc)) + OnionHosts.REQUIRED -> ValueTitleDesc(OnionHosts.REQUIRED, generalGetString(MR.strings.network_use_onion_hosts_required), generalGetString(MR.strings.network_use_onion_hosts_required_desc)) } } } @@ -346,13 +347,13 @@ private fun UseOnionHosts( Column( Modifier.fillMaxWidth(), ) { - AppBarTitle(stringResource(R.string.network_use_onion_hosts)) + AppBarTitle(stringResource(MR.strings.network_use_onion_hosts)) SectionViewSelectable(null, onionHosts, values, useOnion) } } SectionItemWithValue( - generalGetString(R.string.network_use_onion_hosts), + generalGetString(MR.strings.network_use_onion_hosts), onionHosts, values, icon = painterResource(R.drawable.ic_security), @@ -370,14 +371,14 @@ private fun SessionModePicker( val values = remember { TransportSessionMode.values().map { when (it) { - TransportSessionMode.User -> ValueTitleDesc(TransportSessionMode.User, generalGetString(R.string.network_session_mode_user), generalGetString(R.string.network_session_mode_user_description)) - TransportSessionMode.Entity -> ValueTitleDesc(TransportSessionMode.Entity, generalGetString(R.string.network_session_mode_entity), generalGetString(R.string.network_session_mode_entity_description)) + TransportSessionMode.User -> ValueTitleDesc(TransportSessionMode.User, generalGetString(MR.strings.network_session_mode_user), generalGetString(MR.strings.network_session_mode_user_description)) + TransportSessionMode.Entity -> ValueTitleDesc(TransportSessionMode.Entity, generalGetString(MR.strings.network_session_mode_entity), generalGetString(MR.strings.network_session_mode_entity_description)) } } } SectionItemWithValue( - generalGetString(R.string.network_session_mode_transport_isolation), + generalGetString(MR.strings.network_session_mode_transport_isolation), sessionMode, values, icon = painterResource(R.drawable.ic_safety_divider), @@ -385,7 +386,7 @@ private fun SessionModePicker( Column( Modifier.fillMaxWidth(), ) { - AppBarTitle(stringResource(R.string.network_session_mode_transport_isolation)) + AppBarTitle(stringResource(MR.strings.network_session_mode_transport_isolation)) SectionViewSelectable(null, sessionMode, values, updateSessionMode) } } @@ -399,8 +400,8 @@ private fun NetworkSectionFooter(revert: () -> Unit, save: () -> Unit, revertDis horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - FooterButton(painterResource(R.drawable.ic_replay), stringResource(R.string.network_options_revert), revert, revertDisabled) - FooterButton(painterResource(R.drawable.ic_check), stringResource(R.string.network_options_save), save, saveDisabled) + FooterButton(painterResource(R.drawable.ic_replay), stringResource(MR.strings.network_options_revert), revert, revertDisabled) + FooterButton(painterResource(R.drawable.ic_check), stringResource(MR.strings.network_options_save), save, saveDisabled) } } @@ -420,14 +421,14 @@ private fun validPort(s: String): Boolean { private fun showUpdateNetworkSettingsDialog( title: String, startsWith: String = "", - message: String = generalGetString(R.string.updating_settings_will_reconnect_client_to_all_servers), + message: String = generalGetString(MR.strings.updating_settings_will_reconnect_client_to_all_servers), onDismiss: () -> Unit, onConfirm: () -> Unit ) { AlertManager.shared.showAlertDialog( title = title, text = startsWith + "\n\n" + message, - confirmText = generalGetString(R.string.update_network_settings_confirmation), + confirmText = generalGetString(MR.strings.update_network_settings_confirmation), onDismiss = onDismiss, onConfirm = onConfirm, onDismissRequest = onDismiss diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt index 8bd917e7a5..a509032a06 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt @@ -11,7 +11,7 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow @@ -20,6 +20,7 @@ import chat.simplex.app.R import chat.simplex.app.model.ChatModel import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.* import kotlin.collections.ArrayList @@ -81,9 +82,9 @@ fun NotificationsSettingsLayout( Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.notifications)) + AppBarTitle(stringResource(MR.strings.notifications)) SectionView(null) { - SettingsActionItemWithContent(null, stringResource(R.string.settings_notifications_mode_title), { showPage(CurrentPage.NOTIFICATIONS_MODE) }) { + SettingsActionItemWithContent(null, stringResource(MR.strings.settings_notifications_mode_title), { showPage(CurrentPage.NOTIFICATIONS_MODE) }) { Text( modes.first { it.value == notificationsMode.value }.title, maxLines = 1, @@ -91,7 +92,7 @@ fun NotificationsSettingsLayout( color = MaterialTheme.colors.secondary ) } - SettingsActionItemWithContent(null, stringResource(R.string.settings_notification_preview_mode_title), { showPage(CurrentPage.NOTIFICATION_PREVIEW_MODE) }) { + SettingsActionItemWithContent(null, stringResource(MR.strings.settings_notification_preview_mode_title), { showPage(CurrentPage.NOTIFICATION_PREVIEW_MODE) }) { Text( previewModes.first { it.value == notificationPreviewMode.value }.title, maxLines = 1, @@ -113,7 +114,7 @@ fun NotificationsModeView( Column( Modifier.fillMaxWidth(), ) { - AppBarTitle(stringResource(R.string.settings_notifications_mode_title).lowercase().capitalize(Locale.current)) + AppBarTitle(stringResource(MR.strings.settings_notifications_mode_title).lowercase().capitalize(Locale.current)) SectionViewSelectable(null, notificationsMode, modes, onNotificationsModeSelected) } } @@ -127,7 +128,7 @@ fun NotificationPreviewView( Column( Modifier.fillMaxWidth(), ) { - AppBarTitle(stringResource(R.string.settings_notification_preview_title)) + AppBarTitle(stringResource(MR.strings.settings_notification_preview_title)) SectionViewSelectable(null, notificationPreviewMode, previewModes, onNotificationPreviewModeSelected) } } @@ -138,22 +139,22 @@ private fun notificationModes(): List> { res.add( ValueTitleDesc( NotificationsMode.OFF, - generalGetString(R.string.notifications_mode_off), - generalGetString(R.string.notifications_mode_off_desc), + generalGetString(MR.strings.notifications_mode_off), + generalGetString(MR.strings.notifications_mode_off_desc), ) ) res.add( ValueTitleDesc( NotificationsMode.PERIODIC, - generalGetString(R.string.notifications_mode_periodic), - generalGetString(R.string.notifications_mode_periodic_desc), + generalGetString(MR.strings.notifications_mode_periodic), + generalGetString(MR.strings.notifications_mode_periodic_desc), ) ) res.add( ValueTitleDesc( NotificationsMode.SERVICE, - generalGetString(R.string.notifications_mode_service), - generalGetString(R.string.notifications_mode_service_desc), + generalGetString(MR.strings.notifications_mode_service), + generalGetString(MR.strings.notifications_mode_service_desc), ) ) return res @@ -165,22 +166,22 @@ fun notificationPreviewModes(): List> { res.add( ValueTitleDesc( NotificationPreviewMode.MESSAGE, - generalGetString(R.string.notification_preview_mode_message), - generalGetString(R.string.notification_preview_mode_message_desc), + generalGetString(MR.strings.notification_preview_mode_message), + generalGetString(MR.strings.notification_preview_mode_message_desc), ) ) res.add( ValueTitleDesc( NotificationPreviewMode.CONTACT, - generalGetString(R.string.notification_preview_mode_contact), - generalGetString(R.string.notification_preview_mode_contact_desc), + generalGetString(MR.strings.notification_preview_mode_contact), + generalGetString(MR.strings.notification_preview_mode_contact_desc), ) ) res.add( ValueTitleDesc( NotificationPreviewMode.HIDDEN, - generalGetString(R.string.notification_preview_mode_hidden), - generalGetString(R.string.notification_display_mode_hidden_desc), + generalGetString(MR.strings.notification_preview_mode_hidden), + generalGetString(MR.strings.notification_display_mode_hidden_desc), ) ) return res diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Preferences.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Preferences.kt index b967806652..c6da840f2f 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Preferences.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/Preferences.kt @@ -12,10 +12,11 @@ import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun PreferencesView(m: ChatModel, user: User, close: () -> Unit,) { @@ -60,7 +61,7 @@ private fun PreferencesLayout( Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.your_preferences)) + AppBarTitle(stringResource(MR.strings.your_preferences)) val timedMessages = remember(preferences) { mutableStateOf(preferences.timedMessages.allow) } TimedMessagesFeatureSection(timedMessages) { applyPrefs(preferences.copy(timedMessages = TimedMessagesPreference(allow = if (it) FeatureAllowed.YES else FeatureAllowed.NO))) @@ -128,19 +129,19 @@ private fun TimedMessagesFeatureSection(allowFeature: State, onS private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) { SectionView { SectionItemView(reset, disabled = disabled) { - Text(stringResource(R.string.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } SectionItemView(save, disabled = disabled) { - Text(stringResource(R.string.save_and_notify_contacts), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(stringResource(MR.strings.save_and_notify_contacts), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } } } private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) { AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.save_preferences_question), - confirmText = generalGetString(R.string.save_and_notify_contacts), - dismissText = generalGetString(R.string.exit_without_saving), + title = generalGetString(MR.strings.save_preferences_question), + confirmText = generalGetString(MR.strings.save_and_notify_contacts), + dismissText = generalGetString(MR.strings.exit_without_saving), onConfirm = save, onDismiss = revert, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt index b961ba58a2..9ca2439283 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt @@ -14,7 +14,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.fragment.app.FragmentActivity @@ -28,6 +28,7 @@ import chat.simplex.app.views.helpers.DatabaseUtils.ksSelfDestructPassword import chat.simplex.app.views.isValidDisplayName import chat.simplex.app.views.localauth.SetAppPasscodeView import chat.simplex.app.views.onboarding.ReadableText +import chat.simplex.res.MR enum class LAMode { SYSTEM, @@ -35,8 +36,8 @@ enum class LAMode { val text: String get() = when (this) { - SYSTEM -> generalGetString(R.string.la_mode_system) - PASSCODE -> generalGetString(R.string.la_mode_passcode) + SYSTEM -> generalGetString(MR.strings.la_mode_system) + PASSCODE -> generalGetString(MR.strings.la_mode_passcode) } } @@ -44,17 +45,17 @@ enum class LAMode { fun PrivacySettingsView( chatModel: ChatModel, showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), - setPerformLA: (Boolean, FragmentActivity) -> Unit + setPerformLA: (Boolean) -> Unit ) { Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { val simplexLinkMode = chatModel.controller.appPrefs.simplexLinkMode - AppBarTitle(stringResource(R.string.your_privacy)) - SectionView(stringResource(R.string.settings_section_title_device)) { + AppBarTitle(stringResource(MR.strings.your_privacy)) + SectionView(stringResource(MR.strings.settings_section_title_device)) { ChatLockItem(chatModel, showSettingsModal, setPerformLA) val context = LocalContext.current - SettingsPreferenceItem(painterResource(R.drawable.ic_visibility_off), stringResource(R.string.protect_app_screen), chatModel.controller.appPrefs.privacyProtectScreen) { on -> + SettingsPreferenceItem(painterResource(R.drawable.ic_visibility_off), stringResource(MR.strings.protect_app_screen), chatModel.controller.appPrefs.privacyProtectScreen) { on -> if (on) { (context as? FragmentActivity)?.window?.setFlags( WindowManager.LayoutParams.FLAG_SECURE, @@ -67,16 +68,16 @@ fun PrivacySettingsView( } SectionDividerSpaced() - SectionView(stringResource(R.string.settings_section_title_chats)) { - SettingsPreferenceItem(painterResource(R.drawable.ic_image), stringResource(R.string.auto_accept_images), chatModel.controller.appPrefs.privacyAcceptImages) - SettingsPreferenceItem(painterResource(R.drawable.ic_travel_explore), stringResource(R.string.send_link_previews), chatModel.controller.appPrefs.privacyLinkPreviews) + SectionView(stringResource(MR.strings.settings_section_title_chats)) { + SettingsPreferenceItem(painterResource(R.drawable.ic_image), stringResource(MR.strings.auto_accept_images), chatModel.controller.appPrefs.privacyAcceptImages) + SettingsPreferenceItem(painterResource(R.drawable.ic_travel_explore), stringResource(MR.strings.send_link_previews), chatModel.controller.appPrefs.privacyLinkPreviews) SimpleXLinkOptions(chatModel.simplexLinkMode, onSelected = { simplexLinkMode.set(it) chatModel.simplexLinkMode.value = it }) } if (chatModel.simplexLinkMode.value == SimplexLinkMode.BROWSER) { - SectionTextFooter(stringResource(R.string.simplex_link_mode_browser_warning)) + SectionTextFooter(stringResource(MR.strings.simplex_link_mode_browser_warning)) } SectionBottomSpacer() } @@ -87,14 +88,14 @@ private fun SimpleXLinkOptions(simplexLinkModeState: State, onS val values = remember { SimplexLinkMode.values().map { when (it) { - SimplexLinkMode.DESCRIPTION -> it to generalGetString(R.string.simplex_link_mode_description) - SimplexLinkMode.FULL -> it to generalGetString(R.string.simplex_link_mode_full) - SimplexLinkMode.BROWSER -> it to generalGetString(R.string.simplex_link_mode_browser) + SimplexLinkMode.DESCRIPTION -> it to generalGetString(MR.strings.simplex_link_mode_description) + SimplexLinkMode.FULL -> it to generalGetString(MR.strings.simplex_link_mode_full) + SimplexLinkMode.BROWSER -> it to generalGetString(MR.strings.simplex_link_mode_browser) } } } ExposedDropDownSettingRow( - generalGetString(R.string.simplex_link_mode), + generalGetString(MR.strings.simplex_link_mode), values, simplexLinkModeState, icon = null, @@ -109,7 +110,7 @@ private val laDelays = listOf(10, 30, 60, 180, 0) fun SimplexLockView( chatModel: ChatModel, currentLAMode: SharedPreference, - setPerformLA: (Boolean, FragmentActivity) -> Unit + setPerformLA: (Boolean) -> Unit ) { val performLA = remember { chatModel.performLA } val laMode = remember { chatModel.controller.appPrefs.laMode.state } @@ -139,11 +140,11 @@ fun SimplexLockView( fun toggleLAMode(toLAMode: LAMode) { authenticate( if (toLAMode == LAMode.SYSTEM) { - generalGetString(R.string.la_enter_app_passcode) + generalGetString(MR.strings.la_enter_app_passcode) } else { - generalGetString(R.string.chat_lock) + generalGetString(MR.strings.chat_lock) }, - generalGetString(R.string.change_lock_mode) + generalGetString(MR.strings.change_lock_mode) ) { laResult -> when (laResult) { is LAResult.Error -> { @@ -153,7 +154,7 @@ fun SimplexLockView( LAResult.Success -> { when (toLAMode) { LAMode.SYSTEM -> { - authenticate(generalGetString(R.string.auth_enable_simplex_lock), promptSubtitle = "", usingLAMode = toLAMode) { laResult -> + authenticate(generalGetString(MR.strings.auth_enable_simplex_lock), promptSubtitle = "", usingLAMode = toLAMode) { laResult -> when (laResult) { LAResult.Success -> { currentLAMode.set(toLAMode) @@ -173,7 +174,7 @@ fun SimplexLockView( submit = { laLockDelay.set(30) currentLAMode.set(toLAMode) - passcodeAlert(generalGetString(R.string.passcode_set)) + passcodeAlert(generalGetString(MR.strings.passcode_set)) }, cancel = {}, close = close @@ -189,7 +190,7 @@ fun SimplexLockView( } fun toggleSelfDestruct(selfDestruct: SharedPreference) { - authenticate(generalGetString(R.string.la_current_app_passcode), generalGetString(R.string.change_self_destruct_mode)) { laResult -> + authenticate(generalGetString(MR.strings.la_current_app_passcode), generalGetString(MR.strings.change_self_destruct_mode)) { laResult -> when (laResult) { is LAResult.Error -> laFailedAlert() is LAResult.Failed -> { /* Can be called multiple times on every failure */ } @@ -208,16 +209,16 @@ fun SimplexLockView( } fun changeLAPassword() { - authenticate(generalGetString(R.string.la_current_app_passcode), generalGetString(R.string.la_change_app_passcode)) { laResult -> + authenticate(generalGetString(MR.strings.la_current_app_passcode), generalGetString(MR.strings.la_change_app_passcode)) { laResult -> when (laResult) { LAResult.Success -> { ModalManager.shared.showCustomModal { close -> Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { SetAppPasscodeView( submit = { - passcodeAlert(generalGetString(R.string.passcode_changed)) + passcodeAlert(generalGetString(MR.strings.passcode_changed)) }, cancel = { - passcodeAlert(generalGetString(R.string.passcode_not_changed)) + passcodeAlert(generalGetString(MR.strings.passcode_not_changed)) }, close = close ) } @@ -231,7 +232,7 @@ fun SimplexLockView( } fun changeSelfDestructPassword() { - authenticate(generalGetString(R.string.la_current_app_passcode), generalGetString(R.string.change_self_destruct_passcode)) { laResult -> + authenticate(generalGetString(MR.strings.la_current_app_passcode), generalGetString(MR.strings.change_self_destruct_passcode)) { laResult -> when (laResult) { LAResult.Success -> { ModalManager.shared.showCustomModal { close -> @@ -239,9 +240,9 @@ fun SimplexLockView( SetAppPasscodeView( passcodeKeychain = ksSelfDestructPassword, submit = { - selfDestructPasscodeAlert(generalGetString(R.string.self_destruct_passcode_changed)) + selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_changed)) }, cancel = { - passcodeAlert(generalGetString(R.string.passcode_not_changed)) + passcodeAlert(generalGetString(MR.strings.passcode_not_changed)) }, close = close ) @@ -258,7 +259,7 @@ fun SimplexLockView( Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.chat_lock)) + AppBarTitle(stringResource(MR.strings.chat_lock)) SectionView { EnableLock(performLA) { performLAToggle -> performLA.value = performLAToggle @@ -266,7 +267,7 @@ fun SimplexLockView( if (performLAToggle) { when (currentLAMode.state.value) { LAMode.SYSTEM -> { - setPerformLA(true, activity) + setPerformLA(true) } LAMode.PASSCODE -> { ModalManager.shared.showCustomModal { close -> @@ -275,7 +276,7 @@ fun SimplexLockView( submit = { laLockDelay.set(30) chatModel.controller.appPrefs.performLA.set(true) - passcodeAlert(generalGetString(R.string.passcode_set)) + passcodeAlert(generalGetString(MR.strings.passcode_set)) }, cancel = { resetLAEnabled(false) @@ -287,7 +288,7 @@ fun SimplexLockView( } } } else { - setPerformLA(false, activity) + setPerformLA(false) } } LockModeSelector(laMode) { newLAMode -> @@ -304,7 +305,7 @@ fun SimplexLockView( if (showChangePasscode.value && laMode.value == LAMode.PASSCODE) { SectionItemView({ changeLAPassword() }) { Text( - generalGetString(R.string.la_change_app_passcode), + generalGetString(MR.strings.la_change_app_passcode), color = MaterialTheme.colors.primary ) } @@ -312,7 +313,7 @@ fun SimplexLockView( } if (performLA.value && laMode.value == LAMode.PASSCODE) { SectionDividerSpaced() - SectionView(stringResource(R.string.self_destruct_passcode).uppercase()) { + SectionView(stringResource(MR.strings.self_destruct_passcode).uppercase()) { val openInfo = { ModalManager.shared.showModal { SelfDestructInfoView() @@ -320,7 +321,7 @@ fun SimplexLockView( } SettingsActionItemWithContent(null, null, click = openInfo) { SharedPreferenceToggleWithIcon( - stringResource(R.string.enable_self_destruct), + stringResource(MR.strings.enable_self_destruct), painterResource(R.drawable.ic_info), openInfo, remember { selfDestructPref.state }.value @@ -332,7 +333,7 @@ fun SimplexLockView( if (remember { selfDestructPref.state }.value) { Column(Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF)) { Text( - stringResource(R.string.self_destruct_new_display_name), + stringResource(MR.strings.self_destruct_new_display_name), fontSize = 16.sp, modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF) ) @@ -346,7 +347,7 @@ fun SimplexLockView( } SectionItemView({ changeSelfDestructPassword() }) { Text( - stringResource(R.string.change_self_destruct_passcode), + stringResource(MR.strings.change_self_destruct_passcode), color = MaterialTheme.colors.primary ) } @@ -363,12 +364,12 @@ private fun SelfDestructInfoView() { Column( Modifier.fillMaxWidth().verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING), ) { - AppBarTitle(stringResource(R.string.self_destruct), withPadding = false) - ReadableText(stringResource(R.string.if_you_enter_self_destruct_code)) + AppBarTitle(stringResource(MR.strings.self_destruct), withPadding = false) + ReadableText(stringResource(MR.strings.if_you_enter_self_destruct_code)) Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { - TextListItem("1.", stringResource(R.string.all_app_data_will_be_cleared)) - TextListItem("2.", stringResource(R.string.app_passcode_replaced_with_self_destruct)) - TextListItem("3.", stringResource(R.string.empty_chat_profile_is_created)) + TextListItem("1.", stringResource(MR.strings.all_app_data_will_be_cleared)) + TextListItem("2.", stringResource(MR.strings.app_passcode_replaced_with_self_destruct)) + TextListItem("3.", stringResource(MR.strings.empty_chat_profile_is_created)) } SectionBottomSpacer() } @@ -381,10 +382,10 @@ private fun EnableSelfDestruct( ) { Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { SetAppPasscodeView( - passcodeKeychain = ksSelfDestructPassword, title = generalGetString(R.string.set_passcode), reason = generalGetString(R.string.enabled_self_destruct_passcode), + passcodeKeychain = ksSelfDestructPassword, title = generalGetString(MR.strings.set_passcode), reason = generalGetString(MR.strings.enabled_self_destruct_passcode), submit = { selfDestruct.set(true) - selfDestructPasscodeAlert(generalGetString(R.string.self_destruct_passcode_enabled)) + selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_enabled)) }, cancel = {}, close = close @@ -397,7 +398,7 @@ private fun EnableLock(performLA: MutableState, onCheckedChange: (Boole SectionItemView { Row(verticalAlignment = Alignment.CenterVertically) { Text( - stringResource(R.string.enable_lock), Modifier + stringResource(MR.strings.enable_lock), Modifier .padding(end = 24.dp) .fillMaxWidth() .weight(1F) @@ -414,7 +415,7 @@ private fun EnableLock(performLA: MutableState, onCheckedChange: (Boole private fun LockModeSelector(state: State, onSelected: (LAMode) -> Unit) { val values by remember { mutableStateOf(LAMode.values().map { it to it.text }) } ExposedDropDownSettingRow( - generalGetString(R.string.lock_mode), + generalGetString(MR.strings.lock_mode), values, state, icon = null, @@ -428,7 +429,7 @@ private fun LockDelaySelector(state: State, onSelected: (Int) -> Unit) { val delays = remember { if (laDelays.contains(state.value)) laDelays else listOf(state.value) + laDelays } val values by remember { mutableStateOf(delays.map { it to laDelayText(it) }) } ExposedDropDownSettingRow( - generalGetString(R.string.lock_after), + generalGetString(MR.strings.lock_after), values, state, icon = null, @@ -449,22 +450,22 @@ private fun laDelayText(t: Int): String { val m = t / 60 val s = t % 60 return if (t == 0) { - generalGetString(R.string.la_immediately) + generalGetString(MR.strings.la_immediately) } else if (m == 0 || s != 0) { // there are no options where both minutes and seconds are needed - generalGetString(R.string.la_seconds).format(s) + generalGetString(MR.strings.la_seconds).format(s) } else { - generalGetString(R.string.la_minutes).format(m) + generalGetString(MR.strings.la_minutes).format(m) } } private fun passcodeAlert(title: String) { AlertManager.shared.showAlertMsg( title = title, - text = generalGetString(R.string.la_please_remember_to_store_password) + text = generalGetString(MR.strings.la_please_remember_to_store_password) ) } private fun selfDestructPasscodeAlert(title: String) { - AlertManager.shared.showAlertMsg(title, generalGetString(R.string.if_you_enter_passcode_data_removed)) + AlertManager.shared.showAlertMsg(title, generalGetString(MR.strings.if_you_enter_passcode_data_removed)) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ProtocolServerView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ProtocolServerView.kt index 86a2cafad2..a14f29062a 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ProtocolServerView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ProtocolServerView.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp @@ -27,6 +27,7 @@ import chat.simplex.app.model.ServerAddress.Companion.parseServerAddress import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.QRCode +import chat.simplex.res.MR import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.isActive @@ -83,7 +84,7 @@ private fun ProtocolServerLayout( .fillMaxWidth() .verticalScroll(rememberScrollState()) ) { - AppBarTitle(stringResource(if (server.preset) R.string.smp_servers_preset_server else R.string.smp_servers_your_server)) + AppBarTitle(stringResource(if (server.preset) MR.strings.smp_servers_preset_server else MR.strings.smp_servers_your_server)) if (server.preset) { PresetServer(testing, server, testServer, onUpdate, onDelete) @@ -102,7 +103,7 @@ private fun PresetServer( onUpdate: (ServerCfg) -> Unit, onDelete: () -> Unit, ) { - SectionView(stringResource(R.string.smp_servers_preset_address).uppercase()) { + SectionView(stringResource(MR.strings.smp_servers_preset_address).uppercase()) { SelectionContainer { Text( server.server, @@ -136,7 +137,7 @@ private fun CustomServer( } } SectionView( - stringResource(R.string.smp_servers_your_server_address).uppercase(), + stringResource(MR.strings.smp_servers_your_server_address).uppercase(), icon = painterResource(R.drawable.ic_error), iconTint = if (!valid.value) MaterialTheme.colors.error else Color.Transparent, ) { @@ -159,7 +160,7 @@ private fun CustomServer( if (valid.value) { SectionDividerSpaced() - SectionView(stringResource(R.string.smp_servers_add_to_another_device).uppercase()) { + SectionView(stringResource(MR.strings.smp_servers_add_to_another_device).uppercase()) { QRCode(serverAddress.value, Modifier.aspectRatio(1f).padding(horizontal = DEFAULT_PADDING)) } } @@ -174,15 +175,15 @@ private fun UseServerSection( onUpdate: (ServerCfg) -> Unit, onDelete: () -> Unit, ) { - SectionView(stringResource(R.string.smp_servers_use_server).uppercase()) { + SectionView(stringResource(MR.strings.smp_servers_use_server).uppercase()) { SectionItemViewSpaceBetween(testServer, disabled = !valid || testing) { - Text(stringResource(R.string.smp_servers_test_server), color = if (valid && !testing) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) + Text(stringResource(MR.strings.smp_servers_test_server), color = if (valid && !testing) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) ShowTestStatus(server) } val enabled = rememberUpdatedState(server.enabled) - PreferenceToggle(stringResource(R.string.smp_servers_use_server_for_new_conn), enabled.value) { onUpdate(server.copy(enabled = it)) } + PreferenceToggle(stringResource(MR.strings.smp_servers_use_server_for_new_conn), enabled.value) { onUpdate(server.copy(enabled = it)) } SectionItemView(onDelete, disabled = testing) { - Text(stringResource(R.string.smp_servers_delete_server), color = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.error) + Text(stringResource(MR.strings.smp_servers_delete_server), color = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.error) } } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ProtocolServersView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ProtocolServersView.kt index 306b0579ae..13b69b6287 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ProtocolServersView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ProtocolServersView.kt @@ -14,7 +14,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -24,6 +24,7 @@ import chat.simplex.app.model.* import chat.simplex.app.model.ServerAddress.Companion.parseServerAddress import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR import kotlinx.coroutines.launch @Composable @@ -102,7 +103,7 @@ fun ProtocolServersView(m: ChatModel, serverProtocol: ServerProtocol, close: () m.currentUser.value, addServer = { AlertManager.shared.showAlertDialogButtonsColumn( - title = generalGetString(R.string.smp_servers_add), + title = generalGetString(MR.strings.smp_servers_add), buttons = { Column { SectionItemView({ @@ -111,7 +112,7 @@ fun ProtocolServersView(m: ChatModel, serverProtocol: ServerProtocol, close: () // No saving until something will be changed on the next screen to prevent blank servers on the list showServer(servers.last()) }) { - Text(stringResource(R.string.smp_servers_enter_manually), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + Text(stringResource(MR.strings.smp_servers_enter_manually), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) } SectionItemView({ AlertManager.shared.hideAlert() @@ -124,7 +125,7 @@ fun ProtocolServersView(m: ChatModel, serverProtocol: ServerProtocol, close: () } } ) { - Text(stringResource(R.string.smp_servers_scan_qr), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) + Text(stringResource(MR.strings.smp_servers_scan_qr), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.primary) } val hasAllPresets = hasAllPresets(presetServers, servers, m) if (!hasAllPresets) { @@ -132,7 +133,7 @@ fun ProtocolServersView(m: ChatModel, serverProtocol: ServerProtocol, close: () AlertManager.shared.hideAlert() servers = (servers + addAllPresets(presetServers, servers, m)).sortedByDescending { it.preset } }) { - Text(stringResource(R.string.smp_servers_preset_add), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.onBackground) + Text(stringResource(MR.strings.smp_servers_preset_add), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = MaterialTheme.colors.onBackground) } } } @@ -194,9 +195,9 @@ private fun ProtocolServersLayout( .fillMaxWidth() .verticalScroll(rememberScrollState()) ) { - AppBarTitle(stringResource(if (serverProtocol == ServerProtocol.SMP) R.string.your_SMP_servers else R.string.your_XFTP_servers)) + AppBarTitle(stringResource(if (serverProtocol == ServerProtocol.SMP) MR.strings.your_SMP_servers else MR.strings.your_XFTP_servers)) - SectionView(stringResource(if (serverProtocol == ServerProtocol.SMP) R.string.smp_servers else R.string.xftp_servers).uppercase()) { + SectionView(stringResource(if (serverProtocol == ServerProtocol.SMP) MR.strings.smp_servers else MR.strings.xftp_servers).uppercase()) { for (srv in servers) { SectionItemView({ showServer(srv) }, disabled = testing) { ProtocolServerView(serverProtocol, srv, servers, testing) @@ -204,7 +205,7 @@ private fun ProtocolServersLayout( } SettingsActionItem( painterResource(R.drawable.ic_add), - stringResource(R.string.smp_servers_add), + stringResource(MR.strings.smp_servers_add), addServer, disabled = testing, textColor = if (testing) MaterialTheme.colors.secondary else MaterialTheme.colors.primary, @@ -214,7 +215,7 @@ private fun ProtocolServersLayout( SectionTextFooter( remember(currentUser?.displayName) { buildAnnotatedString { - append(generalGetString(R.string.smp_servers_per_user) + " ") + append(generalGetString(MR.strings.smp_servers_per_user) + " ") withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append(currentUser?.displayName ?: "") } @@ -225,14 +226,14 @@ private fun ProtocolServersLayout( SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false) SectionView { SectionItemView(resetServers, disabled = serversUnchanged) { - Text(stringResource(R.string.reset_verb), color = if (!serversUnchanged) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) + Text(stringResource(MR.strings.reset_verb), color = if (!serversUnchanged) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) } val testServersDisabled = testing || allServersDisabled SectionItemView(testServers, disabled = testServersDisabled) { - Text(stringResource(R.string.smp_servers_test_servers), color = if (!testServersDisabled) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) + Text(stringResource(MR.strings.smp_servers_test_servers), color = if (!testServersDisabled) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) } SectionItemView(saveSMPServers, disabled = saveDisabled) { - Text(stringResource(R.string.smp_servers_save), color = if (!saveDisabled) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) + Text(stringResource(MR.strings.smp_servers_save), color = if (!saveDisabled) MaterialTheme.colors.onBackground else MaterialTheme.colors.secondary) } } SectionDividerSpaced(maxBottomPadding = false) @@ -265,7 +266,7 @@ private fun HowToButton() { val uriHandler = LocalUriHandler.current SettingsActionItem( painterResource(R.drawable.ic_open_in_new), - stringResource(R.string.how_to_use_your_servers), + stringResource(MR.strings.how_to_use_your_servers), { uriHandler.openUriCatching("https://simplex.chat/docs/server.html") }, textColor = MaterialTheme.colors.primary, iconColor = MaterialTheme.colors.primary @@ -308,8 +309,8 @@ private suspend fun testServers(testing: MutableState, servers: List Unit, revert: () -> Unit) { AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.smp_save_servers_question), - confirmText = generalGetString(R.string.save_verb), - dismissText = generalGetString(R.string.exit_without_saving), + title = generalGetString(MR.strings.smp_save_servers_question), + confirmText = generalGetString(MR.strings.save_verb), + dismissText = generalGetString(MR.strings.exit_without_saving), onConfirm = save, onDismiss = revert, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/RTCServers.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/RTCServers.kt index a187281e1d..e21fbda51d 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/RTCServers.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/RTCServers.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp @@ -23,6 +23,7 @@ import chat.simplex.app.model.ChatModel import chat.simplex.app.ui.theme.* import chat.simplex.app.views.call.parseRTCIceServers import chat.simplex.app.views.helpers.* +import chat.simplex.res.MR @Composable fun RTCServersView( @@ -42,8 +43,8 @@ fun RTCServersView( editRTCServers = false } else { AlertManager.shared.showAlertMsg( - generalGetString(R.string.error_saving_ICE_servers), - generalGetString(R.string.ensure_ICE_server_address_are_correct_format_and_unique) + generalGetString(MR.strings.error_saving_ICE_servers), + generalGetString(MR.strings.ensure_ICE_server_address_are_correct_format_and_unique) ) } } @@ -63,9 +64,9 @@ fun RTCServersView( isUserRTCServers = true } else if (userRTCServers.isNotEmpty()) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.use_simplex_chat_servers__question), - text = generalGetString(R.string.saved_ICE_servers_will_be_removed), - confirmText = generalGetString(R.string.confirm_verb), + title = generalGetString(MR.strings.use_simplex_chat_servers__question), + text = generalGetString(MR.strings.saved_ICE_servers_will_be_removed), + confirmText = generalGetString(MR.strings.confirm_verb), onConfirm = { resetRTCServers() isUserRTCServers = false @@ -99,7 +100,7 @@ fun RTCServersLayout( editOn: () -> Unit, ) { Column { - AppBarTitle(stringResource(R.string.your_ICE_servers)) + AppBarTitle(stringResource(MR.strings.your_ICE_servers)) Column( Modifier .fillMaxWidth() @@ -108,7 +109,7 @@ fun RTCServersLayout( verticalArrangement = Arrangement.spacedBy(8.dp) ) { SectionItemViewSpaceBetween(padding = PaddingValues()) { - Text(stringResource(R.string.configure_ICE_servers), Modifier.padding(end = 24.dp)) + Text(stringResource(MR.strings.configure_ICE_servers), Modifier.padding(end = 24.dp)) DefaultSwitch( checked = isUserRTCServers, onCheckedChange = isUserRTCServersOnOff, @@ -116,9 +117,9 @@ fun RTCServersLayout( } if (!isUserRTCServers) { - Text(stringResource(R.string.using_simplex_chat_servers), lineHeight = 22.sp) + Text(stringResource(MR.strings.using_simplex_chat_servers), lineHeight = 22.sp) } else { - Text(stringResource(R.string.enter_one_ICE_server_per_line)) + Text(stringResource(MR.strings.enter_one_ICE_server_per_line)) if (editRTCServers) { TextEditor(userRTCServersStr, Modifier.height(160.dp), contentPadding = PaddingValues()) @@ -130,14 +131,14 @@ fun RTCServersLayout( Column { Row { Text( - stringResource(R.string.cancel_verb), + stringResource(MR.strings.cancel_verb), color = MaterialTheme.colors.primary, modifier = Modifier .clickable(onClick = cancelEdit) ) Spacer(Modifier.padding(horizontal = 8.dp)) Text( - stringResource(R.string.save_servers_button), + stringResource(MR.strings.save_servers_button), color = MaterialTheme.colors.primary, modifier = Modifier.clickable(onClick = { saveRTCServers() @@ -175,7 +176,7 @@ fun RTCServersLayout( ) { Column { Text( - stringResource(R.string.edit_verb), + stringResource(MR.strings.edit_verb), color = MaterialTheme.colors.primary, modifier = Modifier .clickable(onClick = editOn) @@ -199,9 +200,9 @@ private fun howToButton() { verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clickable { uriHandler.openUriCatching("https://simplex.chat/docs/webrtc.html#configure-mobile-apps") } ) { - Text(stringResource(R.string.how_to), color = MaterialTheme.colors.primary) + Text(stringResource(MR.strings.how_to), color = MaterialTheme.colors.primary) Icon( - painterResource(R.drawable.ic_open_in_new), stringResource(R.string.how_to), tint = MaterialTheme.colors.primary, + painterResource(R.drawable.ic_open_in_new), stringResource(MR.strings.how_to), tint = MaterialTheme.colors.primary, modifier = Modifier.padding(horizontal = 5.dp) ) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ScanProtocolServer.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ScanProtocolServer.kt index 525263a27b..69f1e31435 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ScanProtocolServer.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/ScanProtocolServer.kt @@ -5,7 +5,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.ServerAddress.Companion.parseServerAddress @@ -14,6 +14,7 @@ import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.QRCodeScanner import com.google.accompanist.permissions.rememberPermissionState +import chat.simplex.res.MR @Composable fun ScanProtocolServer(onNext: (ServerCfg) -> Unit) { @@ -31,7 +32,7 @@ private fun ScanProtocolServerLayout(onNext: (ServerCfg) -> Unit) { .fillMaxSize() .padding(horizontal = DEFAULT_PADDING) ) { - AppBarTitle(stringResource(R.string.smp_servers_scan_qr), false) + AppBarTitle(stringResource(MR.strings.smp_servers_scan_qr), false) Box( Modifier .fillMaxWidth() @@ -44,8 +45,8 @@ private fun ScanProtocolServerLayout(onNext: (ServerCfg) -> Unit) { onNext(ServerCfg(text, false, null, true)) } else { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.smp_servers_invalid_address), - text = generalGetString(R.string.smp_servers_check_address) + title = generalGetString(MR.strings.smp_servers_invalid_address), + text = generalGetString(MR.strings.smp_servers_check_address) ) } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt index 2aae79fa8a..18313e10b8 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt @@ -18,7 +18,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.* import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -33,10 +33,11 @@ import chat.simplex.app.views.database.DatabaseView import chat.simplex.app.views.helpers.* import chat.simplex.app.views.onboarding.SimpleXInfo import chat.simplex.app.views.onboarding.WhatsNewView +import chat.simplex.res.MR import com.jakewharton.processphoenix.ProcessPhoenix @Composable -fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity) -> Unit) { +fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { val user = chatModel.currentUser.value val stopped = chatModel.chatRunning.value == false @@ -98,7 +99,7 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity) contentAlignment = Alignment.Center ) { SimpleButton( - stringResource(R.string.auth_unlock), + stringResource(MR.strings.auth_unlock), icon = painterResource(R.drawable.ic_lock), click = { runAuth(title, desc, onFinishAuth) @@ -123,7 +124,7 @@ fun SettingsLayout( incognito: MutableState, incognitoPref: SharedPreference, userDisplayName: String, - setPerformLA: (Boolean, FragmentActivity) -> Unit, + setPerformLA: (Boolean) -> Unit, showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), showSettingsModalWithSearch: (@Composable (ChatModel, MutableState) -> Unit) -> Unit, @@ -139,50 +140,50 @@ fun SettingsLayout( .fillMaxSize() .padding(top = DEFAULT_PADDING) ) { - AppBarTitle(stringResource(R.string.your_settings)) + AppBarTitle(stringResource(MR.strings.your_settings)) - SectionView(stringResource(R.string.settings_section_title_you)) { + SectionView(stringResource(MR.strings.settings_section_title_you)) { SectionItemView(showCustomModal { chatModel, close -> UserProfileView(chatModel, close) }, 80.dp, padding = PaddingValues(start = 16.dp, end = DEFAULT_PADDING), disabled = stopped) { ProfilePreview(profile, stopped = stopped) } val profileHidden = rememberSaveable { mutableStateOf(false) } - SettingsActionItem(painterResource(R.drawable.ic_manage_accounts), stringResource(R.string.your_chat_profiles), { withAuth(generalGetString(R.string.auth_open_chat_profiles), generalGetString(R.string.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden) } } }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_manage_accounts), stringResource(MR.strings.your_chat_profiles), { withAuth(generalGetString(MR.strings.auth_open_chat_profiles), generalGetString(MR.strings.auth_log_in_using_credential)) { showSettingsModalWithSearch { it, search -> UserProfilesView(it, search, profileHidden) } } }, disabled = stopped, extraPadding = true) SettingsIncognitoActionItem(incognitoPref, incognito, stopped) { showModal { IncognitoView() }() } - SettingsActionItem(painterResource(R.drawable.ic_qr_code), stringResource(R.string.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_qr_code), stringResource(MR.strings.your_simplex_contact_address), showCustomModal { it, close -> UserAddressView(it, shareViaProfile = it.currentUser.value!!.addressShared, close = close) }, disabled = stopped, extraPadding = true) ChatPreferencesItem(showCustomModal, stopped = stopped) } SectionDividerSpaced() - SectionView(stringResource(R.string.settings_section_title_settings)) { - SettingsActionItem(painterResource(R.drawable.ic_bolt), stringResource(R.string.notifications), showSettingsModal { NotificationsSettingsView(it) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_wifi_tethering), stringResource(R.string.network_and_servers), showSettingsModal { NetworkAndServersView(it, showModal, showSettingsModal, showCustomModal) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_videocam), stringResource(R.string.settings_audio_video_calls), showSettingsModal { CallSettingsView(it, showModal) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_lock), stringResource(R.string.privacy_and_security), showSettingsModal { PrivacySettingsView(it, showSettingsModal, setPerformLA) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_light_mode), stringResource(R.string.appearance_settings), showSettingsModal { AppearanceView(it, showSettingsModal) }, extraPadding = true) + SectionView(stringResource(MR.strings.settings_section_title_settings)) { + SettingsActionItem(painterResource(R.drawable.ic_bolt), stringResource(MR.strings.notifications), showSettingsModal { NotificationsSettingsView(it) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_wifi_tethering), stringResource(MR.strings.network_and_servers), showSettingsModal { NetworkAndServersView(it, showModal, showSettingsModal, showCustomModal) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_videocam), stringResource(MR.strings.settings_audio_video_calls), showSettingsModal { CallSettingsView(it, showModal) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_lock), stringResource(MR.strings.privacy_and_security), showSettingsModal { PrivacySettingsView(it, showSettingsModal, setPerformLA) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_light_mode), stringResource(MR.strings.appearance_settings), showSettingsModal { AppearanceView(it, showSettingsModal) }, extraPadding = true) DatabaseItem(encrypted, showSettingsModal { DatabaseView(it, showSettingsModal) }, stopped) } SectionDividerSpaced() - SectionView(stringResource(R.string.settings_section_title_help)) { - SettingsActionItem(painterResource(R.drawable.ic_help), stringResource(R.string.how_to_use_simplex_chat), showModal { HelpView(userDisplayName) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_add), stringResource(R.string.whats_new), showCustomModal { _, close -> WhatsNewView(viaSettings = true, close) }, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_info), stringResource(R.string.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) }, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_tag), stringResource(R.string.chat_with_the_founder), { uriHandler.openUriCatching(simplexTeamUri) }, textColor = MaterialTheme.colors.primary, disabled = stopped, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_mail), stringResource(R.string.send_us_an_email), { uriHandler.openUriCatching("mailto:chat@simplex.chat") }, textColor = MaterialTheme.colors.primary, extraPadding = true) + SectionView(stringResource(MR.strings.settings_section_title_help)) { + SettingsActionItem(painterResource(R.drawable.ic_help), stringResource(MR.strings.how_to_use_simplex_chat), showModal { HelpView(userDisplayName) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_add), stringResource(MR.strings.whats_new), showCustomModal { _, close -> WhatsNewView(viaSettings = true, close) }, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_info), stringResource(MR.strings.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) }, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_tag), stringResource(MR.strings.chat_with_the_founder), { uriHandler.openUriCatching(simplexTeamUri) }, textColor = MaterialTheme.colors.primary, disabled = stopped, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_mail), stringResource(MR.strings.send_us_an_email), { uriHandler.openUriCatching("mailto:chat@simplex.chat") }, textColor = MaterialTheme.colors.primary, extraPadding = true) } SectionDividerSpaced() - SectionView(stringResource(R.string.settings_section_title_support)) { + SectionView(stringResource(MR.strings.settings_section_title_support)) { ContributeItem(uriHandler) RateAppItem(uriHandler) StarOnGithubItem(uriHandler) } SectionDividerSpaced() - SectionView(stringResource(R.string.settings_section_title_app)) { - SettingsActionItem(painterResource(R.drawable.ic_restart_alt), stringResource(R.string.settings_restart_app), ::restartApp, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_power_settings_new), stringResource(R.string.settings_shutdown), { shutdownAppAlert(::shutdownApp) }, extraPadding = true) - SettingsActionItem(painterResource(R.drawable.ic_code), stringResource(R.string.settings_developer_tools), showSettingsModal { DeveloperView(it, showCustomModal, withAuth) }, extraPadding = true) + SectionView(stringResource(MR.strings.settings_section_title_app)) { + SettingsActionItem(painterResource(R.drawable.ic_restart_alt), stringResource(MR.strings.settings_restart_app), ::restartApp, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_power_settings_new), stringResource(MR.strings.settings_shutdown), { shutdownAppAlert(::shutdownApp) }, extraPadding = true) + SettingsActionItem(painterResource(R.drawable.ic_code), stringResource(MR.strings.settings_developer_tools), showSettingsModal { DeveloperView(it, showCustomModal, withAuth) }, extraPadding = true) AppVersionItem(showVersion) } SectionBottomSpacer() @@ -200,7 +201,7 @@ fun SettingsIncognitoActionItem( SettingsPreferenceItemWithInfo( if (incognito.value) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_theater_comedy), if (incognito.value) Indigo else MaterialTheme.colors.secondary, - stringResource(R.string.incognito), + stringResource(MR.strings.incognito), stopped, onClickInfo, incognitoPref, @@ -236,16 +237,16 @@ fun MaintainIncognitoState(chatModel: ChatModel) { Row(Modifier.weight(1f)) { Icon( painterResource(R.drawable.ic_database), - contentDescription = stringResource(R.string.database_passphrase_and_export), + contentDescription = stringResource(MR.strings.database_passphrase_and_export), tint = if (encrypted) MaterialTheme.colors.secondary else WarningOrange, ) TextIconSpaced(true) - Text(stringResource(R.string.database_passphrase_and_export)) + Text(stringResource(MR.strings.database_passphrase_and_export)) } if (stopped) { Icon( painterResource(R.drawable.ic_report_filled), - contentDescription = stringResource(R.string.chat_is_stopped), + contentDescription = stringResource(MR.strings.chat_is_stopped), tint = Color.Red, modifier = Modifier.padding(end = 6.dp) ) @@ -257,7 +258,7 @@ fun MaintainIncognitoState(chatModel: ChatModel) { @Composable fun ChatPreferencesItem(showCustomModal: ((@Composable (ChatModel, () -> Unit) -> Unit) -> (() -> Unit)), stopped: Boolean) { SettingsActionItem( painterResource(R.drawable.ic_toggle_on), - stringResource(R.string.chat_preferences), + stringResource(MR.strings.chat_preferences), click = if (stopped) null else ({ withApi { showCustomModal { m, close -> @@ -274,18 +275,18 @@ fun MaintainIncognitoState(chatModel: ChatModel) { fun ChatLockItem( chatModel: ChatModel, showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), - setPerformLA: (Boolean, FragmentActivity) -> Unit + setPerformLA: (Boolean) -> Unit ) { val performLA = remember { chatModel.performLA } val currentLAMode = remember { chatModel.controller.appPrefs.laMode } SettingsActionItemWithContent( click = showSettingsModal { SimplexLockView(chatModel, currentLAMode, setPerformLA) }, icon = if (performLA.value) painterResource(R.drawable.ic_lock_filled) else painterResource(R.drawable.ic_lock), - text = stringResource(R.string.chat_lock), + text = stringResource(MR.strings.chat_lock), iconColor = if (performLA.value) SimplexGreen else MaterialTheme.colors.secondary, extraPadding = false, ) { - Text(if (performLA.value) remember { currentLAMode.state }.value.text else generalGetString(androidx.compose.ui.R.string.off), color = MaterialTheme.colors.secondary) + Text(if (performLA.value) remember { currentLAMode.state }.value.text else generalGetString(MR.strings.la_mode_off), color = MaterialTheme.colors.secondary) } } @@ -297,7 +298,7 @@ fun ChatLockItem( tint = MaterialTheme.colors.secondary, ) TextIconSpaced(extraPadding = true) - Text(generalGetString(R.string.contribute), color = MaterialTheme.colors.primary) + Text(generalGetString(MR.strings.contribute), color = MaterialTheme.colors.primary) } } @@ -313,7 +314,7 @@ fun ChatLockItem( tint = MaterialTheme.colors.secondary, ) TextIconSpaced(extraPadding = true) - Text(generalGetString(R.string.rate_the_app), color = MaterialTheme.colors.primary) + Text(generalGetString(MR.strings.rate_the_app), color = MaterialTheme.colors.primary) } } @@ -325,7 +326,7 @@ fun ChatLockItem( tint = MaterialTheme.colors.secondary, ) TextIconSpaced(extraPadding = true) - Text(generalGetString(R.string.star_on_github), color = MaterialTheme.colors.primary) + Text(generalGetString(MR.strings.star_on_github), color = MaterialTheme.colors.primary) } } @@ -333,11 +334,11 @@ fun ChatLockItem( SectionItemView(showTerminal) { Icon( painter = painterResource(id = R.drawable.ic_outline_terminal), - contentDescription = stringResource(R.string.chat_console), + contentDescription = stringResource(MR.strings.chat_console), tint = MaterialTheme.colors.secondary, ) TextIconSpaced() - Text(stringResource(R.string.chat_console)) + Text(stringResource(MR.strings.chat_console)) } } @@ -349,7 +350,7 @@ fun ChatLockItem( tint = MaterialTheme.colors.secondary, ) TextIconSpaced() - Text(generalGetString(R.string.install_simplex_chat_for_terminal), color = MaterialTheme.colors.primary) + Text(generalGetString(MR.strings.install_simplex_chat_for_terminal), color = MaterialTheme.colors.primary) } } @@ -502,8 +503,8 @@ private fun shutdownApp() { private fun shutdownAppAlert(onConfirm: () -> Unit) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.shutdown_alert_question), - text = generalGetString(R.string.shutdown_alert_desc), + title = generalGetString(MR.strings.shutdown_alert_question), + text = generalGetString(MR.strings.shutdown_alert_desc), destructive = true, onConfirm = onConfirm ) @@ -525,7 +526,7 @@ fun PreviewSettingsLayout() { incognito = remember { mutableStateOf(false) }, incognitoPref = SharedPreference({ false }, {}), userDisplayName = "Alice", - setPerformLA = { _, _ -> }, + setPerformLA = { _ -> }, showModal = { {} }, showSettingsModal = { {} }, showSettingsModalWithSearch = { }, diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserAddressLearnMore.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserAddressLearnMore.kt index 371a14548b..de08ffda66 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserAddressLearnMore.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserAddressLearnMore.kt @@ -4,21 +4,22 @@ import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.R import chat.simplex.app.views.helpers.* import chat.simplex.app.views.onboarding.ReadableText import chat.simplex.app.views.onboarding.ReadableTextWithLink +import chat.simplex.res.MR @Composable fun UserAddressLearnMore() { Column( Modifier.verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.simplex_address)) - ReadableText(R.string.you_can_share_your_address) - ReadableText(R.string.you_wont_lose_your_contacts_if_delete_address) - ReadableText(R.string.you_can_accept_or_reject_connection) - ReadableTextWithLink(R.string.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address") + AppBarTitle(stringResource(MR.strings.simplex_address)) + ReadableText(MR.strings.you_can_share_your_address) + ReadableText(MR.strings.you_wont_lose_your_contacts_if_delete_address) + ReadableText(MR.strings.you_can_accept_or_reject_connection) + ReadableTextWithLink(MR.strings.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/app-settings.html#your-simplex-contact-address") } } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt index 8f4b467dab..9bbf00bbd9 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt @@ -17,7 +17,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import chat.simplex.app.R @@ -27,6 +27,7 @@ import chat.simplex.app.ui.theme.* import chat.simplex.app.views.chat.ShareAddressButton import chat.simplex.app.views.helpers.* import chat.simplex.app.views.newchat.QRCode +import chat.simplex.res.MR @Composable fun UserAddressView( @@ -68,9 +69,9 @@ fun UserAddressView( chatModel.userAddress.value = UserContactLinkRec(connReqContact) AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.share_address_with_contacts_question), - text = generalGetString(R.string.add_address_to_your_profile), - confirmText = generalGetString(R.string.share_verb), + title = generalGetString(MR.strings.share_address_with_contacts_question), + text = generalGetString(MR.strings.add_address_to_your_profile), + confirmText = generalGetString(MR.strings.share_verb), onConfirm = { setProfileAddress(true) shareViaProfile.value = true @@ -95,16 +96,16 @@ fun UserAddressView( share = { userAddress: String -> shareText(userAddress) }, sendEmail = { userAddress -> sendEmail( - generalGetString(R.string.email_invite_subject), - generalGetString(R.string.email_invite_body).format(userAddress.connReqContact) + generalGetString(MR.strings.email_invite_subject), + generalGetString(MR.strings.email_invite_body).format(userAddress.connReqContact) ) }, setProfileAddress = ::setProfileAddress, deleteAddress = { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.delete_address__question), - text = if (shareViaProfile.value) generalGetString(R.string.all_your_contacts_will_remain_connected_update_sent) else generalGetString(R.string.all_your_contacts_will_remain_connected), - confirmText = generalGetString(R.string.delete_verb), + title = generalGetString(MR.strings.delete_address__question), + text = if (shareViaProfile.value) generalGetString(MR.strings.all_your_contacts_will_remain_connected_update_sent) else generalGetString(MR.strings.all_your_contacts_will_remain_connected), + confirmText = generalGetString(MR.strings.delete_verb), onConfirm = { progressIndicator = true withApi { @@ -175,7 +176,7 @@ private fun UserAddressLayout( Column( Modifier.verticalScroll(rememberScrollState()), ) { - AppBarTitle(stringResource(R.string.simplex_address), false) + AppBarTitle(stringResource(MR.strings.simplex_address), false) Column( Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), horizontalAlignment = Alignment.CenterHorizontally, @@ -184,7 +185,7 @@ private fun UserAddressLayout( if (userAddress == null) { SectionView { CreateAddressButton(createAddress) - SectionTextFooter(stringResource(R.string.create_address_and_let_people_connect)) + SectionTextFooter(stringResource(MR.strings.create_address_and_let_people_connect)) } SectionDividerSpaced(maxBottomPadding = false) SectionView { @@ -196,7 +197,7 @@ private fun UserAddressLayout( } else { val autoAcceptState = remember { mutableStateOf(AutoAcceptState(userAddress)) } val autoAcceptStateSaved = remember { mutableStateOf(autoAcceptState.value) } - SectionView(stringResource(R.string.address_section_title).uppercase()) { + SectionView(stringResource(MR.strings.address_section_title).uppercase()) { QRCode(userAddress.connReqContact, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f)) ShareAddressButton { share(userAddress.connReqContact) } ShareViaEmailButton { sendEmail(userAddress) } @@ -213,7 +214,7 @@ private fun UserAddressLayout( SectionView { DeleteAddressButton(deleteAddress) - SectionTextFooter(stringResource(R.string.your_contacts_will_remain_connected)) + SectionTextFooter(stringResource(MR.strings.your_contacts_will_remain_connected)) } LaunchedEffect(Unit) { onCloseHandler.value = { close -> @@ -231,7 +232,7 @@ private fun UserAddressLayout( private fun CreateAddressButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_qr_code), - stringResource(R.string.create_simplex_address), + stringResource(MR.strings.create_simplex_address), onClick, iconColor = MaterialTheme.colors.primary, textColor = MaterialTheme.colors.primary, @@ -242,7 +243,7 @@ private fun CreateAddressButton(onClick: () -> Unit) { private fun LearnMoreButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_info), - stringResource(R.string.learn_more_about_address), + stringResource(MR.strings.learn_more_about_address), onClick, ) } @@ -251,7 +252,7 @@ private fun LearnMoreButton(onClick: () -> Unit) { fun ShareViaEmailButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_mail), - stringResource(R.string.invite_friends), + stringResource(MR.strings.invite_friends), onClick, iconColor = MaterialTheme.colors.primary, textColor = MaterialTheme.colors.primary, @@ -261,16 +262,16 @@ fun ShareViaEmailButton(onClick: () -> Unit) { @Composable fun ShareWithContactsButton(shareViaProfile: MutableState, setProfileAddress: (Boolean) -> Unit) { PreferenceToggleWithIcon( - stringResource(R.string.share_with_contacts), + stringResource(MR.strings.share_with_contacts), painterResource(R.drawable.ic_person), checked = shareViaProfile.value, ) { on -> shareViaProfile.value = on if (on) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.share_address_with_contacts_question), - text = generalGetString(R.string.profile_update_will_be_sent_to_contacts), - confirmText = generalGetString(R.string.share_verb), + title = generalGetString(MR.strings.share_address_with_contacts_question), + text = generalGetString(MR.strings.profile_update_will_be_sent_to_contacts), + confirmText = generalGetString(MR.strings.share_verb), onConfirm = { setProfileAddress(on) }, @@ -282,9 +283,9 @@ fun ShareWithContactsButton(shareViaProfile: MutableState, setProfileAd }) } else { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.stop_sharing_address), - text = generalGetString(R.string.profile_update_will_be_sent_to_contacts), - confirmText = generalGetString(R.string.stop_sharing), + title = generalGetString(MR.strings.stop_sharing_address), + text = generalGetString(MR.strings.profile_update_will_be_sent_to_contacts), + confirmText = generalGetString(MR.strings.stop_sharing), onConfirm = { setProfileAddress(on) }, @@ -300,7 +301,7 @@ fun ShareWithContactsButton(shareViaProfile: MutableState, setProfileAd @Composable private fun AutoAcceptToggle(autoAcceptState: MutableState, saveAas: (AutoAcceptState) -> Unit) { - PreferenceToggleWithIcon(stringResource(R.string.auto_accept_contact), painterResource(R.drawable.ic_check), checked = autoAcceptState.value.enable) { + PreferenceToggleWithIcon(stringResource(MR.strings.auto_accept_contact), painterResource(R.drawable.ic_check), checked = autoAcceptState.value.enable) { autoAcceptState.value = if (!it) AutoAcceptState() else @@ -313,7 +314,7 @@ private fun AutoAcceptToggle(autoAcceptState: MutableState, sav private fun DeleteAddressButton(onClick: () -> Unit) { SettingsActionItem( painterResource(R.drawable.ic_delete), - stringResource(R.string.delete_address), + stringResource(MR.strings.delete_address), onClick, iconColor = MaterialTheme.colors.error, textColor = MaterialTheme.colors.error, @@ -378,7 +379,7 @@ private fun AutoAcceptSection( savedAutoAcceptState: MutableState, saveAas: (AutoAcceptState, MutableState) -> Unit ) { - SectionView(stringResource(R.string.auto_accept_contact).uppercase()) { + SectionView(stringResource(MR.strings.auto_accept_contact).uppercase()) { AcceptIncognitoToggle(autoAcceptState) WelcomeMessageEditor(autoAcceptState) SaveAASButton(autoAcceptState.value == savedAutoAcceptState.value) { saveAas(autoAcceptState.value, savedAutoAcceptState) } @@ -388,7 +389,7 @@ private fun AutoAcceptSection( @Composable private fun AcceptIncognitoToggle(autoAcceptState: MutableState) { PreferenceToggleWithIcon( - stringResource(R.string.accept_contact_incognito_button), + stringResource(MR.strings.accept_contact_incognito_button), if (autoAcceptState.value.incognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_theater_comedy), if (autoAcceptState.value.incognito) Indigo else MaterialTheme.colors.secondary, autoAcceptState.value.incognito, @@ -400,7 +401,7 @@ private fun AcceptIncognitoToggle(autoAcceptState: MutableState @Composable private fun WelcomeMessageEditor(autoAcceptState: MutableState) { val welcomeText = rememberSaveable { mutableStateOf(autoAcceptState.value.welcomeText) } - TextEditor(welcomeText, Modifier.height(100.dp), placeholder = stringResource(R.string.enter_welcome_message_optional)) + TextEditor(welcomeText, Modifier.height(100.dp), placeholder = stringResource(MR.strings.enter_welcome_message_optional)) LaunchedEffect(welcomeText.value) { if (welcomeText.value != autoAcceptState.value.welcomeText) { autoAcceptState.value = AutoAcceptState(autoAcceptState.value.enable, autoAcceptState.value.incognito, welcomeText.value) @@ -411,7 +412,7 @@ private fun WelcomeMessageEditor(autoAcceptState: MutableState) @Composable private fun SaveAASButton(disabled: Boolean, onClick: () -> Unit) { SectionItemView(onClick, disabled = disabled) { - Text(stringResource(R.string.save_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) + Text(stringResource(MR.strings.save_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary) } } @@ -441,9 +442,9 @@ fun PreviewUserAddressLayoutNoAddress() { private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) { AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.save_settings_question), - confirmText = generalGetString(R.string.save_auto_accept_settings), - dismissText = generalGetString(R.string.exit_without_saving), + title = generalGetString(MR.strings.save_settings_question), + confirmText = generalGetString(MR.strings.save_auto_accept_settings), + dismissText = generalGetString(MR.strings.exit_without_saving), onConfirm = save, onDismiss = revert, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt index e0d7926486..3b30c42e79 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt @@ -14,7 +14,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -28,6 +28,7 @@ import chat.simplex.app.views.isValidDisplayName import chat.simplex.app.views.onboarding.ReadableText import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.insets.navigationBarsWithImePadding +import chat.simplex.res.MR import kotlinx.coroutines.launch @Composable @@ -101,8 +102,8 @@ fun UserProfileLayout( .verticalScroll(scrollState) .padding(horizontal = DEFAULT_PADDING), ) { - AppBarTitle(stringResource(R.string.your_current_profile)) - ReadableText(generalGetString(R.string.your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it), TextAlign.Center) + AppBarTitle(stringResource(MR.strings.your_current_profile)) + ReadableText(generalGetString(MR.strings.your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it), TextAlign.Center) Column( Modifier .fillMaxWidth() @@ -125,13 +126,13 @@ fun UserProfileLayout( } Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Text( - stringResource(R.string.display_name__field), + stringResource(MR.strings.display_name__field), fontSize = 16.sp ) if (!isValidDisplayName(displayName.value)) { Spacer(Modifier.size(DEFAULT_PADDING_HALF)) Text( - stringResource(R.string.no_spaces), + stringResource(MR.strings.no_spaces), fontSize = 16.sp, color = Color.Red ) @@ -140,7 +141,7 @@ fun UserProfileLayout( ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester) Spacer(Modifier.height(DEFAULT_PADDING)) Text( - stringResource(R.string.full_name__field), + stringResource(MR.strings.full_name__field), fontSize = 16.sp, modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF) ) @@ -159,7 +160,7 @@ fun UserProfileLayout( saveColor = MaterialTheme.colors.secondary } Text( - stringResource(R.string.save_and_notify_contacts), + stringResource(MR.strings.save_and_notify_contacts), modifier = saveModifier, color = saveColor ) @@ -188,7 +189,7 @@ fun EditImageButton(click: () -> Unit) { ) { Icon( painterResource(R.drawable.ic_photo_camera), - contentDescription = stringResource(R.string.edit_image), + contentDescription = stringResource(MR.strings.edit_image), tint = MaterialTheme.colors.primary, modifier = Modifier.size(30.dp) ) @@ -200,7 +201,7 @@ fun DeleteImageButton(click: () -> Unit) { IconButton(onClick = click) { Icon( painterResource(R.drawable.ic_close), - contentDescription = stringResource(R.string.delete_image), + contentDescription = stringResource(MR.strings.delete_image), tint = MaterialTheme.colors.primary, ) } @@ -208,9 +209,9 @@ fun DeleteImageButton(click: () -> Unit) { private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) { AlertManager.shared.showAlertDialogStacked( - title = generalGetString(R.string.save_preferences_question), - confirmText = generalGetString(R.string.save_and_notify_contacts), - dismissText = generalGetString(R.string.exit_without_saving), + title = generalGetString(MR.strings.save_preferences_question), + confirmText = generalGetString(MR.strings.save_and_notify_contacts), + dismissText = generalGetString(MR.strings.exit_without_saving), onConfirm = save, onDismiss = revert, ) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt index 997d0b9f02..0b49c2d889 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/UserProfilesView.kt @@ -7,7 +7,6 @@ import SectionItemViewSpaceBetween import SectionSpacer import SectionTextFooter import SectionView -import androidx.annotation.StringRes import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.material.* @@ -16,7 +15,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -31,6 +30,8 @@ import chat.simplex.app.views.chatlist.UserProfileRow import chat.simplex.app.views.database.PassphraseField import chat.simplex.app.views.helpers.* import chat.simplex.app.views.onboarding.CreateProfile +import chat.simplex.res.MR +import dev.icerock.moko.resources.StringResource import kotlinx.coroutines.delay @Composable @@ -58,14 +59,14 @@ fun UserProfilesView(m: ChatModel, search: MutableState, profileHidden: removeUser = { user -> if (m.users.size > 1 && (user.hidden || visibleUsersCount(m) > 1)) { val text = buildAnnotatedString { - append(generalGetString(R.string.users_delete_all_chats_deleted) + "\n\n" + generalGetString(R.string.users_delete_profile_for) + " ") + append(generalGetString(MR.strings.users_delete_all_chats_deleted) + "\n\n" + generalGetString(MR.strings.users_delete_profile_for) + " ") withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append(user.displayName) } append(":") } AlertManager.shared.showAlertDialogButtonsColumn( - title = generalGetString(R.string.users_delete_question), + title = generalGetString(MR.strings.users_delete_question), text = text, buttons = { Column { @@ -73,25 +74,25 @@ fun UserProfilesView(m: ChatModel, search: MutableState, profileHidden: AlertManager.shared.hideAlert() removeUser(m, user, users, true, searchTextOrPassword.value.trim()) }) { - Text(stringResource(R.string.users_delete_with_connections), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = Color.Red) + Text(stringResource(MR.strings.users_delete_with_connections), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = Color.Red) } SectionItemView({ AlertManager.shared.hideAlert() removeUser(m, user, users, false, searchTextOrPassword.value.trim()) } ) { - Text(stringResource(R.string.users_delete_data_only), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = Color.Red) + Text(stringResource(MR.strings.users_delete_data_only), Modifier.fillMaxWidth(), textAlign = TextAlign.Center, color = Color.Red) } } } ) } else { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.cant_delete_user_profile), + title = generalGetString(MR.strings.cant_delete_user_profile), text = if (m.users.size > 1) { - generalGetString(R.string.should_be_at_least_one_visible_profile) + generalGetString(MR.strings.should_be_at_least_one_visible_profile) } else { - generalGetString(R.string.should_be_at_least_one_profile) + generalGetString(MR.strings.should_be_at_least_one_profile) } ) } @@ -158,14 +159,14 @@ private fun UserProfilesLayout( ) { if (profileHidden.value) { SectionView { - SettingsActionItem(painterResource(R.drawable.ic_lock_open), stringResource(R.string.enter_password_to_show), click = { + SettingsActionItem(painterResource(R.drawable.ic_lock_open), stringResource(MR.strings.enter_password_to_show), click = { profileHidden.value = false } ) } SectionSpacer() } - AppBarTitle(stringResource(R.string.your_chat_profiles)) + AppBarTitle(stringResource(MR.strings.your_chat_profiles)) SectionView { for (user in filteredUsers) { @@ -174,20 +175,20 @@ private fun UserProfilesLayout( } if (searchTextOrPassword.value.trim().isEmpty()) { SectionItemView(addUser, minHeight = 68.dp) { - Icon(painterResource(R.drawable.ic_add), stringResource(R.string.users_add), tint = MaterialTheme.colors.primary) + Icon(painterResource(R.drawable.ic_add), stringResource(MR.strings.users_add), tint = MaterialTheme.colors.primary) Spacer(Modifier.padding(horizontal = 4.dp)) - Text(stringResource(R.string.users_add), color = MaterialTheme.colors.primary) + Text(stringResource(MR.strings.users_add), color = MaterialTheme.colors.primary) } } } - SectionTextFooter(stringResource(R.string.tap_to_activate_profile)) + SectionTextFooter(stringResource(MR.strings.tap_to_activate_profile)) LaunchedEffect(Unit) { if (showHiddenProfilesNotice.state.value && users.size > 1) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.make_profile_private), - text = generalGetString(R.string.you_can_hide_or_mute_user_profile), - confirmText = generalGetString(R.string.ok), - dismissText = generalGetString(R.string.dont_show_again), + title = generalGetString(MR.strings.make_profile_private), + text = generalGetString(MR.strings.you_can_hide_or_mute_user_profile), + confirmText = generalGetString(MR.strings.ok), + dismissText = generalGetString(MR.strings.dont_show_again), onDismiss = { showHiddenProfilesNotice.set(false) }, @@ -217,30 +218,30 @@ private fun UserView( Box(Modifier.padding(horizontal = DEFAULT_PADDING)) { DefaultDropdownMenu(showMenu) { if (user.hidden) { - ItemAction(stringResource(R.string.user_unhide), painterResource(R.drawable.ic_lock_open), onClick = { + ItemAction(stringResource(MR.strings.user_unhide), painterResource(R.drawable.ic_lock_open), onClick = { showMenu.value = false unhideUser(user) }) } else { if (visibleUsersCount > 1) { - ItemAction(stringResource(R.string.user_hide), painterResource(R.drawable.ic_lock), onClick = { + ItemAction(stringResource(MR.strings.user_hide), painterResource(R.drawable.ic_lock), onClick = { showMenu.value = false showHiddenProfile(user) }) } if (user.showNtfs) { - ItemAction(stringResource(R.string.user_mute), painterResource(R.drawable.ic_notifications_off), onClick = { + ItemAction(stringResource(MR.strings.user_mute), painterResource(R.drawable.ic_notifications_off), onClick = { showMenu.value = false muteUser(user) }) } else { - ItemAction(stringResource(R.string.user_unmute), painterResource(R.drawable.ic_notifications), onClick = { + ItemAction(stringResource(MR.strings.user_unmute), painterResource(R.drawable.ic_notifications), onClick = { showMenu.value = false unmuteUser(user) }) } } - ItemAction(stringResource(R.string.delete_verb), painterResource(R.drawable.ic_delete), color = Color.Red, onClick = { + ItemAction(stringResource(MR.strings.delete_verb), painterResource(R.drawable.ic_delete), color = Color.Red, onClick = { removeUser(user) showMenu.value = false }) @@ -264,7 +265,7 @@ private fun ProfileActionView(action: UserProfileAction, user: User, doAction: ( val passwordValid by remember { derivedStateOf { actionPassword.value == actionPassword.value.trim() } } val actionEnabled by remember { derivedStateOf { actionPassword.value != "" && passwordValid && correctPassword(user, actionPassword.value) } } - @Composable fun ActionHeader(@StringRes title: Int) { + @Composable fun ActionHeader(title: StringResource) { AppBarTitle(stringResource(title)) SectionView(padding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) { UserProfileRow(user) @@ -272,10 +273,10 @@ private fun ProfileActionView(action: UserProfileAction, user: User, doAction: ( SectionSpacer() } - @Composable fun PasswordAndAction(@StringRes label: Int, color: Color = MaterialTheme.colors.primary) { + @Composable fun PasswordAndAction(label: StringResource, color: Color = MaterialTheme.colors.primary) { SectionView() { SectionItemView { - PassphraseField(actionPassword, generalGetString(R.string.profile_password), isValid = { passwordValid }, showStrength = true) + PassphraseField(actionPassword, generalGetString(MR.strings.profile_password), isValid = { passwordValid }, showStrength = true) } SectionItemViewSpaceBetween({ doAction(actionPassword.value) }, disabled = !actionEnabled, minHeight = TextFieldDefaults.MinHeight) { Text(generalGetString(label), color = if (actionEnabled) color else MaterialTheme.colors.secondary) @@ -285,15 +286,15 @@ private fun ProfileActionView(action: UserProfileAction, user: User, doAction: ( when (action) { UserProfileAction.DELETE -> { - ActionHeader(R.string.delete_profile) - PasswordAndAction(R.string.delete_chat_profile, color = Color.Red) + ActionHeader(MR.strings.delete_profile) + PasswordAndAction(MR.strings.delete_chat_profile, color = Color.Red) if (actionEnabled) { - SectionTextFooter(stringResource(R.string.users_delete_all_chats_deleted)) + SectionTextFooter(stringResource(MR.strings.users_delete_all_chats_deleted)) } } UserProfileAction.UNHIDE -> { - ActionHeader(R.string.unhide_profile) - PasswordAndAction(R.string.unhide_chat_profile) + ActionHeader(MR.strings.unhide_profile) + PasswordAndAction(MR.strings.unhide_chat_profile) } } SectionBottomSpacer() @@ -358,7 +359,7 @@ private suspend fun doRemoveUser(m: ChatModel, user: User, users: List, de deleteUser(user) } } catch (e: Exception) { - AlertManager.shared.showAlertMsg(generalGetString(R.string.error_deleting_user), e.stackTraceToString()) + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_deleting_user), e.stackTraceToString()) } } @@ -368,7 +369,7 @@ private suspend fun setUserPrivacy(m: ChatModel, onSuccess: (() -> Unit)? = null onSuccess?.invoke() } catch (e: Exception) { AlertManager.shared.showAlertMsg( - title = generalGetString(R.string.error_updating_user_privacy), + title = generalGetString(MR.strings.error_updating_user_privacy), text = e.stackTraceToString() ) } @@ -376,10 +377,10 @@ private suspend fun setUserPrivacy(m: ChatModel, onSuccess: (() -> Unit)? = null private fun showMuteProfileAlert(showMuteProfileAlert: SharedPreference) { AlertManager.shared.showAlertDialog( - title = generalGetString(R.string.muted_when_inactive), - text = generalGetString(R.string.you_will_still_receive_calls_and_ntfs), - confirmText = generalGetString(R.string.ok), - dismissText = generalGetString(R.string.dont_show_again), + title = generalGetString(MR.strings.muted_when_inactive), + text = generalGetString(MR.strings.you_will_still_receive_calls_and_ntfs), + confirmText = generalGetString(MR.strings.ok), + dismissText = generalGetString(MR.strings.dont_show_again), onDismiss = { showMuteProfileAlert.set(false) }, diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/VersionInfoView.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/VersionInfoView.kt index eb3f061667..e7eab47993 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/VersionInfoView.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/views/usersettings/VersionInfoView.kt @@ -6,23 +6,24 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import dev.icerock.moko.resources.compose.stringResource import chat.simplex.app.BuildConfig import chat.simplex.app.R import chat.simplex.app.model.CoreVersionInfo import chat.simplex.app.ui.theme.DEFAULT_PADDING import chat.simplex.app.views.helpers.AppBarTitle +import chat.simplex.res.MR @Composable fun VersionInfoView(info: CoreVersionInfo) { Column( Modifier.padding(horizontal = DEFAULT_PADDING), ) { - AppBarTitle(stringResource(R.string.app_version_title), false) - Text(String.format(stringResource(R.string.app_version_name), BuildConfig.VERSION_NAME)) - Text(String.format(stringResource(R.string.app_version_code), BuildConfig.VERSION_CODE)) - Text(String.format(stringResource(R.string.core_version), info.version)) + AppBarTitle(stringResource(MR.strings.app_version_title), false) + Text(String.format(stringResource(MR.strings.app_version_name), BuildConfig.VERSION_NAME)) + Text(String.format(stringResource(MR.strings.app_version_code), BuildConfig.VERSION_CODE)) + Text(String.format(stringResource(MR.strings.core_version), info.version)) val simplexmqCommit = if (info.simplexmqCommit.length >= 7) info.simplexmqCommit.substring(startIndex = 0, endIndex = 7) else info.simplexmqCommit - Text(String.format(stringResource(R.string.core_simplexmq_version), info.simplexmqVersion, simplexmqCommit)) + Text(String.format(stringResource(MR.strings.core_simplexmq_version), info.simplexmqVersion, simplexmqCommit)) } } diff --git a/apps/multiplatform/android/src/main/res/values-hr/strings.xml b/apps/multiplatform/android/src/main/res/values-hr/strings.xml deleted file mode 100644 index a6b3daec93..0000000000 --- a/apps/multiplatform/android/src/main/res/values-hr/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/apps/multiplatform/common/build.gradle.kts b/apps/multiplatform/common/build.gradle.kts index c3474f451d..880dbf729b 100644 --- a/apps/multiplatform/common/build.gradle.kts +++ b/apps/multiplatform/common/build.gradle.kts @@ -48,6 +48,8 @@ kotlin { implementation("com.godaddy.android.colorpicker:compose-color-picker-jvm:0.7.0") // Link Previews implementation("org.jsoup:jsoup:1.13.1") + // Resources + implementation("dev.icerock.moko:resources:0.22.3") } } val commonTest by getting { @@ -57,6 +59,7 @@ kotlin { } // LALAL CHANGE TO IMPLEMENTATION val androidMain by getting { + kotlin.srcDir("./build/generated/moko/commonMain/src/") dependencies { api("androidx.appcompat:appcompat:1.5.1") api("androidx.core:core-ktx:1.9.0") @@ -105,7 +108,6 @@ kotlin { } val desktopMain by getting { dependencies { - implementation("dev.icerock.moko:resources:0.22.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.7.1") } } @@ -127,7 +129,7 @@ android { } multiplatformResources { - multiplatformResourcesPackage = "com.icerockdev.library" + multiplatformResourcesPackage = "chat.simplex.res" // multiplatformResourcesClassName = "MR" } diff --git a/apps/multiplatform/android/src/main/res/values-ar/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml similarity index 89% rename from apps/multiplatform/android/src/main/res/values-ar/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml index c3919f84e8..20fdcaa477 100644 --- a/apps/multiplatform/android/src/main/res/values-ar/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ar/strings.xml @@ -1,7 +1,7 @@ - + اقبل - عن ٍSimpleX + عن ٍSimpleX a + b اقبل اسبوع 1 @@ -87,7 +87,7 @@ إلغاء معاينة الصورة الكاميرا إلغاء معاينة الارتباط - سيتم استخدام اتصال TCP منفصل (وبيانات اعتماد SOCKS) لكل ملف تعريف دردشة لديك في التطبيق . + لكل ملف تعريف دردشة لديك في التطبيق .]]> ألغيت %s رابط لمرة واحدة 5 دقائق @@ -97,11 +97,11 @@ يمكنك أنت وجهة الاتصال الخاصة بك إرسال رسائل تختفي. مكالمتك تحت الإجراء لا يمكن استقبال الملف - جيد للبطارية . خدمة الخلفية تتحقق من الرسائل كل 10 دقائق. قد تفوتك مكالمات أو رسائل عاجلة. - عريض + جيد للبطارية . خدمة الخلفية تتحقق من الرسائل كل 10 دقائق. قد تفوتك مكالمات أو رسائل عاجلة.]]> + عريض مكالمات الصوت (ليست مشفرة بين الطرفين) - الأفضل للبطارية . ستتلقى إشعارات فقط عندما يكون التطبيق قيد التشغيل (لا توجد خدمة في الخلفية). - تستهلك المزيد من البطارية ! تعمل خدمة الخلفية دائمًا - تظهر الإشعارات بمجرد توفر الرسائل. + الأفضل للبطارية . ستتلقى إشعارات فقط عندما يكون التطبيق قيد التشغيل (لا توجد خدمة في الخلفية).]]> + تستهلك المزيد من البطارية ! تعمل خدمة الخلفية دائمًا - تظهر الإشعارات بمجرد توفر الرسائل.]]> انتهت المكالمة بالفعل! تجزئة رسالة سيئة معرف رسالة سيئ @@ -112,9 +112,9 @@ \nمتوفر في v5.1" مكالمات الصوت/الفيديو محظورة. عن طريق ملف تعريف الدردشة (افتراضي) أو عن طريق الاتصال (تجريبي). - يمكن تعطيله عبر الإعدادات - سيستمر عرض الإشعارات أثناء تشغيل التطبيق. + يمكن تعطيله عبر الإعدادات - سيستمر عرض الإشعارات أثناء تشغيل التطبيق.]]> مكالمات الصوت والفيديو - الرجاء ملاحظة : لن تتمكن من استعادة عبارة المرور أو تغييرها في حالة فقدها. + الرجاء ملاحظة : لن تتمكن من استعادة عبارة المرور أو تغييرها في حالة فقدها.]]> يمكنك أنت وجهة الاتصال الخاصة بك حذف الرسائل المرسلة بشكل لا رجعة فيه. قبول طلبات الاتصال تلقائيًا فشلت المصادقة @@ -147,10 +147,10 @@ تم تغيير العنوان من أجلك لا يمكن حذف ملف تعريف المستخدم! طلب لاستلام الفيديو - إضافة جهة اتصال جديدة : لإنشاء رمز الاستجابة السريعة الخاص بك لمرة واحدة لجهة الاتصال الخاصة بك. - امسح رمز الاستجابة السريعة : للاتصال بجهة الاتصال التي تعرض لك رمز الاستجابة السريعة. + إضافة جهة اتصال جديدة : لإنشاء رمز الاستجابة السريعة الخاص بك لمرة واحدة لجهة الاتصال الخاصة بك.]]> + امسح رمز الاستجابة السريعة : للاتصال بجهة الاتصال التي تعرض لك رمز الاستجابة السريعة.]]> مكالمتك تحت الإجراء - انتهت المكالمة <xliff:g xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" id=\"duration\" example=\"01:15\"> + انتهت المكالمة تغيير عبارة مرور قاعدة البيانات؟ لا يمكن الوصول إلى Keystore لحفظ كلمة مرور قاعدة البيانات إلغاء معاينة الملف @@ -162,4 +162,6 @@ رسائل أفضل يمكنك أنت وجهة الاتصال الخاصة بك إرسال رسائل صوتية. يمكنك أنت وجهة الاتصال إجراء مكالمات. + بحث + غير مفعّل \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index bd82c3c944..75a6bf3546 100644 --- a/apps/multiplatform/android/src/main/res/values/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1,5 +1,5 @@ - - SimpleX + + SimpleX k @@ -19,7 +19,7 @@ error connecting You are connected to the server used to receive messages from this contact. - Trying to connect to the server used to receive messages from this contact (error: %1$s). + Trying to connect to the server used to receive messages from this contact (error: %1$s). Trying to connect to the server used to receive messages from this contact. @@ -38,7 +38,7 @@ Decryption error - connection %1$d + connection %1$d connection established invited to connect connecting… @@ -55,7 +55,7 @@ SimpleX contact address SimpleX one-time invitation SimpleX group link - via %1$s + via %1$s SimpleX links Description Full link @@ -81,7 +81,7 @@ Connection timeout Connection error - Please check your network connection with %1$s and try again. + Please check your network connection with %1$s and try again. Error sending message Error loading details Error adding member(s) @@ -91,7 +91,7 @@ Error receiving file Error creating address Contact already exists - You are already connected to %1$s. + You are already connected to %1$s. Invalid connection link Please check that you used the correct link or ask your contact to send you another one. Connection error (AUTH) @@ -126,9 +126,9 @@ Instant notifications Instant notifications! Instant notifications are disabled! - To preserve your privacy, instead of push notifications the app has a SimpleX background service – it uses a few percent of the battery per day. - It can be disabled via settings – notifications will still be shown while the app is running. - In order to use it, please disable battery optimization for SimpleX in the next dialog. Otherwise, the notifications will be disabled. + SimpleX background service – it uses a few percent of the battery per day.]]> + It can be disabled via settings – notifications will still be shown while the app is running.]]> + disable battery optimization for SimpleX in the next dialog. Otherwise, the notifications will be disabled.]]> Battery optimization is active, turning off background service and periodic requests for new messages. You can re-enable them via settings. Periodic notifications Periodic notifications are disabled! @@ -139,7 +139,7 @@ The database is not working correctly. Tap to learn more - SimpleX Chat service + SimpleX Chat service Receiving messages… Hide @@ -215,6 +215,7 @@ Save Edit Info + Search Sent message Received message History @@ -250,7 +251,7 @@ unread - Welcome %1$s! + Welcome %1$s! Welcome! This text is available in settings Chats @@ -307,8 +308,8 @@ File Large file! - Your contact sent a file that is larger than currently supported maximum size (%1$s). - Currently maximum supported file size is %1$s. + Your contact sent a file that is larger than currently supported maximum size (%1$s). + Currently maximum supported file size is %1$s. Waiting for file File will be received when your contact completes uploading it. File will be received when your contact is online, please wait or check later! @@ -318,7 +319,7 @@ Voice message - Voice message (%1$s) + Voice message (%1$s) Voice message… @@ -391,17 +392,17 @@ Video - Thank you for installing SimpleX Chat! - You can connect to SimpleX Chat developers to ask any questions and to receive updates. + Thank you for installing SimpleX Chat! + connect to SimpleX Chat developers to ask any questions and to receive updates.]]> To start a new chat Tap button above, then: - Add new contact: to create your one-time QR Code for your contact. - Scan QR code: to connect to your contact who shows QR code to you. + Add new contact: to create your one-time QR Code for your contact.]]> + Scan QR code: to connect to your contact who shows QR code to you.]]> To connect via link - If you received SimpleX Chat invitation link, you can open it in your browser: - 💻 desktop: scan displayed QR code from the app, via Scan QR code. - 📱 mobile: tap Open in mobile app, then tap Connect in the app. + If you received SimpleX Chat invitation link, you can open it in your browser: + Scan QR code.]]> + Open in mobile app, then tap Connect in the app.]]> Accept connection request? @@ -453,10 +454,10 @@ cancel link preview Settings QR Code - SimpleX Address + SimpleX Address help - SimpleX Team - SimpleX Logo + SimpleX Team + SimpleX Logo Email More @@ -472,9 +473,9 @@ You will be connected to group when the group host\'s device is online, please wait or check later! You will be connected when your connection request is accepted, please wait or check later! You will be connected when your contact\'s device is online, please wait or check later! - If you can\'t meet in person, show QR code in the video call, or share the link. + show QR code in the video call, or share the link.]]> Your chat profile will be sent\nto your contact - If you cannot meet in person, you can scan QR code in the video call, or your contact can share an invitation link. + scan QR code in the video call, or your contact can share an invitation link.]]> Share 1-time link Paste the link you received into the box below to connect with your contact. Your chat profile will be sent to your contact @@ -489,14 +490,14 @@ You can share your address as a link or QR code - anybody can connect to you. You won\'t lose your contacts if you later delete your address. When people request to connect, you can accept or reject it. - Read more in User Guide. + User Guide.]]> Connect via link Connect Paste This string is not a connection link! - You can also connect by clicking the link. If it opens in the browser, click Open in mobile app button. + Open in mobile app button.]]> Create one-time invitation link @@ -522,7 +523,7 @@ Your SimpleX address Your chat profiles Database passphrase & export - About SimpleX Chat + About SimpleX Chat How to use it Markdown help Markdown in messages @@ -553,14 +554,14 @@ The servers for new connections of your current chat profile Save servers? XFTP servers - Install SimpleX Chat for terminal + Install SimpleX Chat for terminal Star on GitHub Contribute Rate the app - Use SimpleX Chat servers? + Use SimpleX Chat servers? Your SMP servers Your XFTP servers - Using SimpleX Chat servers. + Using SimpleX Chat servers. How to How to use your servers Saved WebRTC ICE servers will be removed. @@ -596,10 +597,10 @@ Transport isolation Chat profile Connection - A separate TCP connection (and SOCKS credential) will be used for each chat profile you have in the app. - A separate TCP connection (and SOCKS credential) will be used for each contact and group member.\nPlease note: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail. + for each chat profile you have in the app.]]> + for each contact and group member.\nPlease note: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail.]]> Update transport isolation mode? - Set Use .onion hosts to No if SOCKS proxy does not support them. + Use .onion hosts to No if SOCKS proxy does not support them.]]> Appearance Customize theme THEME COLORS @@ -649,7 +650,7 @@ Display name: "Full name: Your current profile - Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. + Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile. Edit image Delete image Save preferences? @@ -684,12 +685,12 @@ How to use markdown You can use markdown to format messages: - bold - italic - strike + bold + italic + strike a + b - colored - secret + colored + secret calling… @@ -698,7 +699,7 @@ accepted call connecting call… call in progress - call ended %1$s + call ended %1$s call error @@ -724,13 +725,13 @@ How it works - How SimpleX works - Many people asked: if SimpleX has no user identifiers, how can it deliver messages? - To protect privacy, instead of user IDs used by all other platforms, SimpleX has identifiers for message queues, separate for each of your contacts. - You control through which server(s) to receive the messages, your contacts – the servers you use to message them. - Only client devices store user profiles, contacts, groups, and messages sent with 2-layer end-to-end encryption. + How SimpleX works + if SimpleX has no user identifiers, how can it deliver messages?]]> + To protect privacy, instead of user IDs used by all other platforms, SimpleX has identifiers for message queues, separate for each of your contacts. + to receive the messages, your contacts – the servers you use to message them.]]> + 2-layer end-to-end encryption.]]> Read more in our GitHub repository. - Read more in our GitHub repository. + GitHub repository.]]> Use chat @@ -739,9 +740,9 @@ When app is running Periodic Instant - Best for battery. You will receive notifications only when the app is running (NO background service). - Good for battery. Background service checks messages every 10 minutes. You may miss calls or urgent messages. - Uses more battery! Background service always runs – notifications are shown as soon as messages are available. + Best for battery. You will receive notifications only when the app is running (NO background service).]]> + Good for battery. Background service checks messages every 10 minutes. You may miss calls or urgent messages.]]> + Uses more battery! Background service always runs – notifications are shown as soon as messages are available.]]> Paste received link @@ -749,7 +750,7 @@ Incoming video call Incoming audio call - %1$s wants to connect with you via + %1$s wants to connect with you via video call (not e2e encrypted) e2e encrypted video call audio call (not e2e encrypted) @@ -775,7 +776,7 @@ Relay server is only used if necessary. Another party can observe your IP address. - Open SimpleX Chat to accept call + Open SimpleX Chat to accept call Enable calls from lock screen via Settings. Open @@ -805,7 +806,7 @@ Answer call - %1$d skipped message(s) + %1$d skipped message(s) bad message hash bad message ID duplicate message @@ -815,8 +816,8 @@ The hash of the previous message is different." Bad message ID The ID of the next message is incorrect (less or equal to the previous).\nIt can happen because of some bug or when the connection is compromised. - %1$d messages failed to decrypt. - %1$d messages skipped. + %1$d messages failed to decrypt. + %1$d messages skipped. It can happen when you or your connection used the old database backup. This error is permanent for this connection, please re-connect. Please report it to the developers. @@ -838,6 +839,7 @@ Authentication cancelled System Passcode + Off Passcode set! Passcode changed! Passcode not changed! @@ -950,7 +952,7 @@ Your chat database is not encrypted - set passphrase to protect it. Android Keystore is used to securely store passphrase - it allows notification service to work. Database is encrypted using a random passphrase, you can change it. - Please note: you will NOT be able to recover or change passphrase if you lose it. + Please note: you will NOT be able to recover or change passphrase if you lose it.]]> Android Keystore will be used to securely store passphrase after you restart the app or change passphrase - it will allow receiving notifications. You have to enter passphrase every time the app starts - it is not stored on the device. Encrypt database? @@ -1007,11 +1009,11 @@ CHAT ARCHIVE Save archive Delete archive - Created on %1$s + Created on %1$s Delete chat archive? - invitation to group %1$s + invitation to group %1$s Join group? You are invited to group. Join to connect with group members. Join @@ -1040,19 +1042,19 @@ Group invitation expired - invited %1$s + invited %1$s connected left changed role of %s to %s changed your role to %s - removed %1$s + removed %1$s removed you deleted group updated group profile invited via your group link you changed role of %s to %s you changed role for yourself to %s - you removed %1$s + you removed %1$s you left group profile updated @@ -1102,8 +1104,8 @@ Invite members - %1$s MEMBERS - you: %1$s + %1$s MEMBERS + you: %1$s Delete group Delete group? Group will be deleted for all members - this cannot be undone! @@ -1166,7 +1168,7 @@ Group Connection direct - indirect (%1$s) + indirect (%1$s) Welcome message @@ -1202,6 +1204,7 @@ sec TCP connection timeout Protocol timeout + Protocol timeout per KB PING interval PING count Enable TCP keep-alive @@ -1285,7 +1288,7 @@ no always on - off + off` Chat preferences Contact preferences Group preferences diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/bn/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/bn/strings.xml new file mode 100644 index 0000000000..13e322f078 --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/bn/strings.xml @@ -0,0 +1,46 @@ + + + রং + ১ দিন + ১ মিনিট + এককালীন সংযোগ-সূত্র + ৩০ সেকেন্ড + SimpleX সম্পর্কে + SimpleX ঠিকানা সম্পর্কে জানুন + থামুন + ঠিকানা পরিবর্তন বাতিল করতে চান\? + ৫ মিনিট + উপরে, তারপর + গ্রহণ করুন + গ্রহণ করুন + ঠিকানা পরিবর্তন থামান + গ্রহণ করুন + ১ মাস + ১ সপ্তাহ + About SimpleX Chat + গ্রহণ করুন + সংযোগের অনুরোধটি গ্রহণ করবেন কি\? + কলটি গৃহীত হয়েছে + পূর্বনির্ধারিত সার্ভারগুলি যুক্ত করুন + অ্যাডমিন + স্বাগত বার্তা যুক্ত করুন + প্রোফাইল যুক্ত করুন + আনুষঙ্গিক রং + অ্যাডমিনরা গ্রুপে যোগদানের সংযোগ-সূত্র তৈরি করতে পারবেন। + QR কোড স্ক্যান করে সার্ভার যুক্ত করুন। + সার্ভার যুক্ত করুন… + ঠিকানা + ঠিকানা পরিবর্তন বাতিল করা হবে। বার্তা গ্রহণের পুরনো ঠিকানা ব্যবহার করা হবে। + অ্যাপের সকল তথ্য মুছে ফেলা হয়েছে। + আরেকটি যন্ত্রে যুক্ত করুন + সকল আলাপ এবং বার্তা মুছে ফেলা হবে - এটি আর পূর্বাবস্থায় ফেরানো যাবে না! + এটি প্রবেশ করালে সকল তথ্য মুছে ফেলা হবে। + অগ্রবর্তী নেটওয়ার্ক সেটিংস + হাজার + আমন্ত্রণের সংযোগ-সূত্র দ্বারা যুক্ত হতে চান\? + যোগাযোগের সংযোগ-সূত্র দ্বারা যুক্ত হতে চান\? + গ্রুপের সংযোগ-সূত্র দ্বারা যুুক্ত হতে চান\? + গুপ্ত-পরিচয় গ্রহণ করুন + সার্চ + বন্ধ আছে + \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-cs/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-cs/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml index 932d4df232..431b494d29 100644 --- a/apps/multiplatform/android/src/main/res/values-cs/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/cs/strings.xml @@ -1,5 +1,5 @@ - + Povolit hlasové zprávy, pokud je váš kontakt povolí. Mizící zprávy povoleny. Hlasové zprávy povoleny. @@ -12,7 +12,7 @@ Přistupovat k serverům přes SOCKS proxy na portu %d\? Před povolením této možnosti musí být spuštěna proxy. Přijmout Povolte svým kontaktům odesílat mizící zprávy. - O SimpleX Chat + O SimpleX Chat Přidat do jiného zařízení Povolit Povolit hlasové zprávy\? @@ -43,7 +43,7 @@ ČLEN Změnit roli ve skupině\? Připoj - nepřímé (%1$s) + nepřímé (%1$s) SERVERY Příjímáno přez Vytvoření tajné skupiny @@ -84,7 +84,7 @@ Vaše kontakty mohou povolit úplné mazání zpráv. Mizící zprávy Porovnejte bezpečnostní kódy se svými kontakty. - SimpleX + SimpleX k Připojit se odkazem\? Připojit se pozvánkou\? @@ -97,7 +97,7 @@ smazáno neplatný chat neplatná data - spojení %1$d + spojení %1$d spojení navázáno pozvánka k připojení připojování… @@ -111,7 +111,7 @@ SimpleX adresa Jednorázová pozvánka SimpleX Skupinový odkaz SimpleX - prostřednictvím %1$s + prostřednictvím %1$s Odkazy na SimpleX Popis Úplný odkaz @@ -124,11 +124,11 @@ Aktualizujte aplikaci a kontaktujte vývojáře. Časový limit připojení Chyba připojení - Zkontrolujte prosím své síťové připojení pomocí %1$s a zkuste to znovu. + Zkontrolujte prosím své síťové připojení pomocí %1$s a zkuste to znovu. Chyba odesílání zprávy Chyba přidávání členů Kontakt již existuje - Jste již připojeni k %1$s. + Jste již připojeni k %1$s. Neplatný odkaz na spojení Chyba příjmu požadavku od kontaktu Chyba změny adresy @@ -146,7 +146,7 @@ Sdílet Kopírovat nepřečteno - Vítejte %1$s! + Vítejte %1$s! Vítejte! Tento text je k dispozici v nastavení odeslání se nezdařilo @@ -160,8 +160,8 @@ Obrázek odeslán Čekám na obrázek Obrázek bude přijat, až bude váš kontakt online, vyčkejte prosím nebo se podívejte později! - Váš kontakt odeslal soubor, který je větší než aktuálně podporovaná maximální velikost (%1$s). - V současné době je maximální podporovaná velikost souboru %1$s. + Váš kontakt odeslal soubor, který je větší než aktuálně podporovaná maximální velikost (%1$s). + V současné době je maximální podporovaná velikost souboru %1$s. Chyba ukládání souboru Hlasová zpráva Hlasová zpráva… @@ -193,9 +193,9 @@ Pro zahájení nové konverzace Klepněte na tlačítko potom: - Přidejte nový kontakt: vytvořte jednorázý QR kód pro váš kontakt. - Naskenujte QR kód: připojíte se ke kontaktu, který vám QR kód ukázal. - 💻 počítač: naskenujte QR kód z aplikace přez Skenovat QR kód. + Přidejte nový kontakt: vytvořte jednorázý QR kód pro váš kontakt.]]> + Naskenujte QR kód: připojíte se ke kontaktu, který vám QR kód ukázal.]]> + Skenovat QR kód.]]> Vyčistit chat\? Vyčistit Označit jako přečteno @@ -206,8 +206,8 @@ Kontakt, se kterým jste tento odkaz sdíleli, se NEBUDE moci připojit! Připojení, které jste přijali, bude zrušeno! help - SimpleX Tým - SimpleX Adresa + SimpleX Tým + SimpleX Adresa Ke skupině budete připojeni, až bude zařízení hostitele skupiny online, vyčkejte prosím nebo se podívejte později! Budete připojeni, jakmile bude vaše žádost o připojení přijata, vyčkejte prosím nebo se podívejte později! Požadavek na připojení byl odeslán! @@ -246,12 +246,12 @@ Vytvořit profil Profil je sdílen pouze s vašimi kontakty. Zobrazované jméno nesmí obsahovat mezery. - tučně + tučně probíhající hovor Decentralizovaná Jak to funguje - Jak funguje SimpleX - Pouze klientská zařízení ukládají uživatelské profily, kontakty, skupiny a zprávy odesílané pomocí 2 vrstvého koncového šifrování. + Jak funguje SimpleX + 2 vrstvého koncového šifrování.]]> Oznámení Pravidelné Ignorovat @@ -260,7 +260,7 @@ audio hovor Audio a video hovory Hovory na uzamčené obrazovce: - Otevřete SimpleX Chat pro přijetí hovoru + Otevřete SimpleX Chat pro přijetí hovoru Povolte volání ze zamčené obrazovky prostřednictvím Nastavení. Otevřený Zvuk zapnut @@ -301,7 +301,7 @@ Zadejte prosím správnou aktuální přístupovou frázi. Chat databáze není šifrována - nastavte přístupovou frázi pro její ochranu. K bezpečnému uložení přístupové fráze slouží úložiště klíčů Android - umožňuje fungování služby oznámení. - Upozornění: pokud přístupovou frázi ztratíte, NEBUDE možné ji obnovit ani změnit. + Upozornění: pokud přístupovou frázi ztratíte, NEBUDE možné ji obnovit ani změnit.]]> Databáze bude šifrována a přístupová fráze bude uložena v úložišti klíčů. Heslo uložte bezpečně, v případě jeho ztráty jej NEBUDE možné změnit. Soubor: %s @@ -321,7 +321,7 @@ Nelze pozvat kontakty! změnili jste roli %s na %s změnili jste svou roli na %s - odebrali jste %1$s + odebrali jste %1$s odešli jste změnila se vaše adresa Rozšířit výběr rolí @@ -330,8 +330,8 @@ Vytvořit frontu Zabezpečit frontu Okamžitá oznámení! - V nastavení ji lze vypnout - oznámení se budou zobrazovat pokud aplikace běží. - Chcete-li ji používat, vypněte optimalizaci baterie pro SimpleX v dalším dialogu. V opačném případě budou oznámení vypnuta. + V nastavení ji lze vypnout - oznámení se budou zobrazovat pokud aplikace běží.]]> + vypněte optimalizaci baterie pro SimpleX v dalším dialogu. V opačném případě budou oznámení vypnuta.]]> Aplikace pravidelně načítá nové zprávy - denně spotřebuje několik procent baterie. Aplikace nepoužívá push oznámení - data ze zařízení nejsou odesílána na servery. Je vyžadována přístupová fráze Chcete-li dostávat oznámení, zadejte přístupovou frázi do databáze. @@ -344,13 +344,13 @@ Potvrdit Pošlete nám e-mail Zámek SimpleX - Instalovat SimpleX Chat terminál + Instalovat SimpleX Chat terminál Hvězdu na GitHubu Ohodnoťte aplikaci Vaše servery SMP Pokud potvrdíte, budou servery zasílající zprávy vidět vaši IP adresu a váš poskytovatel - ke kterým serverům se připojujete. - barevné - tajné + barevné + tajné volání… připojen ukončen @@ -375,7 +375,7 @@ Smazat čekající připojení\? Nastavení QR kód - Pokud se nemůžete setkat osobně, ukažte ve videohovoru QR kód nebo sdílejte odkaz. + videohovoru QR kód nebo sdílejte odkaz.]]> Skenovat kód Nesprávný bezpečnostní kód! Naskenujte bezpečnostní kód z aplikace vašeho kontaktu. @@ -396,9 +396,9 @@ Smazat adresu Celé jméno: Váš současný profil - Pro zachování vašeho soukromí používá aplikace místo push oznámení SimpleX službu na pozadí - denně využije několik procent baterie. + SimpleX službu na pozadí - denně využije několik procent baterie.]]> Pravidelná oznámení - SimpleX Chat služba + SimpleX Chat služba Příjem zpráv… Zprávy SimpleX Chat Zobrazení náhledu @@ -427,7 +427,7 @@ Soubor bude přijat, až bude váš kontakt online, vyčkejte prosím, nebo se podívejte později! Soubor uložen Soubor nenalezen - Hlasová zpráva (%1$s) + Hlasová zpráva (%1$s) Kontakt a všechny zprávy budou smazány - nelze to vzít zpět! Smazat kontakt Nastavení jména kontaktu… @@ -505,7 +505,7 @@ Připojíte se ke skupině, na kterou odkazuje tento odkaz, a spojíte se s jejími členy. Připojení Jste připojeni k serveru, který se používá k přijímání zpráv od tohoto kontaktu. - Pokoušíte se připojit k serveru používaném pro příjem zpráv od tohoto kontaktu (chyba: %1$s). + Pokoušíte se připojit k serveru používaném pro příjem zpráv od tohoto kontaktu (chyba: %1$s). označit jako smazáno Odesílání souborů zatím není podporováno Přijímání souborů zatím není podporováno @@ -581,12 +581,12 @@ Odeslat živou zprávu Živá zpráva! Připojit se prostřednictvím odkazu / QR kódu - Děkujeme za instalaci SimpleX Chat! - Můžete se připojit k SimpleX Chat vývojářům, položit jim případné dotazy a získat aktualizace. + Děkujeme za instalaci SimpleX Chat! + připojit k SimpleX Chat vývojářům, položit jim případné dotazy a získat aktualizace.]]> Připojení prostřednictvím odkazu - Pokud jste dostali SimpleX Chat pozvánku, můžete ji otevřít v prohlížeči: + Pokud jste dostali SimpleX Chat pozvánku, můžete ji otevřít v prohlížeči: Pokud zvolíte odmítnutí, odesílatel NEBUDE upozorněn. - 📱 telefon: Otevřete v mobilní aplikaci, potom klikněte na Připojit. + Otevřete v mobilní aplikaci, potom klikněte na Připojit.]]> Odmítnout Smazat chat Vyčistit @@ -602,7 +602,7 @@ Kontakt ještě není připojen! náhled odkazu Zrušit náhled odkazu - SimpleX Logo + SimpleX Logo E-mail Více Zobrazit QR kód @@ -610,12 +610,12 @@ Tento QR kód není odkaz! Neplatný odkaz! Tento odkaz není platným odkazem pro připojení! - Pokud se nemůžete setkat osobně, můžete skenovat QR kód ve videohovoru nebo může váš kontakt sdílet pozvánku. + skenovat QR kód ve videohovoru nebo může váš kontakt sdílet pozvánku.]]> Připojte se prostřednictvím odkazu Připojit Vložit Tento řetězec není odkazem na připojení! - Můžete se také připojit kliknutím na odkaz. Pokud se otevře v prohlížeči, klikněte na tlačítko Otevřít v mobilní aplikaci. + Otevřít v mobilní aplikaci.]]> %s není ověřeno Návod k použití Nápověda k markdown @@ -628,8 +628,8 @@ Použít server Použít pro nová připojení Servery pro nová připojení vašeho aktuálního chat profilu. - Použít SimpleX Chat servery\? - Použití SimpleX Chat serverů. + Použít SimpleX Chat servery\? + Použití SimpleX Chat serverů. Uložené servery WebRTC ICE budou odstraněny. Chyba ukládání serverů ICE Ujistěte se, že adresy serverů WebRTC ICE jsou ve správném formátu, oddělené na řádcích a nejsou duplicitní. @@ -644,7 +644,7 @@ Onion hostitelé budou použiti, pokud jsou k dispozici. Pro připojení budou vyžadováni Onion hostitelé. Izolace přenosu - A separate TCP connection (and SOCKS credential) will be used for each chat profile you have in the app. + for each chat profile you have in the app.]]> Oddělit TCP připojení (a SOCKS pověření) bude použito pro všechny kontakty a členy skupin. \nUpozornění: Pokud máte mnoho připojení, může být spotřeba baterie a provoz podstatně vyšší a některá připojení mohou selhat. Vzhled @@ -654,7 +654,7 @@ Smazat adresu\? Všechny vaše kontakty zůstanou připojeny. Zobrazované jméno: - Váš profil je uložen v zařízení a je sdílen pouze s vašimi kontakty. SimpleX servery váš profil vidět nemohou. + Váš profil je uložen v zařízení a je sdílen pouze s vašimi kontakty. SimpleX servery váš profil vidět nemohou. Uložit předvolby\? Uložit a upozornit kontakt Uložit a upozornit kontakty @@ -666,12 +666,12 @@ Vytvořit Jak používat markdown K formátování zpráv můžete použít markdown: - kurzíva - přeškrtnout + kurzíva + přeškrtnout zmeškané volání odmítnutý hovor spojovací hovor… - hovor ukončen %1$s + hovor ukončen %1$s začíná… čeká na odpověď… čekání na potvrzení… @@ -681,22 +681,22 @@ Nové vymezení soukromí 1. platforma bez jakýchkoliv uživatelských identifikátorů – soukromá již od návrhu. Odolná vůči spamu a zneužití - K ochraně soukromí, místo uživatelských ID užívaných všemi ostatními platformami, SimpleX používá identifikátory pro fronty zpráv, zvlášť pro každý z vašich kontaktů. - Mnoho lidí se ptá: když SimpleX nemá žádný identifikátor uživatelů, jak může doručovat zprávy\? - Vy určujete, přes které servery přijímat zprávy, vaše kontakty – servery, které používáte k zasílání zpráv. + K ochraně soukromí, místo uživatelských ID užívaných všemi ostatními platformami, SimpleX používá identifikátory pro fronty zpráv, zvlášť pro každý z vašich kontaktů. + když SimpleX nemá žádný identifikátor uživatelů, jak může doručovat zprávy\?]]> + přijímat zprávy, vaše kontakty – servery, které používáte k zasílání zpráv.]]> Další informace najdete v našem repozitáři na GitHubu. - Další informace najdete v našem úložišti GitHub. + úložišti GitHub.]]> Použijte chat Lze změnit později v nastavení. Když aplikace běží Okamžité - Nejlepší pro baterii. Budete přijímat oznámení pouze když aplikace běží (žádná služba na pozadí). - Dobré pro baterii. Služba na pozadí bude kontrolovat každých 10 minut. Můžete zmeškat hovory nebo naléhavé zprávy. - Využívá více baterie! Služba na pozadí je spuštěna vždy - oznámení se zobrazí, jakmile jsou zprávy k dispozici. + Nejlepší pro baterii. Budete přijímat oznámení pouze když aplikace běží (žádná služba na pozadí).]]> + Dobré pro baterii. Služba na pozadí bude kontrolovat každých 10 minut. Můžete zmeškat hovory nebo naléhavé zprávy.]]> + Využívá více baterie! Služba na pozadí je spuštěna vždy - oznámení se zobrazí, jakmile jsou zprávy k dispozici.]]> Vložení přijatého odkazu Příchozí videohovor Příchozí zvukový hovor - %1$s se s vámi chce spojit prostřednictvím + %1$s se s vámi chce spojit prostřednictvím videohovoru (nešifrovaného e2e). zvukový hovor (nešifrováno e2e) Odmítnout @@ -716,7 +716,7 @@ Spojování hovoru Skončený hovor Přijmout hovor - %1$d přeskočená zpráva (zprávy) + %1$d přeskočená zpráva (zprávy) Může se to stát, když: \n1. Zprávy vypršely v odesílajícím klientovi po 2 dnech nebo na serveru po 30 dnech. \n2. Dešifrování zprávy se nezdařilo, protože vy nebo váš kontakt jste použili starou zálohu databáze. @@ -790,8 +790,8 @@ Chat můžete spustit v Nastavení / Databáze nebo restartováním aplikace. Uložit archiv Smazat archiv - pozvánka do skupiny %1$s - Vytvořeno dne %1$s + pozvánka do skupiny %1$s + Vytvořeno dne %1$s Jste zváni do skupiny. Připojte se k členům skupiny. Připojit se inkognito Připojit ke skupině @@ -808,11 +808,11 @@ Připojili jste se k této skupině Odmítli jste pozvánku do skupiny Platnost pozvánky do skupiny vypršela - pozval %1$s + pozval %1$s připojen změnil roli %s na %s změnil svou roli na %s - odstraněn %1$s + odstraněn %1$s odstranil vás skupina odstraněna aktualizoval profil skupiny @@ -845,8 +845,8 @@ Zkontrolované kontakty %d kontakt(y) vybrán(y) Pozvat členy - %1$s MEMBERS - vy: %1$s + %1$s MEMBERS + vy: %1$s Smazat skupinu Smazat skupinu\? Skupina bude smazána pro všechny členy - nelze to vzít zpět! @@ -1074,7 +1074,7 @@ Zámek SimpleX není povolen! Zámek SimpleX můžete zapnout v Nastavení. Port - Nastavte Použít .onion hostitele na Ne, pokud je SOCKS proxy nepodporuje. + Použít .onion hostitele na Ne, pokud je SOCKS proxy nepodporuje.]]> Vaše XFTP servery Povolit zámek Zamknout po @@ -1096,8 +1096,8 @@ Hash předchozí zprávy se liší. ID další zprávy je nesprávné (menší nebo rovno předchozí). \nMůže se to stát kvůli nějaké chybě, nebo pokud je spojení kompromitováno. - %1$d zprávy se nepodařilo dešifrovat. - %1$d zprývy přeskočeny. + %1$d zprávy se nepodařilo dešifrovat. + %1$d zprývy přeskočeny. Nahlaste to prosím vývojářům. Tato chyba je pro toto připojení trvalá, připojte se znovu. Může se to stát, když vy nebo vaše připojení použijete starou zálohu databáze. @@ -1145,6 +1145,7 @@ Vybrat Chyba načítání podrobností Info + Hledat Otevřít chat profily Historie Přijatá zpráva @@ -1195,7 +1196,7 @@ Chyba nastavení adresy Pro připojení může váš kontakt naskenovat QR kód, nebo použít odkaz v aplikaci. Když někdo požádá o připojení, můžete žádost přijmout nebo odmítnout. - Přečtěte si více v Uživatelské příručce. + Uživatelské příručce.]]> Adresa SimpleX BARVY MOTIVU Přizpůsobit motiv @@ -1266,4 +1267,5 @@ Oznámení přestanou fungovat až do nového spuštění aplikace Vypnout Restartovat + Vypnuto \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-de/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-de/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml index 5c265adfeb..97402b4871 100644 --- a/apps/multiplatform/android/src/main/res/values-de/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/de/strings.xml @@ -1,6 +1,6 @@ - - SimpleX + + SimpleX k Über den Kontakt-Link verbinden? @@ -14,7 +14,7 @@ Fehler Verbinde Sie sind mit dem Server verbunden, der für den Empfang von Nachrichten mit diesem Kontakt genutzt wird. - Beim Versuch die Verbindung mit dem Server aufzunehmen, der für den Empfang von Nachrichten mit diesem Kontakt genutzt wird, ist ein Fehler aufgetreten (Fehler: %1$s). + Beim Versuch die Verbindung mit dem Server aufzunehmen, der für den Empfang von Nachrichten mit diesem Kontakt genutzt wird, ist ein Fehler aufgetreten (Fehler: %1$s). Versuche die Verbindung mit dem Server aufzunehmen, der für den Empfang von Nachrichten mit diesem Kontakt genutzt wird. Gelöscht @@ -25,7 +25,7 @@ Unbekanntes Nachrichtenformat Unzulässiges Nachrichtenformat - verbindung %1$d + verbindung %1$d verbindung hergestellt für eine Verbindung eingeladen verbinde… @@ -41,7 +41,7 @@ SimpleX Kontaktadressen-Link SimpleX Einmal-Link SimpleX Gruppen-Link - über %1$s + über %1$s SimpleX-Links Beschreibung Vollständiger Link @@ -54,7 +54,7 @@ Verbindungszeitüberschreitung Verbindungsfehler - Bitte überprüfen Sie Ihre Netzwerkverbindung mit %1$s und versuchen Sie es erneut. + Bitte überprüfen Sie Ihre Netzwerkverbindung mit %1$s und versuchen Sie es erneut. Fehler beim Senden der Nachricht Fehler beim Hinzufügen von Mitgliedern Fehler beim Beitritt zur Gruppe @@ -63,7 +63,7 @@ Fehler beim Empfangen der Datei Fehler beim Erstellen der Adresse Kontakt ist bereits vorhanden - Sie sind bereits mit %1$s verbunden. + Sie sind bereits mit %1$s verbunden. Ungültiger Verbindungslink Überprüfen Sie bitte, ob Sie den richtigen Link genutzt haben oder bitten Sie Ihren Kontakt darum, Ihnen nochmal einen Link zuzusenden. Verbindungsfehler (AUTH) @@ -87,9 +87,9 @@ Sofortige Benachrichtigungen Sofortige Benachrichtigungen! Sofortige Benachrichtigungen sind deaktiviert! - Um Ihre Privatsphäre zu schützen kann statt der Push-Benachrichtigung der SimpleX Hintergrunddienst genutzt werden – dieser benötigt ein paar Prozent Akkuleistung am Tag. - Diese können über die Einstellungen deaktiviert werden – Solange die App abläuft werden Benachrichtigungen weiterhin angezeigt. - Um diese Funktion zu nutzen, ist es nötig, die Einstellung Akkuoptimierung für SimpleX im nächsten Dialog zu deaktivieren. Ansonsten werden die Benachrichtigungen deaktiviert. + SimpleX Hintergrunddienst genutzt werden – dieser benötigt ein paar Prozent Akkuleistung am Tag.]]> + Diese können über die Einstellungen deaktiviert werden – Solange die App abläuft werden Benachrichtigungen weiterhin angezeigt.]]> + Akkuoptimierung für SimpleX im nächsten Dialog zu deaktivieren. Ansonsten werden die Benachrichtigungen deaktiviert.]]> Die Akkuoptimierung ist aktiv, der Hintergrunddienst und die periodische Nachfrage nach neuen Nachrichten ist abgeschaltet. Sie können diese Funktion in den Einstellungen wieder aktivieren. Periodische Benachrichtigungen Periodische Benachrichtigungen sind deaktiviert! @@ -99,7 +99,7 @@ Die Datenbank kann nicht initialisiert werden Die Datenbank arbeitet nicht richtig. Tippen Sie für weitere Informationen. - SimpleX Chat Hintergrunddienst + SimpleX Chat Hintergrunddienst Empfange Nachrichten … Verberge @@ -167,7 +167,7 @@ Senden fehlgeschlagen Ungelesen - Willkommen %1$s! + Willkommen %1$s! Willkommen! Dieser Text ist in den Einstellungen verfügbar. Chats @@ -202,8 +202,8 @@ Datei Große Datei! - Ihr Kontakt hat eine Datei gesendet, die größer ist als die derzeit unterstützte maximale Größe (%1$s). - Die derzeit maximal unterstützte Dateigröße beträgt %1$s. + Ihr Kontakt hat eine Datei gesendet, die größer ist als die derzeit unterstützte maximale Größe (%1$s). + Die derzeit maximal unterstützte Dateigröße beträgt %1$s. Warte auf Datei Die Datei wird empfangen, sobald Ihr Kontakt online ist. Bitte warten oder schauen Sie später nochmal nach! Datei gespeichert @@ -211,7 +211,7 @@ Fehler beim Speichern der Datei Sprachnachricht - Sprachnachricht (%1$s) + Sprachnachricht (%1$s) Sprachnachricht… Benachrichtigungen @@ -224,8 +224,8 @@ Getrennt Fehler Ausstehend - Empfängeradresse wechseln? - Diese Funktion ist experimentell! Sie wird nur funktionieren, wenn der Kontakt ebenfalls eine SimpleX-Version ab v4.2 installiert hat. Sobald der Adress-Wechsel abgeschlossen ist, sollten Sie die Nachricht im Chat-Verlauf sehen. Bitte prüfen Sie, ob Sie weiterhin Nachrichten von diesem Kontakt (oder Gruppenmitglied) empfangen können. + Empfängeradresse wechseln\? + Die Empfängeradresse wird auf einen anderen Server geändert. Der Adresswechsel wird abgeschlossen, wenn der Absender wieder online ist. Nachricht senden Nehme Sprachnachricht auf @@ -260,17 +260,17 @@ Bild Video - Danke, dass Sie SimpleX Chat installiert haben! - Sie können sich mit SimpleX Chat Entwicklern verbinden, um Fragen zu stellen und Updates zu erhalten. + Danke, dass Sie SimpleX Chat installiert haben! + mit SimpleX Chat Entwicklern verbinden, um Fragen zu stellen und Updates zu erhalten.]]> Um einen neuen Chat zu starten Schaltfläche antippen Danach die gewünschte Aktion auswählen: - Neuen Kontakt hinzufügen: Um Ihren Einmal-QR-Code für Ihren Kontakt zu erstellen. - QR-Code scannen: Um sich mit Ihrem Kontakt zu verbinden, der Ihnen seinen QR-Code zeigt. + Neuen Kontakt hinzufügen: Um Ihren Einmal-QR-Code für Ihren Kontakt zu erstellen.]]> + QR-Code scannen: Um sich mit Ihrem Kontakt zu verbinden, der Ihnen seinen QR-Code zeigt.]]> Über Link verbinden - Wenn Sie einen SimpleX Chat Einladungslink erhalten haben, können Sie ihn in Ihrem Browser öffnen: - 💻 Desktop: Angezeigten QR-Code aus der App scannen, über QR-Code scannen. - 📱 Handy: Tippen Sie auf In mobiler App öffnen und dann auf Verbinden in der App. + Wenn Sie einen SimpleX Chat Einladungslink erhalten haben, können Sie ihn in Ihrem Browser öffnen: + QR-Code scannen.]]> + In mobiler App öffnen und dann auf Verbinden in der App.]]> Die Verbindungsanfrage akzeptieren? Wenn Sie ablehnen, wird der Absender NICHT benachrichtigt. @@ -311,10 +311,10 @@ Link Vorschau abbrechen Einstellungen QR Code - SimpleX Adresse + SimpleX Adresse Hilfe - SimpleX Team - SimpleX Logo + SimpleX Team + SimpleX Logo E-Mail Mehr @@ -328,10 +328,10 @@ Sie werden mit der Gruppe verbunden, sobald das Endgerät des Gruppen-Hosts online ist. Bitte warten oder schauen Sie später nochmal nach! Sie werden verbunden, sobald Ihre Verbindungsanfrage akzeptiert wird. Bitte warten oder schauen Sie später nochmal nach! Sie werden verbunden, sobald das Endgerät Ihres Kontakts online ist. Bitte warten oder schauen Sie später nochmal nach! - Wenn Sie sich nicht persönlich treffen können, können Sie den QR-Code während eines Videoanrufs anzeigen oder einen Einladungslink über einen anderen Kanal mit Ihrem Kontakt teilen. + den QR-Code während eines Videoanrufs anzeigen oder einen Einladungslink über einen anderen Kanal mit Ihrem Kontakt teilen.]]> Ihr Chat-Profil wird \nan Ihren Kontakt gesendet - Wenn Sie sich nicht persönlich treffen können, können Sie den QR-Code während eines Videoanrufs scannen oder Ihr Kontakt kann einen Einladungslink über einen anderen Kanal mit Ihnen teilen. + den QR-Code während eines Videoanrufs scannen oder Ihr Kontakt kann einen Einladungslink über einen anderen Kanal mit Ihnen teilen.]]> Einmal-Link teilen Fügen Sie den erhaltenen Link in das Feld unten ein, um sich mit Ihrem Kontakt zu verbinden. Ihr Chat-Profil wird an Ihren Kontakt gesendet @@ -340,7 +340,7 @@ Verbinden Einfügen Diese Zeichenfolge entspricht keinem gültigen Verbindungslink! - Sie können sich auch verbinden, indem Sie auf den Link klicken. Wenn er im Browser geöffnet wird, klicken Sie auf die Schaltfläche In mobiler App öffnen. + In mobiler App öffnen.]]> Link / QR-Code erstellen Einmaliger Einladungs-Link @@ -348,7 +348,7 @@ Meine Einstellungen Meine SimpleX-Adresse Datenbank-Passwort & -Export - Über SimpleX Chat + Über SimpleX Chat Wie man SimpleX nutzt Markdown Hilfe Markdown in Nachrichten @@ -376,13 +376,13 @@ Ungültige Serveradresse! Überprüfen Sie die Serveradresse und versuchen Sie es nochmal. Server löschen - Installieren Sie SimpleX Chat als Terminalanwendung + Installieren Sie SimpleX Chat als Terminalanwendung Stern auf GitHub vergeben Unterstützen Sie uns Bewerten Sie die App - Verwenden Sie SimpleX Chat Server? + Verwenden Sie SimpleX Chat Server? Ihre SMP-Server - Verwendung von SimpleX Chat Servern. + Verwendung von SimpleX Chat Servern. Anleitung Wie Sie Ihre Server nutzen Gespeicherte WebRTC ICE-Server werden entfernt. @@ -421,7 +421,7 @@ Angezeigter Name: "Vollständiger Name: Mein aktuelles Chat-Profil - Ihr Profil wird auf Ihrem Gerät gespeichert und nur mit Ihren Kontakten geteilt. SimpleX-Server können Ihr Profil nicht sehen. + Ihr Profil wird auf Ihrem Gerät gespeichert und nur mit Ihren Kontakten geteilt. SimpleX-Server können Ihr Profil nicht sehen. Bild bearbeiten Bild löschen Präferenzen speichern? @@ -444,12 +444,12 @@ Wie Sie Markdowns anwenden Sie können Markdowns verwenden, um Nachrichten zu formatieren: - fett - kursiv - durchstreichen + fett + kursiv + durchstreichen a + b - farbig - geheim + farbig + geheim Anruf… Anruf verpasst @@ -457,7 +457,7 @@ Anruf angenommen Anruf wird verbunden… Anruf läuft - Anruf beendet %1$s + Anruf beendet %1$s Fehler bei Anruf Verbindung wird gestartet… @@ -480,19 +480,19 @@ Stellen Sie eine private Verbindung her Wie es funktioniert - Wie SimpleX funktioniert - Viele Menschen haben gefragt: Wie kann SimpleX Nachrichten zustellen, wenn es keine Benutzerkennungen gibt? - Zum Schutz Ihrer Privatsphäre verwendet SimpleX an Stelle von Benutzerkennungen, die von allen anderen Plattformen verwendet werden, Kennungen für Nachrichtenwarteschlangen, die für jeden Ihrer Kontakte individuell sind. - Sie können selbst festlegen, über welche Server Sie Ihre Nachrichten empfangen und an Ihre Kontakte senden wollen. - Nur die Endgeräte speichern die Benutzerprofile, Kontakte, Gruppen und Nachrichten, welche über eine 2-Schichten Ende-zu-Ende-Verschlüsselung gesendet werden. + Wie SimpleX funktioniert + Wie kann SimpleX Nachrichten zustellen, wenn es keine Benutzerkennungen gibt?]]> + Zum Schutz Ihrer Privatsphäre verwendet SimpleX an Stelle von Benutzerkennungen, die von allen anderen Plattformen verwendet werden, Kennungen für Nachrichtenwarteschlangen, die für jeden Ihrer Kontakte individuell sind. + empfangen und an Ihre Kontakte senden wollen.]]> + 2-Schichten Ende-zu-Ende-Verschlüsselung gesendet werden.]]> Erfahren Sie in unserem GitHub-Repository mehr dazu. - Erfahren Sie in unserem GitHub-Repository mehr dazu. + GitHub-Repository mehr dazu.]]> Fügen Sie den erhaltenen Link ein Eingehender Videoanruf Eingehender Audioanruf - %1$s möchte sich mit Ihnen verbinden per + %1$s möchte sich mit Ihnen verbinden per Videoanruf (nicht E2E verschlüsselt) E2E-verschlüsseltem Videoanruf Audioanruf (nicht E2E verschlüsselt) @@ -516,7 +516,7 @@ Relais-Server schützen Ihre IP-Adresse, aber sie können die Anrufdauer erfassen. Relais-Server werden nur genutzt, wenn sie benötigt werden. Ihre IP-Adresse kann von Anderen erfasst werden. - Öffnen Sie SimpleX Chat, um den Anruf anzunehmen. + Öffnen Sie SimpleX Chat, um den Anruf anzunehmen. Aktivieren Sie Anrufe vom Sperrbildschirm über die Einstellungen. Öffnen @@ -543,7 +543,7 @@ Anruf beendet Anruf annehmen - %1$d übersprungene Nachricht(en) + %1$d übersprungene Nachricht(en) Ungültiger Nachrichten-Hash Falsche Nachrichten-ID Doppelte Nachricht @@ -639,7 +639,7 @@ Ihre Chat-Datenbank ist nicht verschlüsselt. Bitte legen Sie ein Passwort fest, um sie zu schützen. Der Android Keystore wird verwendet, um das Passwort sicher zu speichern. Dies ermöglicht die ordentliche Funktion des Benachrichtigungsdienstes. Die Datenbank wird mit einem zufälligen Passwort verschlüsselt, Sie können es ändern. - Bitte beachten Sie: Sie können das Passwort NICHT wiederherstellen oder ändern, wenn Sie es vergessen haben oder verlieren. + Bitte beachten Sie: Sie können das Passwort NICHT wiederherstellen oder ändern, wenn Sie es vergessen haben oder verlieren.]]> Der Android Keystore wird verwendet, um das Passwort sicher zu speichern, nachdem Sie die App neu gestartet oder das Passwort geändert haben – dies ermöglicht den Empfang von Benachrichtigungen. Sie müssen das Passwort jedes Mal eingeben, wenn die App startet. Es wird nicht auf dem Gerät gespeichert. Datenbank verschlüsseln? @@ -682,10 +682,10 @@ CHAT ARCHIV Archiv speichern Archiv löschen - Erstellt am %1$s + Erstellt am %1$s Chat Archiv löschen? - Einladung zur Gruppe %1$s + Einladung zur Gruppe %1$s Der Gruppe beitreten? Sie sind zu einer Gruppe eingeladen worden. Treten Sie bei, um sich mit Gruppenmitgliedern zu verbinden. Beitreten @@ -712,19 +712,19 @@ Sie haben die Gruppeneinladung abgelehnt Die Gruppeneinladung ist abgelaufen - hat %1$s eingeladen. + hat %1$s eingeladen. beigetreten hat die Gruppe verlassen änderte die Rolle von %s auf %s änderte Ihre Rolle auf %s - entfernte %1$s aus der Gruppe. + entfernte %1$s aus der Gruppe. hat Sie aus der Gruppe entfernt Gruppe gelöscht Aktualisiertes Gruppenprofil wurde über Ihren Gruppen-Link eingeladen Sie haben die Rolle von %s auf %s geändert Sie haben Ihre eigene Rolle auf %s geändert - entfernt %1$s aus der Gruppe. + entfernt %1$s aus der Gruppe. hat die Gruppe verlassen Gruppenprofil aktualisiert @@ -766,8 +766,8 @@ Sie versuchen, einen Kontakt, mit dem Sie ein Inkognito-Profil geteilt haben, in die Gruppe einzuladen, in der Sie Ihr Hauptprofil verwenden. Mitglieder einladen - %1$s MITGLIEDER - Sie: %1$s + %1$s MITGLIEDER + Sie: %1$s Gruppe löschen Gruppe löschen? Die Gruppe wird für alle Mitglieder gelöscht - dies kann nicht rückgängig gemacht werden! @@ -805,13 +805,13 @@ Gruppe Verbindung direkt - indirekt (%1$s) + indirekt (%1$s) SERVER Empfangen über Senden über Netzwerkstatus - Wechseln der Empfängeradresse + Empfängeradresse wechseln Geheime Gruppe erstellen Die Gruppe ist vollständig dezentralisiert – sie ist nur für Mitglieder sichtbar. @@ -904,8 +904,8 @@ LIVE Schauen Sie sich den Sicherheitscode an Sofort - Gute Option für die Batterieausdauer. Der Hintergrundservice überprüft alle 10 Minuten nach Nachrichten. Sie können eventuell Anrufe oder dringende Nachrichten verpassen. - Beste Option für die Batterieausdauer. Sie empfangen Benachrichtigungen nur solange die App abläuft (kein aktiver Hintergrundservice). + Gute Option für die Batterieausdauer. Der Hintergrundservice überprüft alle 10 Minuten nach Nachrichten. Sie können eventuell Anrufe oder dringende Nachrichten verpassen.]]> + Beste Option für die Batterieausdauer. Sie empfangen Benachrichtigungen nur solange die App abläuft (kein aktiver Hintergrundservice).]]> Senden %s wurde erfolgreich überprüft Überprüfung zurücknehmen @@ -941,7 +941,7 @@ Fehler beim Laden des Chats Fehler beim Laden der Chats Bitte aktualisieren Sie die App und nehmen Sie Kontakt mit den Entwicklern auf. - Benötigt mehr Leistung Ihrer Batterie! Der Hintergrundservice läuft permanent ab. Benachrichtigungen werden Ihnen angezeigt, sobald Sie neue Nachrichten erhalten haben. + Benötigt mehr Leistung Ihrer Batterie! Der Hintergrundservice läuft permanent ab. Benachrichtigungen werden Ihnen angezeigt, sobald Sie neue Nachrichten erhalten haben.]]> Gruppenlink erstellen Erlauben Sie Ihren Kontakten das Senden von verschwindenden Nachrichten. Das Senden von verschwindenden Nachrichten verbieten. @@ -1013,7 +1013,7 @@ Für jeden Kontakt und jedes Gruppenmitglied wird eine separate TCP-Verbindung (und SOCKS-Berechtigung) genutzt. \n \nBitte beachten Sie: Wenn Sie viele Verbindung haben, kann der Batterieverbrauch und die Datennutzung wesentlich höher sein und einige Verbindungen können scheitern. - Für jedes von Ihnen in der App genutzte Chat-Profil wird eine separate TCP-Verbindung (und SOCKS-Berechtigung) genutzt. + Für jedes von Ihnen in der App genutzte Chat-Profil wird eine separate TCP-Verbindung (und SOCKS-Berechtigung) genutzt.]]> Nur lokale Profildaten Profil und Serververbindungen Diese Einstellung gilt für Nachrichten in Ihrem aktuellen Chat-Profil @@ -1166,21 +1166,21 @@ SOCKS-Proxy nutzen SimpleX Sperr-Modus SimpleX Sperre ist nicht aktiviert! - Setzen Sie Verwende .onion-Hosts auf \"Nein\", wenn der SOCKS-Proxy sie nicht unterstützt. + Verwende .onion-Hosts auf \"Nein\", wenn der SOCKS-Proxy sie nicht unterstützt.]]> Bestätigen System Sie können nicht überprüft werden - bitte versuchen Sie es nochmal. XFTP-Server Die ID der nächsten Nachricht ist falsch (kleiner oder gleich der Vorherigen). \nDies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompromittiert wurde. - %1$d Nachrichten konnten nicht entschlüsselt werden. + %1$d Nachrichten konnten nicht entschlüsselt werden. Der Hash der vorherigen Nachricht unterscheidet sich. Sie können die SimpleX Sperre über die Einstellungen aktivieren. SOCKS-Proxy Einstellungen System-Authentifizierung Es handelt sich um einen permanenten Fehler für diese Verbindung - bitte verbinden Sie sich neu. Datei hochladen - %1$d Nachrichten übersprungen. + %1$d Nachrichten übersprungen. Anrufe sind nur erlaubt, wenn Ihr Kontakt das ebenfalls erlaubt. Erlaubt Ihren Kontakten Sie anzurufen. Audio/Video Anrufe @@ -1259,7 +1259,7 @@ Weiter Dunkles Design Falls Sie sich nicht persönlich treffen können, zeigen Sie den QR-Code in einem Videoanruf oder teilen Sie den Link. - Lesen Sie mehr dazu in der Benutzeranleitung. + Benutzeranleitung.]]> Stellen Sie sicher, dass die Datei die korrekte YAML-Syntax hat. Exportieren sie das Design, um ein Beispiel für die Dateistruktur des Designs zu erhalten. Offene Chat-Profile Sie können Ihre Adresse als Link oder QR-Code teilen - jede Person kann sich mit Ihnen verbinden. @@ -1284,6 +1284,7 @@ Fehler beim Laden von Details Empfangene Nachricht Information + Suchen Gesendete Nachricht Zeit anpassen Verschwindende Nachricht @@ -1347,4 +1348,20 @@ APP Neustart Herunterfahren + Fehler beim Abbrechen des Adresswechsels + Abbrechen + Dateien und Medien + Das Senden von Dateien und Medien erlauben. + Das Senden von Dateien und Medien nicht erlauben. + Wechsel der Adresse abbrechen + Wechsel der Adresse abbrechen\? + Dateien und Medien sind nicht erlaubt! + Nur Gruppenbesitzer können Dateien und Medien aktivieren. + Gruppenmitglieder können Dateien und Medien senden. + Der Wechsel der Adresse wird abgebrochen. Die bisherige Adresse wird weiter verwendet. + In dieser Gruppe sind Dateien und Medien nicht erlaubt. + Favorit löschen + Favorit + Keine gefilterten Chats + Aus \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-el/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml similarity index 95% rename from apps/multiplatform/android/src/main/res/values-el/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml index 6926e0c891..714f31732c 100644 --- a/apps/multiplatform/android/src/main/res/values-el/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/el/strings.xml @@ -1,17 +1,17 @@ - + 1 μέρα 1 μήνας Για το SimpleX Σαρώστε τον QR κωδικό α + β - Για το SimpleX Chat + Για το SimpleX Chat Σαρώστε τον κωδικό ασφαλείας από την εφαρμογή επαφών σας Ασφαλή ουρά δε Κωδικός ασφαλείας Σαρώστε τον κωδικό QR διακομιστή - μυστικό + μυστικό 1 εβδομάδα αξιολόγηση ασφαλείας Συναινώ @@ -37,7 +37,7 @@ Να επιτρέπεται η αποστολή άμεσων μηνυμάτων στα μέλη. Επιτρέπεται η αποστολή μηνυμάτων που εξαφανίζονται. Επιτρέπεται η αποστολή φωνητικών μηνυμάτων. - SimpleX + SimpleX Αποδοχή Αποδοχή αιτήματος σύνδεσης; αποδεκτή κλήση @@ -54,4 +54,6 @@ Να επιτρέπονται τα φωνητικά μηνύματα; Πάντα ενεργό Να χρησιμοποιείται πάντα αναμεταδότη + Αναζήτηση + Ανενεργό \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-es/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml similarity index 93% rename from apps/multiplatform/android/src/main/res/values-es/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml index c8c4eb8564..a4c2f6614e 100644 --- a/apps/multiplatform/android/src/main/res/values-es/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/es/strings.xml @@ -1,10 +1,10 @@ - + Autenticación no disponible Aceptar Configuración avanzada de red - Mejor para la batería. Recibirás notificaciones sólo cuando la aplicación se esté ejecutando, SIN servicio en segundo plano. - Bueno para la batería. El servicio en segundo plano comprueba si hay mensajes cada 10 minutos. Puedes perder llamadas o mensajes urgentes. + Mejor para la batería. Recibirás notificaciones sólo cuando la aplicación se esté ejecutando, SIN servicio en segundo plano.]]> + Bueno para la batería. El servicio en segundo plano comprueba si hay mensajes cada 10 minutos. Puedes perder llamadas o mensajes urgentes.]]> Aceptar Copia de seguridad de los datos de la aplicación un dia @@ -24,11 +24,11 @@ Se enviará un perfil aleatorio al contacto del que recibió este enlace La optimización de la batería está activa, desactivando el servicio en segundo plano y las solicitudes periódicas de nuevos mensajes. Puedes volver a activarlos en Configuración. El servicio está siempre en funcionamiento en segundo plano. Las notificaciones se muestran en cuanto haya mensajes nuevos. - Se puede desactivar en Configuración – las notificaciones se seguirán mostrando mientras la app esté en funcionamiento. + Se puede desactivar en Configuración – las notificaciones se seguirán mostrando mientras la app esté en funcionamiento.]]> Siempre activo Permitir y después: - Añadir nuevo contacto: para crear tu código QR de un solo uso para tu contacto. + Añadir nuevo contacto: para crear tu código QR de un solo uso para tu contacto.]]> ¿Aceptar solicitud de conexión\? Aceptar incógnito Se eliminarán todos los mensajes SOLO para tí. ¡No podrá deshacerse! @@ -37,12 +37,12 @@ Todos tus contactos permanecerán conectados. Apariencia Versión - Se usará una conexión TCP (y credenciales SOCKS) independiente por cada perfil que tengas en la aplicación. + por cada perfil que tengas en la aplicación.]]> Se usará una conexión TCP (y credenciales SOCKS) independiente por cada contacto y miembro del grupo. \nAtención: si tienes muchas conexiones, el consumo de batería y tráfico pueden ser sustancialmente mayores y algunas conexiones pueden fallar. a + b Acerca de SimpleX - negrita + negrita llamada aceptada Aceptar llamada (sin cifrar) @@ -72,16 +72,16 @@ administrador ¿Permites los mensajes de voz\? Volver - Sobre SimpleX Chat + Sobre SimpleX Chat Añadir a otro dispositivo Versión de la aplicación: v%s Solicita recibir la imagen - Atención: NO podrás recuperar o cambiar la contraseña si la pierdes. + Atención: NO podrás recuperar o cambiar la contraseña si la pierdes.]]> Tanto tú como tu contacto podéis enviar mensajes de voz. - ¡Consume más batería! El servicio en segundo plano se ejecuta siempre y las notificaciones se mostrarán en cuanto haya mensajes disponibles. + ¡Consume más batería! El servicio en segundo plano se ejecuta siempre y las notificaciones se mostrarán en cuanto haya mensajes disponibles.]]> Tanto tú como tu contacto podéis eliminar de forma irreversible los mensajes enviados. Tanto tú como tu contacto podéis enviar mensajes temporales. - Escanear código QR: para conectar con tu contacto mediante su código QR. + Escanear código QR: para conectar con tu contacto mediante su código QR.]]> Crear Crea enlace de invitación de un uso Crea grupo secreto @@ -108,7 +108,7 @@ Conectado Desactivar Bloqueo SimpleX Autenticación de dispositivo desactivada. Bloqueo SimpleX deshabilitado. - El tamaño máximo de archivo admitido es %1$s + El tamaño máximo de archivo admitido es %1$s Eliminar verificación Crear perfil Llamada con cifrado de extremo a extremo @@ -140,7 +140,7 @@ conectando (invitación de presentación ) conectando (aceptado) conectando (anunciado) - conexión %1$d + conexión %1$d Conecta vía enlace / Código QR El contacto y todos los mensajes serán eliminados. ¡No podrá deshacerse! Contacto verificado @@ -164,7 +164,7 @@ Conectado Copiado en portapapeles Crea enlace de invitación de un uso. - 💻 PC: escanéa el código QR desde la aplicación mediante Escanear código QR + Escanear código QR ]]> Eliminar Eliminar ¡El contacto aun no se ha conectado! @@ -220,7 +220,7 @@ %dd %d días ¿Eliminar archivos y multimedia\? - Creado: %1$s + Creado: %1$s Eliminar archivo conectado directa @@ -263,11 +263,11 @@ Vaciar Vaciar chat Configurar servidores ICE - Llamada terminada %1$s + Llamada terminada %1$s error en la llamada llamando llamada en curso - coloreado + coloreado ha cambiado tu rol a %s cambiando de servidor para %s completado @@ -357,11 +357,11 @@ De la Galería Imagen Vídeo - Si has recibido un enlace de invitación a SimpleX Chat puedes abrirlo en tu navegador: + Si has recibido un enlace de invitación a SimpleX Chat puedes abrirlo en tu navegador: Si eliges rechazar, el remitente NO será notificado. ¡Enlace no válido! - Si no puedes reunirte en persona, puedes escanear el código QR en la videollamada, o tu contacto puede compartir un enlace de invitación. - Si no puedes reunirte en persona, muestra el código QR en la videollamada, o comparte el enlace. + escanear el código QR en la videollamada, o tu contacto puede compartir un enlace de invitación.]]> + muestra el código QR en la videollamada, o comparte el enlace.]]> Cómo Ignorar Error eliminando la base de datos @@ -393,7 +393,7 @@ Servidores ICE (uno por línea) Nombre completo: Las personas pueden conectarse contigo sólo mediante los enlaces que compartes. - Cómo funciona SimpleX + Cómo funciona SimpleX Colgar Archivos y multimedia ¡Grupo no encontrado! @@ -443,10 +443,10 @@ Cómo funciona El mensaje se eliminará. ¡No podrá deshacerse! La función del modo incógnito es proteger la identidad del perfil principal: por cada contacto nuevo se genera un perfil aleatorio. - Para poder usarse deshabilita la optimización de batería para SimpleX en el siguiente cuadro de diálogo. De lo contrario las notificaciones estarán desactivadas. - Instalar terminal para SimpleX Chat - invitación al grupo %1$s - ha invitado a %1$s + deshabilita la optimización de batería para SimpleX en el siguiente cuadro de diálogo. De lo contrario las notificaciones estarán desactivadas.]]> + Instalar terminal para SimpleX Chat + invitación al grupo %1$s + ha invitado a %1$s Permite tener varias conexiones anónimas sin datos compartidos entre estas dentro del mismo perfil. Invitar al grupo Para comprobar el cifrado de extremo a extremo con tu contacto compara (o escanea) el código en tus dispositivos. @@ -455,12 +455,12 @@ Notificación instantánea Configuración de red No se usarán hosts .onion - Sólo los dispositivos cliente almacenan perfiles de usuario, contactos, grupos y mensajes enviados con cifrado de extremo a extremo de 2 capas . + cifrado de extremo a extremo de 2 capas .]]> Puede cambiarse más tarde en Configuración. Instantánea Únete Únete en modo incógnito - indirecta (%1$s) + indirecta (%1$s) Claro Activado La eliminación irreversible de mensajes no está permitida en este chat. @@ -483,7 +483,7 @@ Servicio El mensaje se marcará para eliminar. El destinatario o destinatarios podrán revelar este mensaje. ¡Mensaje en vivo! - 📱 móvil: pulse Abrir en aplicación móvil, después pulse Conectar en la aplicación. + Abrir en aplicación móvil, después pulse Conectar en la aplicación.]]> Marcar como leído Marcar como no leído Código QR inválido @@ -519,7 +519,7 @@ Se requieren hosts .onion para la conexión Se usarán hosts .onion si están disponibles. Inmune a spam y abuso - Muchos se preguntarán: si SimpleX no tiene identificadores de usuario, ¿cómo puede entregar los mensajes\? + si SimpleX no tiene identificadores de usuario, ¿cómo puede entregar los mensajes\?]]> Videollamada entrante has salido has cambiado la dirección @@ -537,7 +537,7 @@ Ayuda sintaxis markdown Servidores y Redes Se usarán hosts .onion si están disponibles. - cursiva + cursiva Llamada entrante videollamada (sin cifrar) sin cifrar @@ -587,7 +587,7 @@ Marcar como verificado ¡Dirección de servidor no válida! Establecer una conexión privada - Comprueba tu conexión de red con %1$s e inténtalo de nuevo. + Comprueba tu conexión de red con %1$s e inténtalo de nuevo. El remitente puede haber eliminado la solicitud de conexión. Posiblemente la huella digital del certificado en la dirección del servidor es incorrecta Responder @@ -611,8 +611,8 @@ Escanear código Se eliminarán los servidores WebRTC ICE guardados. llamada rechazada - secreto - Abrir SimpleX Chat para aceptar llamada + secreto + Abrir SimpleX Chat para aceptar llamada Restablecer valores por defecto Guardar color Pendiente @@ -624,9 +624,9 @@ imagen del perfil No se permiten mensajes de voz. Proteger la pantalla de la aplicación - Más información en nuestro repositorio GitHub . + repositorio GitHub .]]> Grabar mensaje de voz - ha expulsado a %1$s + ha expulsado a %1$s Enviar previsualizacion de enlaces Envía un mensaje en vivo: se actualizará para el(los) destinatario(s) a medida que se escribe error de envío @@ -723,9 +723,9 @@ Este texto está disponible en Configuración ¡Experimental! Sólo funcionará si el otro cliente tiene instalada la versión 4.2. Deberías ver el mensaje en la conversación una vez completado el cambio de dirección. Comprueba que puedes seguir recibiendo mensajes de este contacto (o miembro del grupo). Bloqueo SimpleX - Usando servidores SimpleX Chat. + Usando servidores SimpleX Chat. Aislamiento de transporte - tachado + tachado Usar Chat PROXY SOCKS TEMAS @@ -762,17 +762,17 @@ Esta acción no se puede deshacer. Se eliminarán los mensajes enviados y recibidos anteriores a la selección. Puede tardar varios minutos. Esta configuración se aplica a los mensajes del perfil actual ¡Esta cadena no es un enlace de conexión! - Para preservar tu privacidad, en lugar de notificaciones automáticas la aplicación cuenta con un servicio en segundo planoSimpleX, utiliza un pequeño porcentaje de la batería al día. + servicio en segundo planoSimpleX, utiliza un pequeño porcentaje de la batería al día.]]> Configuración Altavoz desactivado Inciar chat nuevo Para poder exportar, importar o eliminar la base de datos primero debes detener Chat. Durante el tiempo que esté detenido no podrás recibir ni enviar mensajes. - Gracias por instalar SimpleX Chat! - Para proteger la privacidad, en lugar de los identificadores de usuario que utilizan el resto de plataformas, SimpleX dispone de identificadores para las colas de mensajes, independientes para cada uno de tus contactos. + Gracias por instalar SimpleX Chat! + Para proteger la privacidad, en lugar de los identificadores de usuario que utilizan el resto de plataformas, SimpleX dispone de identificadores para las colas de mensajes, independientes para cada uno de tus contactos. Para proteger tu información, activa Bloqueo SimpleX. \nSe te pedirá que completes la autenticación antes de activar esta función. Al actualizar la configuración, el cliente se reconectará a todos los servidores. - ¿Usar servidores SimpleX Chat\? + ¿Usar servidores SimpleX Chat\? Enlace de grupo SimpleX Invitación única SimpleX Enlaces SimpleX @@ -832,7 +832,7 @@ ¿Actualizar la configuración de red\? Intentando conectar con el servidor utilizado para recibir mensajes de este contacto. formato de mensaje desconocido - Intentando conectar con el servidor utilizado para recibir mensajes de este contacto (error: %1$s ). + Intentando conectar con el servidor utilizado para recibir mensajes de este contacto (error: %1$s ). Prueba fallida en el paso %s. Pulsa para iniciar chat nuevo Compartir mensaje… @@ -862,11 +862,11 @@ Has sido invitado al grupo Mensajes de voz Tus contactos pueden permitir la eliminación completa de mensajes. - Tú controlas a través de qué servidor(es) recibes los mensajes. Tus contactos controlan a través de qué servidor(es) envías tus mensajes. + recibes los mensajes. Tus contactos controlan a través de qué servidor(es) envías tus mensajes.]]> Mensajes de voz Los mensajes de voz no están permitidos en este grupo. Comprobar la seguridad de la conexión - ¡Ya estás conectado a %1$s. + ¡Ya estás conectado a %1$s. ¡Bienvenido! Tu perfil Chat será enviado \na tu contacto @@ -878,10 +878,10 @@ Mensaje de voz Esperando imagen Servidores WebRTC ICE - %1$s quiere conectarse contigo mediante + %1$s quiere conectarse contigo mediante Tienes un perfil de chat con el mismo nombre mostrado. Debes elegir otro nombre. - También puedes conectarte pulsando el enlace. Si se abre en el navegador, pulsa en Abrir en aplicación móvil. - Puedes ponerte en contacto con los desarrolladores de SimpleX Chat para consultas y para recibir actualizaciones. + Abrir en aplicación móvil.]]> + ponerte en contacto con los desarrolladores de SimpleX Chat para consultas y para recibir actualizaciones.]]> ¡No puedes enviar mensajes! Puedes usar la sintaxis markdown para dar formato a tus mensajes: Debes usar la versión más reciente de tu base de datos ÚNICAMENTE en un dispositivo, de lo contrario podrías dejar de recibir mensajes de algunos contactos. @@ -895,18 +895,18 @@ Se te pedirá identificarte cuándo inicies o continues usando la aplicación tras 30 segundos en segundo plano. Estás intentando invitar a un contacto con el que compartes un perfil incógnito a un grupo en el que usas tu perfil principal Mediante navegador - mediante %1$s - Servicio SimpleX Chat - ¡Bienvenido %1$s ! + mediante %1$s + Servicio SimpleX Chat + ¡Bienvenido %1$s ! has sido invitado al grupo Esperando archivo Esperando imagen - Mensaje de voz (%1$s ) + Mensaje de voz (%1$s ) Si disponibles No almacenamos ninguno de tus contactos o mensajes (una vez entregados) en los servidores. Has sido invitado al grupo. Únete para conectarte con los miembros del grupo. - has expulsado a %1$s - Tú: %1$s + has expulsado a %1$s + Tú: %1$s Puedes compartir un enlace o un código QR: cualquiera podrá unirse al grupo. Si lo eliminas más tarde los miembros del grupo no se perderán. Cuando compartes un perfil incógnito con alguien, este perfil también se usará para los grupos a los que te inviten. Mis preferencias @@ -932,14 +932,14 @@ Puedes iniciar el chat en Configuración / Base de datos o reiniciando la aplicación. Has enviado una invitación de grupo %d contacto(s) seleccionado(s) - %1$s MIEMBROS + %1$s MIEMBROS Los mensajes de voz no están permitidos en este chat. Novedades La contraseña no se almacena en el dispositivo, tienes que introducirla cada vez que inicies la aplicación. Te has unido a este grupo Permites - SimpleX + SimpleX Tu perfil se enviará al contacto del que has recibido este enlace. Te unirás al grupo al que hace referencia este enlace y te conectarás con sus miembros. @@ -949,23 +949,23 @@ has compartido enlace de un solo uso has compartido enlace de un solo uso en módo incógnito No tienes chats - El contacto ha enviado un archivo mayor al máximo admitido (%1$s ). - %1$d mensaje(s) omitido(s) + El contacto ha enviado un archivo mayor al máximo admitido (%1$s ). + %1$d mensaje(s) omitido(s) Dejarás de recibir mensajes de este grupo. El historial del chat se conservará. Mostrar código de seguridad Para poder enviar mensajes de voz antes debes permitir que tu contacto pueda enviarlos. ¡Mensajes de voz prohibidos! Tu perfil Chat será enviado a los miembros del grupo - Dirección SimpleX - Logo SimpleX - Equipo SimpleX + Dirección SimpleX + Logo SimpleX + Equipo SimpleX Tu perfil Chat se enviará a tu contacto Mis perfiles Mi dirección SimpleX Tu servidor Dirección de tu servidor Tu perfil actual - Tu perfil se almacena en tu dispositivo y sólo se comparte con tus contactos. Los servidores SimpleX no pueden ver tu perfil. + Tu perfil se almacena en tu dispositivo y sólo se comparte con tus contactos. Los servidores SimpleX no pueden ver tu perfil. Sistema Añadir mensaje de bienvenida Llamadas y videollamadas @@ -1056,7 +1056,7 @@ Servidores XFTP Puerto puerto %d - Configura Usar hosts .onion a No si el proxy SOCKS no los admite. + Usar hosts .onion a No si el proxy SOCKS no los admite.]]> Descargar archivo Usar proxy SOCKS Host @@ -1095,13 +1095,13 @@ El ID del siguiente mensaje es incorrecto (menor o igual que el anterior). \nPuede ocurrir por algún bug o cuando la conexión está comprometida. Por favor, informa a los desarrolladores. - %1$d mensajes omitidos. + %1$d mensajes omitidos. Hash de mensaje incorrecto ID de mensaje incorrecto Puede ocurrir cuando tu o tu contacto estáis usando una copia de seguridad antigua de la base de datos. El hash del mensaje anterior es diferente. El error es permanente para esta conexión, por favor vuelve a conectarte. - %1$d mensajes no pudieron ser descifrados. + %1$d mensajes no pudieron ser descifrados. ¡Sin espacios! Detener archivo El archivo será eliminado de los servidores. @@ -1138,7 +1138,7 @@ Vista previa Abriendo base de datos… Error al introducir la dirección - Más información en la Guía de usuario. + Guía de usuario.]]> Enlace un uso Dirección SimpleX Cuando alguien solicite conectarse podrás aceptar o rechazar su solicitud. @@ -1206,6 +1206,7 @@ personalizado Historial Detalles + Buscar Mensaje entrante Mensaje saliente Mensaje temporal @@ -1268,4 +1269,5 @@ Reiniciar Cerrar Las notificaciones dejarán de funcionar hasta que reinicies la aplicación + Desactivado \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-fi/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-fi/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml index 83c37137a0..39b860d455 100644 --- a/apps/multiplatform/android/src/main/res/values-fi/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fi/strings.xml @@ -1,5 +1,5 @@ - + 1 päivä 1 minuutti 1 kuukausi @@ -45,7 +45,7 @@ Pyydettiin videon vastaanottamista Tunnistaudu Tunnistautuminen ei ole käytettävissä - Huomaa: ET voi palauttaa tai muuttaa tunnuslausetta, jos kadotat sen. + Huomaa: ET voi palauttaa tai muuttaa tunnuslausetta, jos kadotat sen.]]> Yhdistä Yhteyden aikakatkaisu Kontaktin asetukset @@ -72,7 +72,7 @@ Poista jäsenviesti\? Laitteen todennus ei ole käytössä. Voit ottaa SimpleX Lockin käyttöön asetuksista, kun olet ottanut laitteen todennuksen käyttöön. Keskustele kehittäjien kanssa - Nykyinen tuettu enimmäistiedostokoko on %1$s. + Nykyinen tuettu enimmäistiedostokoko on %1$s. Poista kontakti\? Peruuta Poista palvelin @@ -83,7 +83,7 @@ %dd %d päivää Tuhoutuvat viestit ovat kiellettyjä tässä keskustelussa. - Erillistä TCP-yhteyttä (ja SOCKS-tunnistetietoja) käytetään jokaisessa käyttämässäsi sovelluksen chat-profiilissa. + jokaisessa käyttämässäsi sovelluksen chat-profiilissa.]]> Sovellusversio: %s Poista osoite Tietokanta salattu! @@ -133,7 +133,7 @@ %d kontaktia valittu mukautettu Aina päällä - Se voidaan poistaa käytöstä asetuksista – ilmoitukset näkyvät edelleen, kun sovellus on käynnissä. + Se voidaan poistaa käytöstä asetuksista – ilmoitukset näkyvät edelleen, kun sovellus on käynnissä.]]> Tarkistaa uudet viestit 10 minuutin välein enintään 1 minuutin ajan Vahvista kirjautumistietosi Laitteen todennus on poistettu käytöstä. SimpleX Lock kytketään pois päältä. @@ -148,7 +148,7 @@ Sovellusversio Yhteys Ydinversio: v%s - värillinen + värillinen virheellinen viestin tarkiste virheellinen viestin tunniste Vaihda itsetuhotilaa @@ -170,7 +170,7 @@ Lisää esiasetettuja palvelimia Arkisto Poista keskusteluarkisto\? - Luotu %1$s + Luotu %1$s %s:n rooli muutettu %s:ksi poistettu ryhmä yhdistää @@ -189,7 +189,7 @@ Salli kontaktiesi lähettää katoavia viestejä. Tuhoutuvat viestit Kontekstikuvake - Skannaa QR-koodi: muodostaaksesi yhteyden kontaktiisi, joka näyttää QR-koodin sinulle. + Skannaa QR-koodi: muodostaaksesi yhteyden kontaktiisi, joka näyttää QR-koodin sinulle.]]> Peruuta live-viesti Määritä ICE-palvelimet Lisää osoite profiiliisi, jotta kontaktisi voivat jakaa sen muiden kanssa. Profiilipäivitys lähetetään kontakteillesi. @@ -203,7 +203,7 @@ yhdistetty yhdistää… yhteys luotu - yhteys %1$d + yhteys %1$d Vertaa tiedostoa Kontaktia ei ole vielä yhdistetty! Tietoja SimpleX osoitteesta @@ -253,8 +253,8 @@ Mukautetut teemat Parempia viestejä Mukauta ja jaa väriteemoja. - Hyvä akulle. Taustapalvelu tarkistaa viestit 10 minuutin välein. Saatat jättää vastaamatta puheluihin tai kiireellisiin viesteihin. - Käyttää enemmän akkua! Taustapalvelu toimii aina – ilmoitukset näytetään heti, kun viestejä on saatavilla. + Hyvä akulle. Taustapalvelu tarkistaa viestit 10 minuutin välein. Saatat jättää vastaamatta puheluihin tai kiireellisiin viesteihin.]]> + Käyttää enemmän akkua! Taustapalvelu toimii aina – ilmoitukset näytetään heti, kun viestejä on saatavilla.]]> Salauksen purkuvirhe Poista minulle Poista kontakti @@ -263,7 +263,7 @@ Jokaiselle kontaktille ja ryhmän jäsenelle käytetään erillistä TCP-yhteyttä (ja SOCKS-tunnistetietoja). \nHuomaa: jos sinulla on useita yhteyksiä, akun ja data-liikenteen määrä voi olla huomattavasti korkeampi ja jotkin yhteydet voivat epäonnistua. Äänipuhelu - Paras akulle. Saat ilmoituksia vain, kun sovellus on käynnissä (EI taustapalvelua). + Paras akulle. Saat ilmoituksia vain, kun sovellus on käynnissä (EI taustapalvelua).]]> %d tuntia Taustapalvelu on aina käynnissä – ilmoitukset näytetään heti, kun viestit ovat saatavilla. Kontaktin nimi @@ -274,13 +274,13 @@ Katkaistu Takaisin Yhdistä linkillä / QR-koodilla - Lisää uusi kontakti: luo kertakäyttöinen QR-koodi kontaktille. + Lisää uusi kontakti: luo kertakäyttöinen QR-koodi kontaktille.]]> Tyhjennä - 💻 työpöytä: skannaa esitetty QR-koodi sovelluksesta käyttämällä Skannaa QR-koodi. + Skannaa QR-koodi.]]> Poistetaanko odottava yhteys\? Yhteyspyyntö lähetetty! Yhdistä linkin kautta - Tietoja SimpleX Chatistä + Tietoja SimpleX Chatistä Tietokannan tunnuslause ja vienti Luo profiili Luo @@ -295,7 +295,7 @@ muuttamassa %s:n osoitetta … muuttunut osoite sinulle Hyväksy puhelu - lihavoitu + lihavoitu yhdistää… Pyydettiin kuvan vastaanottamista Liitä @@ -311,7 +311,7 @@ Tarkista palvelimen osoite ja yritä uudelleen. Luo osoite Poista osoite\? - puhelu päättyi %1$s + puhelu päättyi %1$s puhelu käynnissä yhdistetty yhdistää puhelun… @@ -383,7 +383,7 @@ Ryhmälinkki Otetaanko automaattinen viestien poisto käyttöön\? Tiedosto vastaanotetaan, kun kontakti on online-tilassa, odota tai tarkista myöhemmin! - Jos et voi tavata henkilökohtaisesti, voit skannata QR-koodin videopuhelussa , tai kontaktisi voi jakaa kutsulinkin. + skannata QR-koodin videopuhelussa , tai kontaktisi voi jakaa kutsulinkin.]]> Jos päätät hylätä, lähettäjälle EI ilmoiteta. Jos syötät tämän pääsykoodin sovellusta avatessasi, kaikki sovelluksen tiedot poistetaan peruuttamattomasti! Ryhmäprofiili tallennetaan jäsenten laitteille, ei palvelimille. @@ -401,7 +401,7 @@ Miten Koko nimi: Miten markdownia käytetään - Miten SimpleX toimii + Miten SimpleX toimii Saapuva äänipuhelu Saapuva videopuhelu Sivuuta @@ -439,6 +439,7 @@ Välittömät ilmoitukset! Välittömät ilmoitukset on poistettu käytöstä! Tiedot + Haku Piilota Historia Suuri tiedosto! @@ -500,10 +501,10 @@ Virhe kontaktin poistamisessa Lataa tiedosto Virhe osoitteen asettamisessa - Jos sait SimpleX Chat -kutsulinkin, voit avata sen selaimessasi: + Jos sait SimpleX Chat -kutsulinkin, voit avata sen selaimessasi: Syötä palvelin manuaalisesti Miten käytät palvelimiasi - Asenna SimpleX Chat terminaaliin + Asenna SimpleX Chat terminaaliin Kirjoita tervetuloviesti... (valinnainen) Kutsu ystäviä Hei! @@ -553,7 +554,7 @@ apua Väärä turvakoodi! Virhe viestin lähettämisessä - Jotta voit käyttää sitä, <b xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">poista akun optimointi käytöstä</b> kohteelle <xliff:g xmlns:xliff=\"urn:oasis: names:tc:xliff:document:1.2\" id=\"appName\">SimpleX</xliff:g> seuraavassa valintaikkunassa. Muussa tapauksessa ilmoitukset poistetaan käytöstä. + poista akun optimointi käytöstä kohteelle SimpleX seuraavassa valintaikkunassa. Muussa tapauksessa ilmoitukset poistetaan käytöstä.]]> Piilotettu Heti Syötä pääsykoodi @@ -563,20 +564,20 @@ Galleriasta Virheellinen linkki! Virheellinen QR-koodi - Jos et voi tavata henkilökohtaisesti, näytä QR-koodi videopuhelussa tai jaa linkki. + näytä QR-koodi videopuhelussa tai jaa linkki.]]> Virheellinen palvelimen osoite! Näyttönimi Käännä kamera Se voi tapahtua, kun sinä tai kontaktisi käytitte vanhaa varmuuskopiota tietokannasta. Väärä pääsykoodi Ota lukitus käyttöön - kutsu ryhmään %1$s + kutsu ryhmään %1$s Kutsu jäseniä Ryhmäkutsu on vanhentunut - kutsuttu %1$s + kutsuttu %1$s Ryhmän koko nimi: Koko nimi (valinnainen) - kursivoitu + kursivoitu Avainnipun virhe muokattu Tiedosto poistetaan palvelimilta. @@ -596,7 +597,7 @@ ryhmäprofiili päivitetty Kutsu on vanhentunut! kutsuttu - epäsuora (%1$s) + epäsuora (%1$s) Ryhmän näyttönimi: Syötä salasana hakuun Ryhmän asetukset @@ -634,7 +635,7 @@ Onion-isäntiä käytetään, kun niitä on saatavilla. Portti portti %d - Aseta Use .onion hosts arvoon Ei, jos SOCKS-välityspalvelin ei tue niitä. + Use .onion hosts arvoon Ei, jos SOCKS-välityspalvelin ei tue niitä.]]> Jaa linkki Tallenna profiilin salasana Viestireaktiot @@ -672,7 +673,7 @@ Palauta Profiili- ja palvelinyhteydet Aseta ryhmän asetukset - Monet ovat kysyneet: jos SimpleX ei sisällä käyttäjätunnuksia, kuinka se voi toimittaa viestejä\? + jos SimpleX ei sisällä käyttäjätunnuksia, kuinka se voi toimittaa viestejä\?]]> PALVELIMET Tallenna ja ilmoita kontaktille Tallenna ja ilmoita kontakteille @@ -729,7 +730,7 @@ simplexmq: v%s (%2s) SOCKS-välityspalvelimen asetukset vastaamaton puhelu - salainen + salainen Jaa kontaktien kanssa Itsetuho Itsetuhoutuva pääsykoodi vaihdettu! @@ -753,7 +754,7 @@ Järjestelmän todennus Esiasetettu palvelimen osoite %s:n rooli muutettu: %s: - poistettu %1$s + poistettu %1$s Napauta liittyäksesi incognito-tilassa poistunut poisti sinut @@ -816,16 +817,16 @@ SimpleX-ryhmän linkki SimpleX-kertakutsu Päivitä sovellus ja ota yhteyttä kehittäjiin. - Tarkista verkkoyhteytesi %1$s ja yritä uudelleen. + Tarkista verkkoyhteytesi %1$s ja yritä uudelleen. Palvelin vaatii valtuutuksen jonojen luomiseen, tarkista salasana Moderoi - 📱 mobiili: napauta Avaa mobiilisovelluksessa, napauta sitten Yhdistä sovelluksessa. + Avaa mobiilisovelluksessa, napauta sitten Yhdistä sovelluksessa.]]> Lähetä live-viesti - se päivittyy vastaanottajille, kun kirjoitat sitä Merkitse luetuksi Merkitse lukemattomaksi Aseta kontaktin nimi Hyväksymäsi yhteys peruuntuu! - Lue lisää Käyttöoppaasta. + Käyttöoppaasta.]]> Merkitse vahvistetuksi SimpleX-osoite Lähetä kysymyksiä ja ideoita @@ -847,13 +848,13 @@ Tallenna asetukset\? Jutellaan SimpleX Chatissa vahvistus saatu… - Lue lisää GitHub-arkistostamme. + GitHub-arkistostamme.]]> Säännölliset - Vain asiakaslaitteet tallentavat käyttäjäprofiileja, yhteystietoja, ryhmiä ja viestejä, jotka on lähetetty 2-kerroksisella päästä päähän -salauksella. + 2-kerroksisella päästä päähän -salauksella.]]> Lue lisää GitHub-arkistostamme. Liitä vastaanotettu linkki Välityspalvelin suojaa IP-osoitteesi, mutta se voi tarkkailla puhelun kestoa. - Avaa SimpleX Chat hyväksyäksesi puhelun + Avaa SimpleX Chat hyväksyäksesi puhelun ei e2e-salausta TUE SIMPLEX CHATia VIESTIT JA TIEDOSTOT @@ -921,7 +922,7 @@ Ota yhteyttä ryhmän ylläpitäjään. Vaihda vastaanotto-osoite\? Pyydä kontaktiasi sallimaan ääniviestien lähettäminen. - Kiitos SimpleX Chatin asentamisesta! + Kiitos SimpleX Chatin asentamisesta! Asetukset Lisää Onion-isäntiä ei käytetä. @@ -1028,7 +1029,7 @@ kuukautta sekuntia Kiitos käyttäjille – osallistu Weblaten kautta! - Olet jo muodostanut yhteyden %1$s kanssa. + Olet jo muodostanut yhteyden %1$s kanssa. Ellei yhteyshenkilösi poistanut yhteyttä tai tämä linkki oli jo käytössä, se voi olla virhe - ilmoita siitä. \nJos haluat muodostaa yhteyden, pyydä kontaktiasi luomaan toinen yhteyslinkki ja tarkista, että verkkoyhteytesi on vakaa. Jos haluat saada ilmoituksia, kirjoita tietokannan tunnuslause @@ -1036,9 +1037,9 @@ Suojaa tietosi ottamalla SimpleX Lock käyttöön. \nSinua kehotetaan suorittamaan todennus loppuun, ennen kuin tämä ominaisuus otetaan käyttöön. Viesti poistetaan kaikilta jäseniltä. - Tervetuloa %1$s! + Tervetuloa %1$s! Et voi lähettää viestejä! - Kontaktisi lähetti tiedoston, joka on suurempi kuin tällä hetkellä tuettu enimmäiskoko (%1$s). + Kontaktisi lähetti tiedoston, joka on suurempi kuin tällä hetkellä tuettu enimmäiskoko (%1$s). Ääniviesti… Ääniviestit kielletty! Palvelimet nykyisen keskusteluprofiilisi uusille yhteyksille @@ -1053,27 +1054,27 @@ Väärä tunnuslause! Tuntematon tietokantavirhe: %s Tervetuloviesti - sinä: %1$s + sinä: %1$s Et menetä kontaktejasi, jos poistat osoitteesi myöhemmin. Kun sovellus on käynnissä - SimpleX + SimpleX Profiilisi lähetetään kontaktille, jolta sait tämän linkin. Liityt ryhmään, johon tämä linkki viittaa, ja muodostat yhteyden sen ryhmän jäseniin. Olet yhteydessä palvelimeen, jota käytetään vastaanottamaan viestejä tältä kontaktilta. - Yritetään muodostaa yhteys palvelimeen, jota käytetään viestien vastaanottamiseen tältä kontaktilta (virhe: %1$s). + Yritetään muodostaa yhteys palvelimeen, jota käytetään viestien vastaanottamiseen tältä kontaktilta (virhe: %1$s). sinä kertalinkillä - %1$s:n kautta + %1$s:n kautta Selaimella - SimpleX Chat palvelu + SimpleX Chat palvelu luvaton lähetys Kuvaa ei voida purkaa. Kokeile toista kuvaa tai ota yhteyttä kehittäjiin. Odottaa tiedostoa Aloita uusi keskustelu - Käyttää SimpleX Chat -palvelimia. - Sinä päätät, minkä palvelimien kautta viestit vastaanotetaan, kontaktiesi – palvelimet, joita käytät viestien lähettämiseen. + Käyttää SimpleX Chat -palvelimia. + vastaanotetaan, kontaktiesi – palvelimet, joita käytät viestien lähettämiseen.]]> Yksityisyytesi - poistit %1$s + poistit %1$s kyllä Ääniviestit Väärä tietokannan tunnuslause @@ -1086,7 +1087,7 @@ Käytä SOCKS-välityspalvelinta\? Hallitset keskustelujasi! Nykyinen profiilisi - Profiilisi tallennetaan laitteeseesi ja jaetaan vain kontaktiesi kanssa. SimpleX -palvelimet eivät näe profiiliasi. + Profiilisi tallennetaan laitteeseesi ja jaetaan vain kontaktiesi kanssa. SimpleX -palvelimet eivät näe profiiliasi. TEEMAT Tämä asetus koskee nykyisen keskusteluprofiilisi viestejä Tätä toimintoa ei voi kumota - kaikki vastaanotetut ja lähetetyt tiedostot ja media poistetaan. Matalan resoluution kuvat säilyvät. @@ -1103,7 +1104,7 @@ Teema Keskustelut-tietokantaasi ei ole salattu - aseta tunnuslause sen suojaamiseksi. Päivitä - %1$d ohitetut viestit + %1$d ohitetut viestit Voit aloittaa keskustelun sovelluksen Asetukset / Tietokanta kautta tai käynnistämällä sovelluksen uudelleen. muutit osoitetta Sinun on tunnistauduttava, kun käynnistät sovelluksen tai jatkat sen käyttöä 30 sekunnin tauon jälkeen. @@ -1114,14 +1115,14 @@ Odottaa kuvaa Video vastaanotetaan, kun kontaktisi on online-tilassa, odota tai tarkista myöhemmin! Näytä turvakoodi - Ääniviesti (%1$s) + Ääniviesti (%1$s) Video Voit jakaa osoitteesi linkkinä tai QR-koodina - kuka tahansa voi muodostaa yhteyden sinuun. Voit tarkistaa päästä päähän -salauksen kontaktisi kanssa vertaamalla (tai skannaamalla) laitteidenne koodia. Kontaktisi pysyvät yhdistettyinä. Viestintä- ja sovellusalusta, joka suojaa yksityisyyttäsi ja tietoturvaasi. videopuhelu - %1$s JÄSENET + %1$s JÄSENET Rooli muuttuu muotoon \"%s\". Kaikille ryhmän jäsenille ilmoitetaan asiasta. Rooli muuttuu muotoon \"%s\". Jäsen saa uuden kutsun. Ääniviestit ovat kiellettyjä tässä keskustelussa. @@ -1141,7 +1142,7 @@ Asetuksesi SMP-palvelimesi XFTP-palvelimesi - Käytä SimpleX Chat palvelimia\? + Käytä SimpleX Chat palvelimia\? TEEMAN VÄRIT Päivitä kuljetuksen eristystila\? Voit luoda sen myöhemmin @@ -1149,8 +1150,8 @@ \nVoit muuttaa sitä Asetuksista. Voit paljastaa piilotetun profiilisi kirjoittamalla koko salasanan Keskusteluprofiilit-sivun hakukenttään. Emme tallenna mitään kontaktejasi tai viestejäsi (kun ne on toimitettu) palvelimille. - Yksityisyyden suojaamiseksi kaikkien muiden alustojen käyttämien käyttäjätunnusten sijaan SimpleX käyttää viestijonojen tunnisteita, jotka ovat kaikille kontakteille erillisiä. - %1$s haluaa olla yhteydessä sinuun kautta + Yksityisyyden suojaamiseksi kaikkien muiden alustojen käyttämien käyttäjätunnusten sijaan SimpleX käyttää viestijonojen tunnisteita, jotka ovat kaikille kontakteille erillisiä. + %1$s haluaa olla yhteydessä sinuun kautta WebRTC ICE -palvelimet Keskustelut-tietokantasi Sinun tulee käyttää keskustelujen-tietokannan uusinta versiota AINOSTAAN yhdessä laitteessa, muuten saatat lakata vastaanottamasta viestejä joiltakin kontakteilta. @@ -1192,12 +1193,12 @@ Tämä teksti on saatavilla asetuksista Tervetuloa! lukematon - SimpleX Logo - SimpleX Tiimi + SimpleX Logo + SimpleX Tiimi Tämä linkki ei ole kelvollinen yhteyslinkki! Keskusteluprofiilisi Lataa tiedosto - Yksityisyytesi säilyttämiseksi sovelluksessa on push-ilmoitusten sijaan SimpleX-taustapalvelu – se kuluttaa muutaman prosentin akusta päivässä. + SimpleX-taustapalvelu – se kuluttaa muutaman prosentin akusta päivässä.]]> Avaa olet tarkkailija Liikaa videoita! @@ -1205,12 +1206,12 @@ Odottaa videota Tämä ominaisuus on kokeellinen! Se toimii vain, jos toisella on asennettuna versio 4.2. Sinun pitäisi nähdä viesti keskustelussa, kun osoitteenmuutos on valmis - tarkista, että voit edelleen vastaanottaa viestejä kyseiseltä kontaktilta (tai ryhmän jäseneltä). Sinun on sallittava kontaktiesi lähettää ääniviestejä, jotta voit lähettää niitä. - Voit olla yhteydessä SimpleX Chatin -kehittäjiin kysyäksesi kysymyksiä ja saadaksesi päivityksiä. + olla yhteydessä SimpleX Chatin -kehittäjiin kysyäksesi kysymyksiä ja saadaksesi päivityksiä.]]> Tämä QR-koodi ei ole linkki! Sinut yhdistetään ryhmään, kun ryhmän isännän laite on online-tilassa, odota tai tarkista myöhemmin! Sinut yhdistetään, kun yhteyspyyntösi on hyväksytty, odota tai tarkista myöhemmin! Sinut yhdistetään, kun kontaktisi laite on online-tilassa, odota tai tarkista myöhemmin! - Voit myös muodostaa yhteyden klikkaamalla linkkiä. Jos se avautuu selaimessa, napsauta Avaa mobiilisovelluksessa -painiketta. + Avaa mobiilisovelluksessa -painiketta.]]> SimpleX-osoitteesi Käytä uusiin yhteyksiin Käytä SOCKS-välityspalvelinta @@ -1235,15 +1236,15 @@ Kutsuit kontaktisi releellä Varoitus: saatat menettää joitain tietoja! - SimpleX Osoite + SimpleX Osoite Keskusteluprofiilisi lähetetään kontakteillesi odottaa vastaamista… Seuraavan sukupolven yksityisviestit odottaa vahvistusta… - %1$d viestit ohitettu. + %1$d viestit ohitettu. Seuraavan viestin tunnus on väärä (pienempi tai yhtä suuri kuin edellisen). \nTämä voi johtua jostain virheestä tai siitä, että yhteys on vaarantunut. - %1$d viestien salauksen purku epäonnistui. + %1$d viestien salauksen purku epäonnistui. Näytä Sinun on annettava tunnuslause aina, kun sovellus käynnistyy - sitä ei tallenneta laitteeseen. Päivitä tietokannan tunnuslause @@ -1265,4 +1266,5 @@ SOVELLUS Käynnistä uudelleen Sulje\? + Pois \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-fr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-fr/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml index ace389afb9..325b02ecfd 100644 --- a/apps/multiplatform/android/src/main/res/values-fr/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/fr/strings.xml @@ -1,8 +1,8 @@ - + k Se connecter via le lien du contact \? - SimpleX + SimpleX Votre profil va être envoyé au contact qui vous a envoyé ce lien. Vous allez rejoindre le groupe correspondant à ce lien et être mis en relation avec les autres membres du groupe. Se connecter @@ -14,7 +14,7 @@ connexion établie invité à se connecter Invitation unique SimpleX - via %1$s + via %1$s Liens SimpleX Description Erreur lors de la suppression du contact @@ -31,7 +31,7 @@ Lien de groupe SimpleX Via navigateur Ouvrir le lien dans le navigateur peut réduire la confidentialité et la sécurité de la connexion. Les liens SimpleX non fiables seront en rouge. - Vérifiez votre connexion réseau avec %1$s et réessayez. + Vérifiez votre connexion réseau avec %1$s et réessayez. Erreur lors de la réception du fichier L\'expéditeur a peut-être supprimé la demande de connexion. Vous êtes connecté·e au serveur utilisé pour recevoir les messages de ce contact. @@ -41,7 +41,7 @@ Adresse de contact SimpleX Tentative de connexion au serveur utilisé pour recevoir les messages de ce contact. la réception de fichiers n\'est pas encore supportée - connexion %1$d + connexion %1$d vous avez partagé un lien unique via un lien unique mode incognito via un lien unique @@ -52,7 +52,7 @@ Veuillez vérifier que vous avez utilisé le bon lien ou demandez à votre contact de vous en envoyer un autre. Erreur de connexion Erreur lors de l\'ajout de membre·s - Tentative de connexion au serveur utilisé pour recevoir les messages de ce contact (erreur : %1$s). + Tentative de connexion au serveur utilisé pour recevoir les messages de ce contact (erreur : %1$s). format de message invalide Lien entier Erreur lors de la sauvegarde des serveurs SMP @@ -60,7 +60,7 @@ Lien de connection invalide Délai de connexion Erreur lors de l\'envoi du message - Vous êtes déjà connecté à %1$s. + Vous êtes déjà connecté à %1$s. Erreur de connexion (AUTH) A moins que votre contact ait supprimé la connexion ou que ce lien ait déjà été utilisé, il peut s\'agir d\'un bug - veuillez le signaler. \nPour vous connecter, veuillez demander à votre contact de créer un autre lien de connexion et vérifiez que vous disposez d\'une connexion réseau stable. @@ -79,15 +79,15 @@ Notifications instantanées Notifications instantanées ! Les notifications instantanées sont désactivées ! - Il peut être désactivé via les paramètres - les notifications seront toujours affichées lorsque l\'application est en cours d\'exécution. + Il peut être désactivé via les paramètres - les notifications seront toujours affichées lorsque l\'application est en cours d\'exécution.]]> L\'optimisation de la batterie est active et désactive le service de fond et les demandes périodiques de nouveaux messages. Vous pouvez les réactiver via les paramètres. Notifications périodiques Les notifications périodiques sont désactivées ! Une phrase secrète est nécessaire - Pour l\'utiliser, veuillez désactiver l\'optimisation de la batterie pour SimpleX dans la prochaine fenêtre de dialogue. Sinon, les notifications seront désactivées. + désactiver l\'optimisation de la batterie pour SimpleX dans la prochaine fenêtre de dialogue. Sinon, les notifications seront désactivées.]]> Le serveur requiert une autorisation pour créer des files d\'attente, vérifiez le mot de passe L\'application récupère périodiquement les nouveaux messages - elle utilise un peu votre batterie chaque jour. L\'application n\'utilise pas les notifications push - les données de votre appareil ne sont pas envoyées aux serveurs. - Pour protéger votre vie privée, au lieu des notifications push, l\'application possède un SimpleX service de fond - il utilise quelques pour cent de la batterie par jour. + SimpleX service de fond - il utilise quelques pour cent de la batterie par jour.]]> Cacher Montrer l\'aperçu Nom du contact @@ -138,7 +138,7 @@ Aperçu de notification Échec d’initialisation de la base de données Pour recevoir des notifications, veuillez entrer la phrase secrète de la base de données - service SimpleX Chat + service SimpleX Chat Ce texte est disponible dans les paramètres rejoindre en tant que %s vous êtes invité·e au groupe @@ -158,7 +158,7 @@ Partager le message… Partager le média… Envoi de 10 images en même temps maximum - Bienvenue %1$s ! + Bienvenue %1$s ! Vérifie les nouveaux messages toutes les 10 minutes pendant 1 minute au maximum. Afficher uniquement le contact Pour tous @@ -206,11 +206,11 @@ Vidéo Pour démarrer une nouvelle discussion Appuyez sur le bouton - Scanner un code QR : pour vous connecter à votre contact qui vous montre un code QR. + Scanner un code QR : pour vous connecter à votre contact qui vous montre un code QR.]]> Pour se connecter via un lien - Si vous avez reçu un lien d\'invitation SimpleX Chat, vous pouvez l\'ouvrir dans votre navigateur : - 💻 bureau : scanner le code QR affiché depuis l\'app, via Scanner le code QR. - 📱 mobile : appuyez sur Ouvrir dans l\'application, puis appuyez sur se connecter dans l\'app. + Si vous avez reçu un lien d\'invitation SimpleX Chat, vous pouvez l\'ouvrir dans votre navigateur : + Scanner le code QR.]]> + Ouvrir dans l\'application, puis appuyez sur se connecter dans l\'app.]]> Accepter en incognito Rejeter Effacer la conversation \? @@ -231,9 +231,9 @@ image d\'aperçu du lien annuler l\'aperçu du lien Paramètres - Adresse SimpleX + Adresse SimpleX aide - Équipe SimpleX + Équipe SimpleX Plus Afficher le code QR Code QR invalide @@ -246,7 +246,7 @@ Votre profil de chat sera envoyé à votre contact Coller Cette chaîne n\'est pas un lien de connexion ! - Vous pouvez aussi vous connecter en cliquant sur le lien. Si il s\'ouvre dans le navigateur, cliquez sur Ouvrir dans l\'app mobile. + Ouvrir dans l\'app mobile.]]> Créer un lien d\'invitation unique Définir le nom du contact… Déconnecté @@ -275,7 +275,7 @@ veut établir une connexion ! image de profil (placeholder) Code QR - Logo SimpleX + Logo SimpleX E-mail Se connecter L\'application peut recevoir des notifications uniquement lorsqu\'elle est en cours d\'exécution, aucun service d\'arrière-plan ne sera lancé. @@ -290,15 +290,15 @@ modifié L\'image sera reçue quand votre contact sera en ligne, merci d\'attendre ou de revenir plus tard ! Erreur de décodage - Votre contact a envoyé un fichier dont la taille est supérieure à la taille maximale actuellement prise en charge (%1$s). + Votre contact a envoyé un fichier dont la taille est supérieure à la taille maximale actuellement prise en charge (%1$s). En attente du fichier Message vocal Autorisation refusée ! Appareil\nphoto - Merci d\'avoir installé SimpleX Chat ! - Vous pouvez vous connecter aux développeurs de SimpleX Chat pour leur poser des questions et recevoir des réponses :. + Merci d\'avoir installé SimpleX Chat ! + vous connecter aux développeurs de SimpleX Chat pour leur poser des questions et recevoir des réponses :.]]> ci-dessus, puis : - Ajouter un nouveau contact : afin de créer un code QR à usage unique pour votre contact. + Ajouter un nouveau contact : afin de créer un code QR à usage unique pour votre contact.]]> Si vous choisissez de la rejeter, l\'expéditeur·rice NE sera PAS notifié·e. Accepter Muet @@ -309,26 +309,26 @@ Demande de connexion envoyée ! Le fichier sera reçu quand votre contact sera en ligne, merci d\'attendre ou de revenir plus tard ! Message vocal… - La taille maximale supportés des fichiers actuellement est de %1$s. - Message vocal (%1$s) + La taille maximale supportés des fichiers actuellement est de %1$s. + Message vocal (%1$s) Notifications - Cette fonctionnalité est expérimentale ! Elle ne fonctionnera que si l\'autre client a la version 4.2 installée. Vous devriez voir le message dans la conversation une fois le changement d\'adresse effectué. Vérifiez que vous pouvez toujours recevoir des messages de ce contact (ou membre du groupe). + L\'adresse de réception sera changée pour un autre serveur. Le changement d\'adresse sera terminé lorsque l\'expéditeur sera en ligne. Vous serez connecté·e au groupe lorsque l\'appareil de l\'hôte sera en ligne, veuillez attendre ou vérifier plus tard ! - Si vous ne pouvez pas vous rencontrer en personne, montrez le code QR lors d\'un appel vidéo, ou partagez le lien. + montrez le code QR lors d\'un appel vidéo, ou partagez le lien.]]> Scannez le code de sécurité depuis l\'application de votre contact. Pour vérifier le chiffrement de bout en bout avec votre contact, comparez (ou scannez) le code sur vos appareils. - Si vous ne pouvez pas vous rencontrer en personne, vous pouvez scanner un code QR lors d\'un appel vidéo, ou votre contact peut partager un lien d\'invitation. + scanner un code QR lors d\'un appel vidéo, ou votre contact peut partager un lien d\'invitation.]]> Ajouter un serveur… Markdown dans les messages Ajouter des serveurs prédéfinis - Utiliser les serveurs SimpleX Chat \? + Utiliser les serveurs SimpleX Chat \? Supprimer le serveur Assurez-vous que les adresses des serveurs WebRTC ICE sont au bon format et ne sont pas dupliquées, un par ligne. Accéder aux serveurs via un proxy SOCKS sur le port %d \? Le proxy doit être démarré avant d\'activer cette option. Utiliser les hôtes .onions Les hôtes .onion seront utilisés lorsqu\'ils sont disponibles. Les hôtes .onion seront nécessaires pour la connexion. - Vous contrôlez par quel·s serveur·s vous pouvez transmettre ainsi que par quel·s serveur·s vous pouvez recevoir les messages de vos contacts. + transmettre ainsi que par quel·s serveur·s vous pouvez recevoir les messages de vos contacts.]]> Vos paramètres SimpleX Lock Console du chat @@ -339,7 +339,7 @@ Utiliser ce serveur Utiliser pour les nouvelles connexions Ajouter à un autre appareil - Installer SimpleX Chat pour terminal + Installer SimpleX Chat pour terminal Star sur GitHub Contribuer Évaluer l\'app @@ -369,9 +369,9 @@ Créer À propos de SimpleX Vous pouvez utiliser le format markdown pour mettre en forme les messages : - gras - italique - barré + gras + italique + barré appel accepté connexion à l\'appel… erreur d\'appel @@ -379,7 +379,7 @@ confimation reçu… connexion… Protocole et code open-source – n\'importe qui peut heberger un serveur. - Pour protéger votre vie privée, au lieu d\'IDs utilisés par toutes les autres plateformes, SimpleX possède des IDs pour les queues de messages, distinctes pour chacun de vos contacts. + Pour protéger votre vie privée, au lieu d\'IDs utilisés par toutes les autres plateformes, SimpleX possède des IDs pour les queues de messages, distinctes pour chacun de vos contacts. Plus d\'informations sur notre GitHub. Coller le lien reçu Utiliser le chat @@ -388,8 +388,8 @@ Quand l\'application fonctionne Périodique Instantanée - Économie de batterie. Vous recevrez des notifications uniquement lorsque l\'application est en cours d\'exécution (PAS de service d\'arrière-plan) - À propos de SimpleX Chat + Économie de batterie. Vous recevrez des notifications uniquement lorsque l\'application est en cours d\'exécution (PAS de service d\'arrière-plan)]]> + À propos de SimpleX Chat Comment l\'utiliser Aide Markdown Sauvegarder @@ -398,7 +398,7 @@ Quitter sans sauvegarder appel rejeté appel en cours - appel terminé %1$s + appel terminé %1$s lancement… %s est vérifié·e %s n\'est pas vérifié·e @@ -416,7 +416,7 @@ Votre adresse de serveur Adresse de serveur invalide ! Vérifiez l\'adresse du serveur et réessayez. - Utilise les serveurs SimpleX Chat. + Utilise les serveurs SimpleX Chat. Comment faire Serveurs ICE (un par ligne) Erreur lors de la sauvegarde des serveurs ICE @@ -431,7 +431,7 @@ Supprimer l\'adresse Nom affiché : Nom complet : - Votre profil est stocké sur votre appareil et partagé uniquement avec vos contacts. Les serveurs SimpleX ne peuvent pas voir votre profil. + Votre profil est stocké sur votre appareil et partagé uniquement avec vos contacts. Les serveurs SimpleX ne peuvent pas voir votre profil. Supprimer l\'image Sauvegarder les préférences \? Vous maîtrisez vos discussions ! @@ -441,8 +441,8 @@ Nom affiché Comment utiliser markdown a + b - coloré - secret + coloré + secret appel… appel manqué en attente de réponse… @@ -458,13 +458,13 @@ Créez votre profil Établir une connexion privée Comment ça fonctionne - Comment SimpleX fonctionne - Beaucoup se demandent : si SimpleX n\'a pas d\'identifiant d\'utilisateur, comment peut-il transmettre des messages \? - Seuls les appareils clients stockent les profils des utilisateurs, les contacts, les groupes et les messages envoyés avec un chiffrement de bout en bout à deux couches. - Pour en savoir plus, consultez notre GitHub repository. - Batterie peu utilisée. Le service de fond vérifie les messages toutes les 10 minutes. Vous risquez de manquer des appels ou des messages urgents. - Batterie plus utilisée ! Le service de fond est toujours en cours d\'exécution - les notifications s\'affichent dès que les messages sont disponibles. - %1$d message⸱s manqué⸱s + Comment SimpleX fonctionne + si SimpleX n\'a pas d\'identifiant d\'utilisateur, comment peut-il transmettre des messages \?]]> + chiffrement de bout en bout à deux couches.]]> + GitHub repository.]]> + Batterie peu utilisée. Le service de fond vérifie les messages toutes les 10 minutes. Vous risquez de manquer des appels ou des messages urgents.]]> + Batterie plus utilisée ! Le service de fond est toujours en cours d\'exécution - les notifications s\'affichent dès que les messages sont disponibles.]]> + %1$d message⸱s manqué⸱s ID de message incorrecte PARAMÈTRES Cela peut arriver quand : @@ -472,8 +472,8 @@ \n2. Le déchiffrement du message a échoué, car vous ou votre contact avez utilisé une ancienne sauvegarde de base de données. \n3. La connexion a été compromise. Appel rejeté - a retiré %1$s - vous avez retiré %1$s + a retiré %1$s + vous avez retiré %1$s invité par votre lien de groupe vous avez changé d\'adresse Arrêtez le chat pour exporter, importer ou supprimer la base de données du chat. Vous ne pourrez pas recevoir et envoyer de messages pendant que le chat est arrêté. @@ -483,7 +483,7 @@ La phrase secrète n\'a pas été trouvée dans le Keystore, veuillez la saisir manuellement. Cela a pu se produire si vous avez restauré les données de l\'app à l\'aide d\'un outil de sauvegarde. Si ce n\'est pas le cas, veuillez contacter les développeurs. Veuillez entrer le mot de passe précédent après avoir restauré la sauvegarde de la base de données. Cette action ne peut pas être annulée. Erreur de restauration de la base de données - Créé le %1$s + Créé le %1$s appel vidéo (chiffrement de bout en bout) appel audio (sans chiffrement) appel audio (chiffrement de bout en bout) @@ -518,7 +518,7 @@ Chiffrer Veuillez entrer la phrase secrète actuelle correcte. Votre base de données de chat n\'est pas chiffrée - définissez une phrase secrète pour la protéger. - Veuillez noter : vous NE pourrez PAS récupérer ou modifier la phrase secrète si vous la perdez. + Veuillez noter : vous NE pourrez PAS récupérer ou modifier la phrase secrète si vous la perdez.]]> Le Keystore d\'Android sera utilisé pour stocker en toute sécurité la phrase secrète après sa modification ou redémarrage de l\'app - cela permettra de recevoir les notifications. Veuillez conserver votre phrase secrète en lieu sûr, vous NE pourrez PAS accéder au chat si vous la perdez. La phrase secrète de la base de données est différente de celle enregistrée dans le Keystore. @@ -585,7 +585,7 @@ \nCette action ne peut être annulée - votre profil, vos contacts, vos messages et vos fichiers seront irrémédiablement perdus. Entrez la phrase secrète… Appel audio entrant - %1$s veut se connecter à vous via + %1$s veut se connecter à vous via Vos appels Se connecter via relais Appels en écran verrouillé : @@ -595,7 +595,7 @@ Serveurs WebRTC ICE Le serveur relais protège votre adresse IP, mais il peut observer la durée de l\'appel. Le serveur relais n\'est utilisé que si nécessaire. Un tiers peut observer votre adresse IP. - Ouvrez SimpleX Chat pour décrocher + Ouvrez SimpleX Chat pour décrocher sans chiffrement de bout en bout Ce contact a le chiffrement de bout en bout Ce contact n\'a pas le chiffrement de bout en bout @@ -666,7 +666,7 @@ Sauvegarder l\'archive Supprimer l\'archive Supprimer l\'archive du chat \? - Invitation au groupe %1$s + Invitation au groupe %1$s Rejoindre le groupe \? Vous êtes invité·e dans un groupe. Rejoignez le pour vous connecter avec ses membres. Rejoindre @@ -678,7 +678,7 @@ Appuyez pour rejoindre Appuyez pour rejoindre incognito Invitation au groupe expirée - a invité %1$s + a invité %1$s est connecté·e a modifié le rôle de %s pour %s a modifié votre rôle pour %s @@ -737,8 +737,8 @@ Passer l’invitation de membres Sélectionnez des contacts Aucun contact sélectionné - %1$s MEMBRES - vous : %1$s + %1$s MEMBRES + vous : %1$s Supprimer le groupe Le groupe va être supprimé pour tout les membres - impossible de revenir en arrière ! Le groupe va être supprimé pour vous - impossible de revenir en arrière ! @@ -856,7 +856,7 @@ Les messages vocaux sont interdits dans ce groupe. Nom affiché du groupe : Le mode Incognito n\'est pas supporté ici - votre profil principal sera envoyé aux membres du groupe - indirecte (%1$s) + indirecte (%1$s) Groupe Connexion sec @@ -919,7 +919,7 @@ Toutes les discussions et tous les messages seront supprimés - il est impossible de revenir en arrière ! Effacer tous les fichiers Supprimer le profil de chat pour - Une connexion TCP distincte (et un identifiant SOCKS) sera utilisée pour chaque profil de chat que vous avez dans l\'application. + pour chaque profil de chat que vous avez dans l\'application.]]> Supprimer le profil du chat \? Fichiers & médias Messages @@ -1059,7 +1059,7 @@ port %d Paramètres de proxy SOCKS Utiliser un proxy SOCKS - Définissez Utiliser les hôtes .onion sur Non si le proxy SOCKS ne les prend pas en charge. + Utiliser les hôtes .onion sur Non si le proxy SOCKS ne les prend pas en charge.]]> Mode de SimpleX Lock SimpleX Lock n\'est pas activé ! Authentification du système @@ -1119,8 +1119,8 @@ Arrêter de recevoir le fichier \? Cette erreur est persistante pour cette connexion, veuillez vous reconnecter. Vous n\'avez pas pu être vérifié·e ; veuillez réessayer. - %1$d messages n\'ont pas pu être déchiffrés. - %1$d messages sautés. + %1$d messages n\'ont pas pu être déchiffrés. + %1$d messages sautés. Vous pouvez activer SimpleX Lock dans les Paramètres. Merci aux utilisateurs - contribuez via Weblate ! Vidéos et fichiers jusqu\'à 1Go @@ -1180,7 +1180,7 @@ Message reçu Assurez-vous que le fichier a une syntaxe YAML correcte. Exporter le thème pour avoir un exemple de la structure du fichier du thème. La mise à jour du profil sera envoyée à vos contacts. - Pour en savoir plus, consultez le Guide de l\'utilisateur. + Guide de l\'utilisateur.]]> Sauvegarder les paramètres d\'acceptation automatique Pour se connecter, votre contact peut scanner le code QR ou utiliser le lien dans l\'application. Vos contacts dans SimpleX la verront. @@ -1228,6 +1228,7 @@ Erreur de chargement des détails Historique Info + Rechercher Message reçu personnalisé Choisir @@ -1267,4 +1268,10 @@ Mise à l\'arrêt Redémarrer APP + Annuler + Erreur lors de l\'annulation du changement d\'adresse + Abandonner le changement d\'adresse \? + Annuler le changement d\'adresse + Le changement d\'adresse sera annulé. L\'ancienne adresse de réception sera utilisée. + Désactivé \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-hi/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/hi/strings.xml similarity index 97% rename from apps/multiplatform/android/src/main/res/values-hi/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/hi/strings.xml index 8b619b3bfa..049df269ea 100644 --- a/apps/multiplatform/android/src/main/res/values-hi/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/hi/strings.xml @@ -1,5 +1,5 @@ - + चित्र साझा करें… बंद 1 दिन निर्धारित करें @@ -11,7 +11,7 @@ स्वीकार करना जुडिये दूसरे उपकरण में जोड़ें - निडर + निडर कॉल का उत्तर दें तुम समायोजन @@ -27,7 +27,7 @@ 1 दिन 1 सप्ताह सिंपलएक्स के बारे में - बारे में सिंप्लेक्स चैट + बारे में सिंप्लेक्स चैट स्वीकार करना स्वीकार करना स्वीकार करना @@ -48,7 +48,7 @@ फ़ाइल पूर्वावलोकन रद्द करें छवि पूर्वावलोकन रद्द करें साफ़ - रंगीन + रंगीन जुड़े हुए जुडिये जुडिये @@ -57,7 +57,7 @@ जुड़े हुए जुड़े हुए आप इस समूह में शामिल हो गए - तुम: %1$s + तुम: %1$s आपको समूह में आमंत्रित किया जाता है तुमने पता बदल लिया आप चले गए @@ -66,7 +66,7 @@ स्वागत! चालू करो अज्ञात संदेश प्रारूप - स्वागत %1$s! + स्वागत %1$s! शुरुआत भेजना रंग बचाओ @@ -76,7 +76,7 @@ अस्वीकार खुला निकाला गया - निकाला गया %1$s + निकाला गया %1$s जवाब दे दो छोड़ना पढ़ा हुआ चिह्नित करें @@ -87,13 +87,13 @@ बाद मिटा दें जुड़ने के लिए आमंत्रित किया आपके समूह लिंक के माध्यम से आमंत्रित किया गया - आमंत्रित %1$s + आमंत्रित %1$s सदस्यों को आमंत्रित करो अपरिवर्तनीय संदेश विलोपन सदस्यों को आमंत्रित करो समूह में आमंत्रित करें इस समूह में अपरिवर्तनीय संदेश हटाना प्रतिबंधित है। - तिरछा + तिरछा प्रवेश लेना गुप्त में शामिल हों समूह में शामिल होना @@ -290,4 +290,6 @@ सदस्य को समूह से निकाल दिया जाएगा - इसे पूर्ववत नहीं किया जा सकता! सदस्य सदस्य + खोजें + बंद है \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/hr/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/hr/strings.xml new file mode 100644 index 0000000000..bd1875a788 --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/hr/strings.xml @@ -0,0 +1,5 @@ + + + Pretraži + Isključeno + \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-it/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-it/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml index 6e817c23c7..2fdc66e335 100644 --- a/apps/multiplatform/android/src/main/res/values-it/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/it/strings.xml @@ -1,7 +1,7 @@ - + Link di SimpleX - Controlla la tua connessione di rete con %1$s e riprova. + Controlla la tua connessione di rete con %1$s e riprova. Le notifiche istantanee sono disattivate! in connessione… Allega @@ -9,7 +9,7 @@ Possono essere inviate solo 10 immagini alla volta L\'immagine verrà ricevuta quando il tuo contatto sarà in linea, aspetta o controlla più tardi! In attesa dell\'immagine - SimpleX + SimpleX k Connettere via link di invito\? Connettere via link del gruppo\? @@ -81,7 +81,7 @@ Disconnetti Notifiche istantanee Notifiche istantanee! - Può essere disattivato nelle impostazioni; le notifiche verranno comunque mostrate mentre l\'app è in uso. + Può essere disattivato nelle impostazioni; le notifiche verranno comunque mostrate mentre l\'app è in uso.]]> L\'ottimizzazione della batteria è attiva, spegnimento del servizio in secondo piano e delle richieste periodiche di messaggi nuovi. Puoi riattivarli nelle impostazioni. Notifiche periodiche Le notifiche periodiche sono disattivate! @@ -142,7 +142,7 @@ invio non autorizzato invio fallito non letto - Benvenuto/a %1$s! + Benvenuto/a %1$s! Benvenuto/a! Questo testo è disponibile nelle impostazioni Сhat @@ -166,14 +166,14 @@ Immagine salvata nella Galleria File File grande! - Attualmente la dimensione massima supportata è di %1$s. + Attualmente la dimensione massima supportata è di %1$s. In attesa del file Il file verrà ricevuto quando il tuo contatto sarà in linea, aspetta o controlla più tardi! File salvato File non trovato Errore di salvataggio del file Messaggio vocale - Messaggio vocale (%1$s) + Messaggio vocale (%1$s) Messaggio vocale… Notifiche Eliminare il contatto\? @@ -201,19 +201,19 @@ Ripristina OK Connettere via link del contatto\? - Tentativo di connessione al server usato per ricevere messaggi da questo contatto (errore: %1$s). + Tentativo di connessione al server usato per ricevere messaggi da questo contatto (errore: %1$s). Entrerai in un gruppo a cui si riferisce questo link e ti connetterai ai suoi membri. - connessione %1$d + connessione %1$d Descrizione - via %1$s + via %1$s Aprire il link nel browser può ridurre la privacy e la sicurezza della connessione. I link SimpleX non fidati saranno in rosso. - Sei già connesso a %1$s. + Sei già connesso a %1$s. A meno che il tuo contatto non abbia eliminato la connessione o che questo link non sia già stato usato, potrebbe essere un errore; per favore segnalalo. \nPer connetterti, chiedi al tuo contatto di creare un altro link di connessione e controlla di avere una connessione di rete stabile. Probabilmente l\'impronta del certificato nell\'indirizzo del server è sbagliata - Per rispettare la tua privacy, invece delle notifiche push l\'app ha un servizio SimpleX in secondo piano; usa una piccola percentuale di batteria al giorno. - Per poterlo usare, disattiva l\'ottimizzazione della batteria per SimpleX nella prossima schermata. Altrimenti le notifiche saranno disattivate. - Servizio SimpleX Chat + servizio SimpleX in secondo piano; usa una piccola percentuale di batteria al giorno.]]> + disattiva l\'ottimizzazione della batteria per SimpleX nella prossima schermata. Altrimenti le notifiche saranno disattivate.]]> + Servizio SimpleX Chat Servizio in secondo piano sempre attivo. Le notifiche verranno mostrate appena i messaggi saranno disponibili. SimpleX Lock Per proteggere le tue informazioni, attiva SimpleX Lock. @@ -223,14 +223,14 @@ L\'autenticazione del dispositivo non è attiva. Potrai attivare SimpleX Lock nelle impostazioni, quando avrai attivato l\'autenticazione del dispositivo. Il messaggio verrà contrassegnato per l\'eliminazione. I destinatari potranno rivelare questo messaggio. Condividi messaggio… - Il tuo contatto ha inviato un file più grande della dimensione massima supportata (%1$s). + Il tuo contatto ha inviato un file più grande della dimensione massima supportata (%1$s). Il contatto e tutti i messaggi verranno eliminati, non è reversibile! - Questa funzionalità è sperimentale! Funzionerà solo se l\'altro client ha la versione 4.2 installata. Dovresti vedere il messaggio nella conversazione una volta completato il cambio di indirizzo. Controlla di potere ancora ricevere messaggi da questo contatto (o membro del gruppo). + L\'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell\'indirizzo verrà completata dopo che il mittente sarà in linea. Solo i proprietari del gruppo possono attivare i messaggi vocali. Invia un messaggio in diretta: si aggiornerà per i destinatari mentre lo digiti 1 giorno a + b - Riguardo SimpleX Chat + Riguardo SimpleX Chat amministratore 1 settimana Aggiungi ad un altro dispositivo @@ -264,7 +264,7 @@ 1 mese Errore nell\'importazione del database della chat Nome completo del gruppo: - Se non potete incontrarvi di persona, puoi scansionare il codice QR nella videochiamata, oppure il tuo contatto può condividere un link di invito. + scansionare il codice QR nella videochiamata, oppure il tuo contatto può condividere un link di invito.]]> Backup dei dati dell\'app Android Keystore è usato per memorizzare in modo sicuro la password; permette il funzionamento del servizio di notifica. Permetti ai tuoi contatti di inviare messaggi vocali. @@ -272,8 +272,8 @@ ICONA APP Verrà inviato un profilo casuale al contatto da cui hai ricevuto questo link Verrà inviato un profilo casuale al tuo contatto - Ideale per la batteria. Riceverai notifiche solo quando l\'app è in esecuzione (NO servizio in secondo piano). - Consuma più batteria! Servizio in secondo piano sempre attivo: le notifiche sono mostrate non appena i messaggi sono disponibili. + Ideale per la batteria. Riceverai notifiche solo quando l\'app è in esecuzione (NO servizio in secondo piano).]]> + Consuma più batteria! Servizio in secondo piano sempre attivo: le notifiche sono mostrate non appena i messaggi sono disponibili.]]> chiamata… annulla anteprima link Impossibile accedere al Keystore per salvare la password del database @@ -294,8 +294,8 @@ Elimina I messaggi diretti tra i membri sono vietati in questo gruppo. Nome da mostrare - Aggiungi un contatto: per creare il tuo codice QR una tantum per il tuo contatto. - Scansiona codice QR: per connetterti al contatto che ti mostra il codice QR. + Aggiungi un contatto: per creare il tuo codice QR una tantum per il tuo contatto.]]> + Scansiona codice QR: per connetterti al contatto che ti mostra il codice QR.]]> File Svuota chat Svuotare la chat\? @@ -304,7 +304,7 @@ Copiato negli appunti Crea link di invito una tantum Crea gruppo segreto - 💻 desktop: scansiona dall\'app il codice QR mostrato, tramite Scansiona codice QR. + Scansiona codice QR.]]> Dalla Galleria Immagine Video @@ -316,7 +316,7 @@ Eliminare la connessione in attesa\? Email aiuto - Se non potete incontrarvi di persona, mostra il codice QR nella videochiamata, oppure condividi il link. + mostra il codice QR nella videochiamata, oppure condividi il link.]]> Console della chat Annulla la verifica Connetti @@ -337,11 +337,11 @@ Come si fa Come usare i tuoi server Server ICE (uno per riga) - grassetto - chiamata terminata %1$s + grassetto + chiamata terminata %1$s errore di chiamata chiamata in corso - colorato + colorato connesso connessione… connessione chiamata… @@ -357,7 +357,7 @@ Come usare il markdown chiamata audio chiamata audio (non crittografata e2e) - Buono per la batteria. Il servizio in secondo piano cerca messaggi ogni 10 minuti. Potresti perdere chiamate o messaggi urgenti. + Buono per la batteria. Il servizio in secondo piano cerca messaggi ogni 10 minuti. Potresti perdere chiamate o messaggi urgenti.]]> Chiamata già terminata! Crea il tuo profilo Decentralizzato @@ -365,7 +365,7 @@ Videochiamata crittografata e2e terminata Come funziona - Come funziona SimpleX + Come funziona SimpleX Rispondi alla chiamata Audio spento Audio acceso @@ -406,7 +406,7 @@ AIUTO Archivio chat Chat fermata - Creato il %1$s + Creato il %1$s Errore del database La password del database è diversa da quella salvata nel Keystore. Elimina archivio @@ -509,7 +509,7 @@ Messaggi a tempo Nascondi la schermata dell\'app nelle app recenti. Android Keystore verrà usato per memorizzare in modo sicuro la password dopo il riavvio dell\'app o la modifica della password; consentirà di ricevere le notifiche. - Nota bene: NON potrai recuperare o cambiare la password se la perdi. + Nota bene: NON potrai recuperare o cambiare la password se la perdi.]]> Cambiare password del database\? Conferma password nuova… Password attuale… @@ -528,8 +528,8 @@ Errore nella crittografia del database Le tue impostazioni Verrai connesso/a al gruppo quando il dispositivo dell\'host del gruppo sarà in linea, attendi o controlla più tardi! - Se hai ricevuto il link di invito a SimpleX Chat, puoi aprirlo nel tuo browser: - 📱 mobile: tocca Apri nell\'app mobile, quindi Connetti nell\'app. + Se hai ricevuto il link di invito a SimpleX Chat, puoi aprirlo nel tuo browser: + Apri nell\'app mobile, quindi Connetti nell\'app.]]> nessun dettaglio Link di invito una tantum (memorizzato solo dai membri del gruppo) @@ -539,12 +539,12 @@ Scansiona codice QR Inizia una nuova conversazione Tocca il pulsante - Grazie per aver installato SimpleX Chat! + Grazie per aver installato SimpleX Chat! Per connettersi via link (da condividere con il tuo contatto) Per iniziare una nuova chat Fotocamera - Puoi connetterti con gli sviluppatori di SimpleX Chat per porre domande e ricevere aggiornamenti. + connetterti con gli sviluppatori di SimpleX Chat per porre domande e ricevere aggiornamenti.]]> Link non valido! Codice QR non valido immagine di anteprima link @@ -564,9 +564,9 @@ Questo codice QR non è un link! Riattiva notifiche vuole connettersi con te! - Logo di SimpleX - Indirizzo di SimpleX - Squadra di SimpleX + Logo di SimpleX + Indirizzo di SimpleX + Squadra di SimpleX Hai accettato la connessione Hai invitato il contatto Il tuo profilo di chat verrà inviato @@ -605,13 +605,13 @@ Per verificare la crittografia end-to-end con il tuo contatto, confrontate (o scansionate) il codice sui vostri dispositivi. Usa per connessioni nuove Usa il server - Puoi anche connetterti cliccando il link. Se si apre nel browser, clicca il pulsante Apri nell\'app mobile. + Apri nell\'app mobile.]]> Il tuo profilo di chat verrà inviato al tuo contatto Il tuo server L\'indirizzo del tuo server Il tuo indirizzo SimpleX Se confermi, i server di messaggistica saranno in grado di vedere il tuo indirizzo IP e il tuo fornitore, a quali server ti stai connettendo. - Installa SimpleX Chat per terminale + Installa SimpleX Chat per terminale Assicurati che gli indirizzi dei server WebRTC ICE siano nel formato corretto, uno per riga e non doppi. Rete e server Impostazioni di rete @@ -632,12 +632,12 @@ Usare una connessione internet diretta\? Usa gli host .onion Usare il proxy SOCKS\? - Usare i server di SimpleX Chat\? - Stai usando i server di SimpleX Chat. + Usare i server di SimpleX Chat\? + Stai usando i server di SimpleX Chat. Quando disponibili I tuoi server ICE I tuoi server SMP - corsivo + corsivo chiamata persa risposta ricevuta… conferma ricevuta… @@ -646,9 +646,9 @@ Salva e avvisa i contatti Salva e avvisa i membri del gruppo Salvare le preferenze\? - segreto + segreto avvio… - barrato + barrato La piattaforma di messaggistica che protegge la tua privacy e sicurezza. Il profilo è condiviso solo con i tuoi contatti. in attesa di risposta… @@ -658,7 +658,7 @@ Sei tu a controllare la tua chat! Il tuo profilo attuale Il tuo profilo, i contatti e i messaggi recapitati sono memorizzati sul tuo dispositivo. - Il tuo profilo è memorizzato sul tuo dispositivo e condiviso solo con i tuoi contatti. I server di SimpleX non possono vedere il tuo profilo. + Il tuo profilo è memorizzato sul tuo dispositivo e condiviso solo con i tuoi contatti. I server di SimpleX non possono vedere il tuo profilo. Ignora Immune a spam e abusi Chiamata in arrivo @@ -666,26 +666,26 @@ Istantaneo Può essere cambiato in seguito via impostazioni. Crea una connessione privata - Molte persone hanno chiesto: se SimpleX non ha identificatori utente, come può recapitare i messaggi\? - Solo i dispositivi client memorizzano i profili utente, i contatti, i gruppi e i messaggi inviati con crittografia end-to-end a 2 livelli. + se SimpleX non ha identificatori utente, come può recapitare i messaggi\?]]> + crittografia end-to-end a 2 livelli.]]> Protocollo e codice open source: chiunque può gestire i server. Incolla il link ricevuto Le persone possono connettersi a te solo tramite i link che condividi. Periodico Privacy ridefinita Notifiche private - Maggiori informazioni nel nostro repository GitHub. + repository GitHub.]]> Maggiori informazioni nel nostro repository GitHub. Rifiuta La prima piattaforma senza alcun identificatore utente – privata by design. La nuova generazione di messaggistica privata - Per proteggere la privacy, invece degli ID utente usati da tutte le altre piattaforme, SimpleX dispone di identificatori per le code dei messaggi, separati per ciascuno dei tuoi contatti. + Per proteggere la privacy, invece degli ID utente usati da tutte le altre piattaforme, SimpleX dispone di identificatori per le code dei messaggi, separati per ciascuno dei tuoi contatti. Usa la chat videochiamata videochiamata (non crittografata e2e) Quando l\'app è in esecuzione - %1$s vuole connettersi con te via - Puoi controllare attraverso quale/i server ricevere i messaggi, i tuoi contatti – i server che usi per inviare loro i messaggi. + %1$s vuole connettersi con te via + ricevere i messaggi, i tuoi contatti – i server che usi per inviare loro i messaggi.]]> Può accadere quando: \n1. I messaggi sono scaduti sul client mittente dopo 2 giorni o sul server dopo 30 giorni. \n2. La decifrazione del messaggio è fallita, perché tu o il tuo contatto avete usato un backup del database vecchio. @@ -694,7 +694,7 @@ Chiamata persa nessuna crittografia e2e Apri - Apri SimpleX Chat per accettare la chiamata + Apri SimpleX Chat per accettare la chiamata peer-to-peer Chiamata in sospeso Privacy e sicurezza @@ -709,7 +709,7 @@ Server WebRTC ICE Il server relay protegge il tuo indirizzo IP, ma può osservare la durata della chiamata. Il server relay viene usato solo se necessario. Un altro utente può osservare il tuo indirizzo IP. - %1$d messaggio/i saltato/i + %1$d messaggio/i saltato/i Le tue chiamate I tuoi server ICE La tua privacy @@ -738,7 +738,7 @@ Il tuo attuale database di chat verrà ELIMINATO e SOSTITUITO con quello importato. \nQuesta azione non può essere annullata: il tuo profilo, i contatti, i messaggi e i file andranno persi in modo irreversibile. Invito scaduto! - invito al gruppo %1$s + invito al gruppo %1$s Invita membri Entra Entrare nel gruppo\? @@ -763,18 +763,18 @@ Password del database sbagliata Password sbagliata! Sei stato/a invitato/a al gruppo. Entra per connetterti con i suoi membri. - Puoi avviare la chat tramite Impostazioni -> Database o riavviando l\'app. + Puoi avviare la chat tramite Impostazioni -> Database o riavviando l\'app. Sei entrato/a in questo gruppo. Connessione al membro del gruppo invitante. Non riceverai più messaggi da questo gruppo. La cronologia della chat verrà conservata. ha invitato invitato via link del tuo gruppo - invitato %1$s + invitato %1$s uscito/a è uscito/a membro proprietario ha rimosso - rimosso %1$s + rimosso %1$s sei stato/a rimosso/a Tocca per entrare Toccare per entrare in incognito @@ -788,7 +788,7 @@ Sei entrato/a in questo gruppo sei uscito/a Hai rifiutato l\'invito al gruppo - hai rimosso %1$s + hai rimosso %1$s Stai usando un profilo in incognito per questo gruppo: per impedire la condivisione del tuo profilo principale non è consentito invitare contatti Hai inviato un invito al gruppo Invita membri @@ -809,14 +809,14 @@ Salta l\'invito di membri Cambia %d contatto/i selezionato/i - %1$s MEMBRI + %1$s MEMBRI Puoi condividere un link o un codice QR: chiunque potrà unirsi al gruppo. Non perderai i membri del gruppo se in seguito lo elimini. Stai tentando di invitare un contatto con cui hai condiviso un profilo in incognito nel gruppo in cui stai usando il tuo profilo principale - tu: %1$s + tu: %1$s Incognito La modalità in incognito non è supportata qui: il tuo profilo principale verrà inviato ai membri del gruppo La modalità in incognito protegge la privacy del nome e dell\'immagine del tuo profilo principale: per ogni nuovo contatto viene creato un nuovo profilo casuale. - indiretta (%1$s) + indiretta (%1$s) Permette di avere molte connessioni anonime senza dati condivisi tra di loro in un unico profilo di chat. Chiaro Stato della rete @@ -919,7 +919,7 @@ I server per le nuove connessioni del profilo di chat attuale Aggiungi profilo Eliminare il profilo di chat\? - Verrà usata una connessione TCP separata (e le credenziali SOCKS) per ogni profilo di chat presente nell\'app. + per ogni profilo di chat presente nell\'app.]]> Elimina tutti i file Solo dati del profilo locale Messaggi @@ -1056,7 +1056,7 @@ Host Porta porta %d - Imposta Usa gli host .onion su No se il proxy SOCKS non li supporta. + Usa gli host .onion su No se il proxy SOCKS non li supporta.]]> Elimina file Errore nel caricamento dei server SMP Assicurati che gli indirizzi del server XFTP siano nel formato corretto, uno per riga e non doppi. @@ -1091,13 +1091,13 @@ Nuovo codice di accesso Modalità di blocco Errore di decifrazione - %1$d messaggi saltati. + %1$d messaggi saltati. ID del messaggio errato Può accadere quando tu o il tuo contatto avete usato il backup del database vecchio. L\'ID del messaggio successivo non è corretto (inferiore o uguale al precedente). \nPuò accadere a causa di qualche bug o quando la connessione è compromessa. L\'errore è permanente per questa connessione, riconnettiti. - %1$d messaggi non decifrati. + %1$d messaggi non decifrati. Hash del messaggio errato L\'hash del messaggio precedente è diverso. Si prega di segnalarlo agli sviluppatori. @@ -1178,7 +1178,7 @@ Se non potete incontrarvi di persona, mostra il codice QR in una videochiamata o condividi il link. Parliamo in SimpleX Chat L\'aggiornamento del profilo verrà inviato ai tuoi contatti. - Maggiori informazioni nella Guida per l\'utente. + Guida per l\'utente.]]> Menu e avvisi Smettere di condividere l\'indirizzo\? Salvare le impostazioni\? @@ -1229,6 +1229,7 @@ Messaggio a tempo Errore caricamento dettagli Informazioni + Cerca Cronologia Messaggio ricevuto Messaggio inviato @@ -1267,4 +1268,17 @@ Le notifiche smetteranno di funzionare fino a quando non riavvierai l\'app Spegni Spegnere\? + Interrompi + Consenti l\'invio di file e contenuti multimediali. + Interrompi il cambio di indirizzo + Interrompere il cambio di indirizzo\? + Errore nell\'interruzione del cambio di indirizzo + Solo i proprietari del gruppo possono attivare file e contenuti multimediali. + File e multimediali + I membri del gruppo possono inviare file e contenuti multimediali. + Proibisci l\'invio di file e contenuti multimediali. + Il cambio di indirizzo verrà interrotto. Verrà usato il vecchio indirizzo di ricezione. + File e contenuti multimediali sono vietati in questo gruppo. + File e contenuti multimediali vietati! + Off \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-iw/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-iw/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml index ca8df0dfab..a9f4d8e190 100644 --- a/apps/multiplatform/android/src/main/res/values-iw/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/iw/strings.xml @@ -1,9 +1,9 @@ - + הדגשה אשר לאשר בקשת חיבור\? - אודות SimpleX Chat + אודות SimpleX Chat אודות SimpleX ענה שבוע @@ -61,7 +61,7 @@ גרסת האפליקציה פרופיל אקראי יישלח לאיש הקשר פרופיל אקראי יישלח לאיש הקשר שממנו קיבלת קישור זה - חיבור TCP נפרד (ואישור SOCKS) ייווצר לכל פרופיל צ׳אט שיש ברשותך באפליקציה. + לכל פרופיל צ׳אט שיש ברשותך באפליקציה.]]> חיבור TCP נפרד (ואישור SOCKS) ייווצר לכל איש קשר וחבר קבוצה. \nשימו לב: אם ברשותכם חיבורים רבים, צריכת הסוללה ותעבורת האינטרנט עשויה להיות גבוהה משמעותית וחלק מהחיבורים עלולים להיכשל. הנמען התבקש לקבל את הסרטון @@ -76,18 +76,18 @@ שיחות שמע/וידאו שיחות שמע ווידאו מיטוב הסוללה פעיל, מכבה את שירות הרקע ובקשות תקופתיות לקבלת הודעות חדשות. ניתן להפעיל אותם מחדש בהגדרות. - ניתן להשבית זאת בהגדרות – התראות עדיין יוצגו בזמן שהאפליקציה פועלת. + ניתן להשבית זאת בהגדרות – התראות עדיין יוצגו בזמן שהאפליקציה פועלת.]]> שירות רקע תמיד מופעל – התראות יוצגו מיד כאשר הודעות מגיעות. אימות אימות נכשל חזרה - מודגש + מודגש גיבוב הודעה שגוי מזהה הודעה שגוי גיבוב הודעה שגוי מזהה הודעה שגוי קבל אוטומטית תמונות - שימו לב: לא ניתן יהיה לשחזר או לשנות את הסיסמה אם תאבדו אותה. + שימו לב: לא ניתן יהיה לשחזר או לשנות את הסיסמה אם תאבדו אותה.]]> " \nזמין מ־v5.1" גם אתם וגם איש הקשר יכולים לשלוח הודעות קוליות. @@ -95,9 +95,9 @@ אשר אוטומטית בקשות ליצירת קשר. אימות בוטל אימות לא זמין - הוסיפו איש קשר חדש: ליצירת קוד QR חד־פעמי עבור איש הקשר שלכם. - הטוב ביותר לסוללה. התראות יוצגו רק כאשר האפליקציה מופעלת (ללא שירות רקע). - טוב לסוללה. שירות הרקע ייבדוק הודעות כל 10 דקות. שיחות או הודעות דחופות עלולות להתפספס. + הוסיפו איש קשר חדש: ליצירת קוד QR חד־פעמי עבור איש הקשר שלכם.]]> + הטוב ביותר לסוללה. התראות יוצגו רק כאשר האפליקציה מופעלת (ללא שירות רקע).]]> + טוב לסוללה. שירות הרקע ייבדוק הודעות כל 10 דקות. שיחות או הודעות דחופות עלולות להתפספס.]]> גם אתם וגם איש הקשר יכולים למחוק באופן בלתי הפיך הודעות שנשלחו. גם אתם וגם איש הקשר יכולים לשלוח הודעות נעלמות. לא ניתן לקבל את הקובץ @@ -105,11 +105,11 @@ ביטול בטל הודעה חיה מצלמה - סירקו קוד QR: כדי להתחבר לאיש קשר המציג לכם קוד QR. + סירקו קוד QR: כדי להתחבר לאיש קשר המציג לכם קוד QR.]]> בטל תצוגה מקדימה של קישורים שגיאת שיחה שיחה מתמשכת - צורך יותר סוללה! שירות רקע תמיד מופעל – התראות יוצגו מיד כאשר הודעות מגיעות. + צורך יותר סוללה! שירות רקע תמיד מופעל – התראות יוצגו מיד כאשר הודעות מגיעות.]]> השיחה כבר הסתיימה! שיחות במסך הנעילה: השיחה הסתיימה @@ -120,7 +120,7 @@ בוטל %s לפי פרופיל צ׳אט (ברירת מחדל) או לפי חיבור (בביטא). מתקשר… - השיחה הסתיימה %1$s + השיחה הסתיימה %1$s בטל תצוגה מקדימה של קבצים להתחבר באמצעות קישור ליצירת קשר\? התחבר @@ -156,7 +156,7 @@ פרופיל צ׳אט חיבור אימות סיסמה - צבעוני + צבעוני מתחבר לשיחה… מחובר/ת מתחבר… @@ -201,7 +201,7 @@ אימות סיסמה חדשה… מחובר חיבור נוצר - חיבור %1$d + חיבור %1$d להתחבר באמצעות קישור הזמנה\? איש הקשר כבר קיים איש הקשר וכל ההודעות יימחקו – לא ניתן לבטל זאת! @@ -228,7 +228,7 @@ צור צור פרופיל יצירת הפרופיל שלך - נוצר ב־%1$s + נוצר ב־%1$s צור קישור קבוצה צור קישור יוצר הקבוצה @@ -305,7 +305,7 @@ הוסיפו את הכתובת לפרופיל שלכם, כך שאנשי קשר יוכלו לשתף אותה עם אנשים אחרים. עדכון הפרופיל יישלח לאנשי הקשר. הדגשה נוספת כתובת - גודל הקובץ המרבי הנתמך כרגע הוא %1$s + גודל הקובץ המרבי הנתמך כרגע הוא %1$s התאמה אישית מצב כהה מזהה מסד נתונים @@ -323,7 +323,7 @@ מחק לכולם מחק קבוצה למחוק קבוצה\? - 💻 שולחן עבודה: סירקו את קוד ה־QR המוצג באפליקציה, באמצעות סריקת קוד QR. + סריקת קוד QR.]]> מכשיר נעילת המכשיר מושבתת. מכבה נעילת SimpleX. נעילת המכשיר אינה מופעלת. ניתן להפעיל את נעילת SimpleX, לאחר שתפעילו את נעילת המכשיר. @@ -466,7 +466,7 @@ הקובץ יימחק מהשרתים. הפוך מצלמה עזרה - אם לא ניתן להיפגש פנים אל פנים, הציגו את קוד ה־QR בשיחת וידאו, או שתפו את הקישור. + הציגו את קוד ה־QR בשיחת וידאו, או שתפו את הקישור.]]> איך איך להשתמש בשרתים שלך שרתי ICE (אחד בכל שורה) @@ -486,7 +486,7 @@ מוסתר הסתר איש קשר והודעה הסתר - אם לא ניתן להיפגש פנים אל פנים, ניתן לסרוק את קוד ה־QR בשיחת וידאו, או שאיש הקשר שלך ישתף קישור הזמנה. + לסרוק את קוד ה־QR בשיחת וידאו, או שאיש הקשר שלך ישתף קישור הזמנה.]]> אם לא ניתן להיפגש פנים אל פנים, הציגו את קוד ה־QR בשיחת וידאו, או שתפו את הקישור. איך להשתמש בזה היי! @@ -495,7 +495,7 @@ הסתר פרופיל איך להשתמש במרקדאון איך זה עובד - איך SimpleX עובדת + איך SimpleX עובדת נתק עזרה הקבוצה תימחק עבור כל חברי הקבוצה – לא ניתן לבטל זאת! @@ -510,7 +510,7 @@ אם תבחרו לדחות השולח לא יקבל התראה על כך. אם תאשרו, שרתי העברת ההודעות יוכלו לראות את ה־IP שלכם, וספק האינטרנט שלכם – את השרתים אליהם אתם מחוברים. תמונה - אם קיבלתם קישור הזמנה ל־SimpleX Chat, תוכלו לפתוח אותו בדפדפן. + אם קיבלתם קישור הזמנה ל־SimpleX Chat, תוכלו לפתוח אותו בדפדפן. אם תזינו את קוד הגישה להשמדה עצמית בעת פתיחת האפליקציה: אם תזינו קוד גישה זה בעת פתיחת האפליקציה, כל נתוני האפליקציה יימחקו באופן בלתי הפיך! תמונה נשמרה בגלריה @@ -535,20 +535,20 @@ זהות נסתרת באמצעות קישור קבוצה זהות נסתרת באמצעות קישור חד־פעמי קישור חיבור לא תקין - על מנת להשתמש בזה, אנא השביתו מיטוב סוללה עבור SimpleX בתיבת הדו־שיח הבאה. אחרת, ההתראות יושבתו. + השביתו מיטוב סוללה עבור SimpleX בתיבת הדו־שיח הבאה. אחרת, ההתראות יושבתו.]]> התראות מיידיות מושבתות! הזמן חברי קבוצה הוזמן - עקיף (%1$s) + עקיף (%1$s) מצב זהות נסתרת מגן על התמונה והפרטיות של שם הפרופיל הראשי שלך – עבור כל איש קשר חדש נוצר פרופיל חדש אקראי. גרסת מסד נתונים לא תואמת אישור העברת נתונים לא תקין מחיקה בלתי הפיכה של הודעות ממשק איטלקית כתובת שרת לא תקינה! - התקנת SimpleX Chat עבור מסוף הפקודה + התקנת SimpleX Chat עבור מסוף הפקודה הזמן חברים - נטוי + נטוי צ׳אט לא תקין נתונים לא תקינים פורמט הודעה לא תקין @@ -562,9 +562,9 @@ שיחת שמע נכנסת שיחת וידאו נכנסת קוד גישה שגוי - הזמנה לקבוצה %1$s + הזמנה לקבוצה %1$s פג תוקף ההזמנה! - הוזמן %1$s + הוזמן %1$s הוזמן באמצעות קישור הקבוצה שלך תפקיד ראשוני הזמן לקבוצה @@ -600,7 +600,7 @@ למדו עוד עזרה במרקדאון בואו נדבר ב־Simplex Chat - אנשים רבים שאלו: אם ל־SimpleX אין מזהי משתמש, איך ניתן להעביר הודעות\? + אם ל־SimpleX אין מזהי משתמש, איך ניתן להעביר הודעות\?]]> שגיאת Keychain הצטרף עם זהות נסתרת לעזוב קבוצה\? @@ -673,7 +673,7 @@ חסימת הודעה ההודעה תימחק – לא ניתן לבטל זאת! ההודעה תסומן למחיקה. הנמענים יוכלו לחשוף הודעה זו. - 📱 נייד: הקישו פתח באפליקציה, ואז הקישו התחבר באפליקציה. + פתח באפליקציה, ואז הקישו התחבר באפליקציה.]]> (מאוחסן רק על ידי חברי הקבוצה) השתק עוד @@ -684,7 +684,7 @@ לא ייעשה שימוש במארחי Onion. לא ייעשה שימוש במארחי Onion. שיחה שלא נענתה - רק מכשירי לקוח מאחסנים פרופילי משתמש, אנשי קשר, קבוצות, והודעות שנשלחו עם הצפנה מקצה־לקצה דו־שכבתית. + הצפנה מקצה־לקצה דו־שכבתית.]]> ללא הצפנה מקצה־לקצה שיחה שלא נענתה קוד גישה חדש @@ -721,7 +721,7 @@ ההרשאה נדחתה! תמונת פרופיל עדכון הפרופיל יישלח לאנשי הקשר שלך. - פיתחו את Simplex Chat כדי לענות לשיחה. + פיתחו את Simplex Chat כדי לענות לשיחה. שמירת טיוטת ההודעה האחרונה, עם קבצים מצורפים. לאסור תגובות אמוג׳י להודעות. שמות קבצים פרטיים @@ -761,7 +761,7 @@ לאסור מחיקה בלתי הפיכה של הודעות. פותח מסד נתונים… פתיחת הקישור בדפדפן עלולה להפחית את פרטיות ואבטחת החיבור. קישורי SimpleX לא מהימנים יהיו אדומים. - אנא בידקו את חיבור האינטרנט שלכם עם %1$s ונסו שוב. + אנא בידקו את חיבור האינטרנט שלכם עם %1$s ונסו שוב. ייתכן שטביעת האצבע של התעודה בכתובת השרת שגויה פתיחת מסוף צ׳אט פתיחת פרופילי צ׳אט @@ -798,7 +798,7 @@ הסר מקבל באמצעות תום זמן הפרוטוקול - %1$s הוסר/ה + %1$s הוסר/ה הודעה שהתקבלה נמענים רואים הודעות תוך כדי הקלדתן. שימוש מופחת בסוללה @@ -807,10 +807,10 @@ קבלת הקובץ תופסק. הקלט הודעה קולית דחיה - קראו עוד במדריך למשתמש. + מדריך למשתמש.]]> דרגו את האפליקציה קראו עוד ב־GitHub repository שלנו. - קראו עוד ב־GitHub repository שלנו. + GitHub repository שלנו.]]> יבוצע שימוש בשרת ממסר רק במידת הצורך. גורם אחר יכול לצפות בכתובת ה־IP שלך. שרת ממסר מגן על כתובת ה־IP שלך, אך הוא יכול לראות את משך השיחה. שיחה נדחתה @@ -837,6 +837,7 @@ הגב היסטוריה מידע + חיפוש ההודעה תימחק עבור כל חברי הקבוצה. הודעה שהתקבלה נדרש @@ -886,7 +887,7 @@ סרוק קוד QR של שרת לשמור שרתים\? לשמור הגדרות\? - סודי + סודי שחזור שלח הודעה ישירה השולח ביטל את העברת הקובץ. @@ -935,7 +936,7 @@ השרת דורש הרשאה כדי להעלות, בידקו את הסיסמה הגדרת שם איש קשר שימוש במארחי ‪.onion‬ - הגדירו את שימוש במארחי ‪.onion‬ ללא אם פרוקסי SOCKS אינו תומך בהם. + שימוש במארחי ‪.onion‬ ללא אם פרוקסי SOCKS אינו תומך בהם.]]> הודעה שנשלחה הגדרת העדפות קבוצה הגדירו אותו במקום אימות מערכת. @@ -991,7 +992,7 @@ נעילת SimpleX לא מופעלת! עצירת צ׳אט לעצור קבלת קובץ\? - להחליף כתובת מקבלת\? + לשנות כתובת קבלה\? כתובת SimpleX שרתי SMP שתף עם אנשי קשר @@ -1012,7 +1013,7 @@ כמה שגיאות לא קטלניות התרחשו במהלך הייבוא – ניתן לראות את מסוף הצ׳אט לקבלת פרטים נוספים. %s שניות החלף - החלף כתובת קבלה + שנה כתובת קבלה בזכות המשתמשים – תרמו באמצעות Weblate! בזכות המשתמשים – תרמו באמצעות Weblate! בזכות המשתמשים – תרמו באמצעות Weblate! @@ -1037,7 +1038,7 @@ מסד הנתונים אינו פועל כראוי. הקישו למידע נוסף טקסט זה זמין בהגדרות יותר מדי תמונות! - תודה שהתקנתם את SimpleX Chat! + תודה שהתקנתם את SimpleX Chat! קישור זה אינו קישור חיבור תקין! צבעי ערכת נושא שגיאה זו קבועה עבור חיבור זה, אנא התחברו מחדש. @@ -1067,8 +1068,8 @@ נדרש לפחות פרופיל משתמש אחד. נדרש לפחות פרופיל משתמש אחד גלוי. הקבוצה מבוזרת לחלוטין - היא גלויה רק לחברי הקבוצה. - כדי לשמור על הפרטיות, במקום מזהי משתמש הקיימים בכל הפלטפורמות האחרות, ל־SimpleX יש מזהים לתורי הודעות, נפרדים עבור כל אחד מאנשי הקשר שלך. - משתמש בשרתי SimpleX Chatז + כדי לשמור על הפרטיות, במקום מזהי משתמש הקיימים בכל הפלטפורמות האחרות, ל־SimpleX יש מזהים לתורי הודעות, נפרדים עבור כל אחד מאנשי הקשר שלך. + משתמש בשרתי SimpleX Chatז מנסה להתחבר לשרת המשמש לקבלת הודעות מאיש קשר זה. אלא אם איש הקשר שלכם מחק את החיבור או שהקישור הזה כבר היה בשימוש, זה עשוי להיות באג - אנא דווחו על כך. \nכדי להתחבר, אנא בקשו מאיש הקשר שלכם ליצור קישור חיבור נוסף ובידקו שיש לכם חיבור יציב לרשת. @@ -1081,7 +1082,7 @@ שדרג ופתח צ׳אט כדי להגן על אזור הזמן, קובצי תמונה/קול משתמשים ב־UTC. העלה קובץ - כדי לשמור על פרטיותך, האפליקציה כוללת שירות רקע SimpleX – הוא משתמש בכמה אחוזים מהסוללה ביום. + שירות רקע SimpleX – הוא משתמש בכמה אחוזים מהסוללה ביום.]]> כדי לקבל התראות, יש להזין את סיסמת מסד הנתונים בטל נעילה שליחה לא מורשית @@ -1094,12 +1095,12 @@ כדי לאמת הצפנה מקצה־לקצה עם איש הקשר שלכם, יש להשוות (או לסרוק) את הקוד במכשירים שלכם. פרופילי צ׳אט לעדכן מצב בידוד תעבורה\? - מנסה להתחבר לשרת המשמש לקבלת הודעות מאיש קשר זה (שגיאה: %1$s). + מנסה להתחבר לשרת המשמש לקבלת הודעות מאיש קשר זה (שגיאה: %1$s). פורמט הודעה לא ידוע דרך הדפדפן בטל השתקה להשתמש בפרוקסי SOCKS\? - להשתמש בשרתי SimpleX Chat\? + להשתמש בשרתי SimpleX Chat\? להשתמש בחיבור ישיר לאינטרנט\? כדי לחשוף את הפרופיל המוסתר שלכם, הזינו סיסמה מלאה בשדה חיפוש בדף פרופילי צ׳אט. שימוש בצ׳אט @@ -1117,16 +1118,16 @@ ממתין לאישור… ממתין למענה… איננו מאחסנים אף אחד מאנשי הקשר או ההודעות שלך (לאחר המסירה) בשרתים. - SimpleX + SimpleX אתם באמצעות קישור לכתובת איש קשר באמצעות קישור לקבוצה באמצעות קישור חד־פעמי כבר יש לך פרופיל צ׳אט עם אותו שם תצוגה. יש לבחור שם אחר. - הודעה קולית (%1$s) + הודעה קולית (%1$s) רוצה שתתחברו! - כתובת SimpleX - צוות SimpleX + כתובת SimpleX + צוות SimpleX שיחת וידאו (לא מוצפנת מקצה־לקצה) השיחות שלך אתם @@ -1140,11 +1141,11 @@ אזהרה: אתם עלולים לאבד נתונים מסוימים! באפשרותך להתחיל את הצ׳אט באמצעות הגדרות האפליקציה / מסד נתונים או על ידי הפעלה מחדש של האפליקציה. אתם מאפשרים - אתם כבר מחוברים ל־%1$s. - שירות SimpleX Chat + אתם כבר מחוברים ל־%1$s. + שירות SimpleX Chat לא ניתן היה לאמת אתכם; אנא נסו שוב. ברוכים הבאים! - ברוכ/ה הבא/ה %1$s! + ברוכ/ה הבא/ה %1$s! הוזמנת לקבוצה ממתין לתמונה ממתין לתמונה @@ -1156,26 +1157,26 @@ הודעה קולית… עליכם לאפשר לאיש הקשר שלכם לשלוח הודעות קוליות כדי שתוכלו לשלוח אותן. סרטון - באפשרותך להתחבר למפתחי SimpleX Chat כדי לשאול כל שאלה ולקבל עדכונים. - אתם קובעים דרך אילו שרתים לקבל את ההודעות, אנשי הקשר שלכם – השרתים דרכם אתם שולחים להם הודעות. + להתחבר למפתחי SimpleX Chat כדי לשאול כל שאלה ולקבל עדכונים.]]> + לקבל את ההודעות, אנשי הקשר שלכם – השרתים דרכם אתם שולחים להם הודעות.]]> שרתי WebRTC ICE - %1$d הודעות שדולגו + %1$d הודעות שדולגו שבועות הינך צופה אין באפשרותך לשלוח הודעות! סרטון נשלח הודעה קולית אישרת את החיבור - סמל SimpleX + סמל SimpleX שרתי XFTP - %1$d הודעות דולגו. + %1$d הודעות דולגו. סיסמת מסד נתונים שגויה הוזמנת לקבוצה הצטרפת לקבוצה זו אתם יכולים לשתף קישור או קוד QR – כל אחד יוכל להצטרף לקבוצה. לא תאבדו חברי קבוצה אם תמחקו אותו מאוחר יותר. כאשר אתם משתפים פרופיל זהות נסתרת עם מישהו, פרופיל זה ישמש עבור הקבוצות שהוא מזמין אתכם אליהן. כן - דרך %1$s + דרך %1$s אתם מחוברים לשרת המשמש לקבלת הודעות מאיש קשר זה. באפשרותך להפעיל את SimpleX Lock דרך ההגדרות. אין לך צ׳אטים @@ -1185,23 +1186,23 @@ הזמנת את איש הקשר שלך באפשרותכם לשתף את הכתובת שלכם כקישור או כקוד QR – כל אחד יכול להתחבר אליכם. כאשר אנשים מבקשים להתחבר, באפשרותך לקבל או לדחות זאת. - באפשרותכם גם להתחבר על־ידי לחיצה על הקישור. אם הוא נפתח בדפדפן, ליחצו על הכפתור פתח באפליקציה. + פתח באפליקציה.]]> כשזמין תוכלו ליצור אותה מאוחר יותר אתם שולטים בצ׳אט שלכם! באפשרותך להשתמש במרקדאון כדי לעצב הודעות: כאשר האפליקציה פועלת - %1$s רוצה שתתחברו דרך + %1$s רוצה שתתחברו דרך שיחת וידאו דרך ממסר וידאו כבוי וידאו פעיל - %1$d הודעות לא הצליחו לעבור פענוח. + %1$d הודעות לא הצליחו לעבור פענוח. עליכם להשתמש בגרסה העדכנית ביותר של מסד הנתונים שלכם במכשיר אחד בלבד, אחרת אתם עלולים להפסיק לקבל הודעות מאנשי קשר מסוימים. סיסמה שגויה! הוזמנתם לקבוצה. הצטרפו כדי ליצור קשר עם חברי הקבוצה. שינית תפקיד של %s ל%s - %1$s חברי קבוצה + %1$s חברי קבוצה באפשרותך לשתף כתובת זו עם אנשי הקשר שלך כדי לאפשר להם להתחבר עם %s. הודעות קוליות אסורות בצ׳אט זה. הודעות קוליות אסורות בקבוצה זו. @@ -1217,7 +1218,7 @@ מסד הנתונים שלך אינו מוצפן – יש להגדיר סיסמה כדי להגן עליו. אנשי הקשר שלך יכולים לאפשר מחיקת הודעות מלאה. הצ׳אטים - איש הקשר שלך שלח קובץ גדול יותר מהגודל המרבי הנתמך כעת (%1$s). + איש הקשר שלך שלח קובץ גדול יותר מהגודל המרבי הנתמך כעת (%1$s). איש הקשר שלך צריך להיות מקוון כדי שהחיבור יושלם. \nניתן לבטל חיבור זה ולהסיר את איש הקשר (ולנסות מאוחר יותר עם קישור חדש). פרופיל הצ׳אט שלך יישלח @@ -1238,7 +1239,7 @@ שיתפת קישור חד־פעמי לזהות נסתרת הפעלת נעילה הפרופיל האקראי שלך - הסרת את %1$s + הסרת את %1$s הינך משתמשת בפרופיל זהות נסתרת עבור קבוצה זו – כדי למנוע שיתוף הפרופיל הראשי שלך הזמנת אנשי קשר הינה אסורה שרתי ה־ICE שלך הפרטיות שלך @@ -1255,11 +1256,30 @@ כתובת SimpleX שלך שרתי SMP שלך הפרופיל שלך מאוחסן במכשירך ומשותף רק עם אנשי הקשר שלך. -\nשרתי SimpleX אינם יכולים לראות את הפרופיל שלך. +\nשרתי SimpleX אינם יכולים לראות את הפרופיל שלך. הפרופיל, אנשי הקשר וההודעות שנמסרו מאוחסנים במכשיר שלך. אתם תפסיקו לקבל הודעות מקבוצה זו. היסטוריית הצ׳אט תישמר. הינך מנסה להזמין איש קשר איתו שיתפת פרופיל זהות נסתרת לקבוצה בה ישנו שימוש בפרופיל הראשי שלך - את/ה: %1$s + את/ה: %1$s ההעדפות שלך עדיין תקבלו שיחות והתראות מפרופילים מושתקים כאשר הם פעילים. + בטל + בטל שינוי כתובת\? + שינוי הכתובת יבוטל. ייעשה שימוש בכתובת הקבלה הישנה. + ההתראות יפסיקו לפעול עד שתפעיל את האפליקציה מחדש + בטל שינוי כתובת + שגיאה בביטול שינוי הכתובת + כיבוי + אפליקציה + אפשר לשלוח קבצים ומדיה. + מועדף + קבצים ומדיה + אין צ\'אטים מסוננים + לכבות\? + קבצים ומדיה אסורים! + קבצים ומדיה אסורים בקבוצה זו. + חברי הקבוצה יכולים לשלוח קבצים ומדיה. + איתחול + שנוא + כבוי \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-ja/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml similarity index 93% rename from apps/multiplatform/android/src/main/res/values-ja/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml index 38ae6fe4a2..48dc894f1f 100644 --- a/apps/multiplatform/android/src/main/res/values-ja/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ja/strings.xml @@ -1,5 +1,5 @@ - + 1日 1週間 受けた通話 @@ -10,7 +10,7 @@ 1ヶ月 SimpleXについて a + b - SimpleX Chatについて + SimpleX Chatについて アクセントカラー 承諾 接続リクエストを承認しますか? @@ -26,7 +26,7 @@ 全チャットとメッセージが削除されます(※元に戻せません※)! 送信相手からの音声メッセージを許可する。 あなたと連絡相手が音声メッセージを送信できます。 - 電池省エネに良い:バックグラウンド機能で10分毎に新着メッセージを確認します。通話と緊急メッセージを見逃す可能性があります。 + 電池省エネに良い:バックグラウンド機能で10分毎に新着メッセージを確認します。通話と緊急メッセージを見逃す可能性があります。]]> 音声オフ 添付する アプリ・ビルド番号: %s @@ -40,13 +40,13 @@ 見た目 アプリのバージョン アプリのバージョン: v%s - アプリ内の各チャットプロフィールに、.連絡先毎にそれぞれのTCP接続(とSOCKS資格情報)が使われます。 + アプリ内の各チャットプロフィールに、.連絡先毎にそれぞれのTCP接続(とSOCKS資格情報)が使われます。]]> 各連絡先とグループに、それぞれのTCP接続(とSOCKS資格情報)が使われます。 \n※注意※ 接続が多かったら、電池とデータの使用量が増えて、切断する可能性もあります。 - 太文字 + 太文字 音声通話 音声とビデオ通話 - ※注意※:喪失したら、パスフレーズの回復・変更ができません。 + ※注意※:喪失したら、パスフレーズの回復・変更ができません。]]> グループ全員の接続が継続します。 送信相手が消えるメッセージを送るのを許可する。 送信相手が永久メッセージ削除するのを許可する。 @@ -75,12 +75,12 @@ 認証不可能 画像を自動的に受信 バックグラウンド機能が常にオンで、メッセージが到着次第に通知が出ます。 - 新しい連絡先を追加:使い捨てのQRコードを発行 + 新しい連絡先を追加:使い捨てのQRコードを発行]]> 電池省エネをオンに、バックグラウンド機能と定期的な受信依頼をオフにします。設定メニューにて変更できます。 - 電池消費が最少:アプリがアクティブ時のみに通知が出ます(バックグラウンドサービス無し)。 - 設定メニューにてオフにできます。 アプリがアクティブ時に通知が出ます。 + 電池消費が最少:アプリがアクティブ時のみに通知が出ます(バックグラウンドサービス無し)。]]> + 設定メニューにてオフにできます。 アプリがアクティブ時に通知が出ます。]]> あなたと連絡相手が送信済みメッセージを永久削除できます。 - QRコードを読み込み:連絡相手のQRコードをスキャンすると繋がります。 + QRコードを読み込み:連絡相手のQRコードをスキャンすると繋がります。]]> チャットのアーカイブ チャットのアーカイブを削除しますか? シークレットモードで参加 @@ -160,14 +160,14 @@ 即時通知 SMPサーバのアドレスを正しく1行ずつに分けて、重複しないように、形式もご確認ください。 WebRTC ICEサーバのアドレスを正しく1行ずつに分けて、重複しないように、形式もご確認ください。 - よく聞かれるのは、 if SimpleX にユーザIDがなければ、メッセージをどうやって届けるのでしょうかと。 - SimpleX の仕様 + if SimpleX にユーザIDがなければ、メッセージをどうやって届けるのでしょうかと。]]> + SimpleX の仕様 通話中 - 電池消費がより高い!非アクティブ時でもバックグラウンドのサービスが常に稼働します(着信次第に通知がすぐに出ます)。 + 電池消費がより高い!非アクティブ時でもバックグラウンドのサービスが常に稼働します(着信次第に通知がすぐに出ます)。]]> 発信中 - 通話終了 %1$s + 通話終了 %1$s 通話が終了しました。 - 直接会えない時は、 ビデオ通話中にQRコードを見せてもらうか、招待リンクを送ってもらえば相手に繋がります。 + ビデオ通話中にQRコードを見せてもらうか、招待リンクを送ってもらえば相手に繋がります。]]> メンバーをグループから除名する (※元に戻せません※)! メッセージ送信エラー 通話をロック画面に表示 @@ -177,7 +177,7 @@ ファイル受信ができません。 連絡先を招待できません! 変更 - 直接会えない時は、 ビデオ通話にてQRコードを見せるか、招待リンクを送って、相手に繋がります。 + ビデオ通話にてQRコードを見せるか、招待リンクを送って、相手に繋がります。]]> あなたのアドレスを変えました。 アドレスを変更しています… チャットのデータベース @@ -192,7 +192,7 @@ 消す 連絡先がオンラインになったら受信されます。しばらくお待ちください。 連絡先とセキュリティコードを確認 - ターミナル版の SimpleX Chat をインストール + ターミナル版の SimpleX Chat をインストール サーバ設定の向上 プライバシーとセキュリティ強化 シークレットモード @@ -215,7 +215,7 @@ 接続エラー (AUTH) 接続タイムアウト 接続リクエストを送信しました! - 接続 %1$d + 接続 %1$d 連絡先リンク経由で繋がりますか? グループリンク経由で繋がりますか? 招待リンク経由で繋がりますか? @@ -230,7 +230,7 @@ オニオンのホストが使われません。 オニオンのホストが利用可能時に使われます。 画像を1回で最大10枚を送信できます。 - 2層エンドツーエンド暗号化で送信されたプロフィール、連絡先、グループ、メッセージは、クライント端末にしか保存されません。 + 2層エンドツーエンド暗号化で送信されたプロフィール、連絡先、グループ、メッセージは、クライント端末にしか保存されません。]]> グループ設定を変えられるのはグループのオーナーだけです。 音声メッセージを利用可能に設定できるのはグループのオーナーだけです。 プロフィールを作成する @@ -248,13 +248,13 @@ 削除 音声通話着信 連絡先を削除 - 通話を受けるには SimpleX Chat を開きます。 + 通話を受けるには SimpleX Chat を開きます。 削除完了 全チャットプロフィールのファイルを削除 全員分を削除 自分側で削除 画像を削除 - グループへの招待 %1$s + グループへの招待 %1$s 無効な繋がりリンク 無効なサーバアドレス 無効なメッセージのフォーマット @@ -273,7 +273,7 @@ 仮のプロフィール画像 QRコード リンクが正しいかどうかご確認ください。または、連絡相手にもう一度リンクをお求めください。 - %1$s との接続を確認し、もう一度お試しください。 + %1$s との接続を確認し、もう一度お試しください。 現在の正しい暗証フレーズを入力してください。 プレセットサーバ プレセットサーバのアドレス @@ -327,7 +327,7 @@ 保存せずに閉じる 表示の名前には空白が使用できません。 マークダウン (書式) の使い方 - イタリック文字 + イタリック文字 拒否した通話 通話エラー 通話中 @@ -339,7 +339,7 @@ 技術の説明 プライベートな接続をする プライベートな通知 - GitHubリポジトリで詳細をご確認ください。 + GitHubリポジトリで詳細をご確認ください。]]> GitHubリポジトリで詳細をご確認ください。 エンドツーエンド暗号化済みビデオ通話 無効にする @@ -379,7 +379,7 @@ データベース暗号化のパスフレーズが更新されます。 チャットを開くにはデータベース暗証フレーズが必要です。 ファイル: %s - 作成日時 %1$s + 作成日時 %1$s アーカイブを削除 参加 グループに参加しますか? @@ -480,7 +480,7 @@ 起動中アプリリストに出ないようにする。 ライブメッセージ 除名 - 除名されました: %1$s + 除名されました: %1$s 返信する 表示の名前が重複してます! プロフィール作成にエラー発生 @@ -489,7 +489,7 @@ サーバの待ち行列を作成する 待ち行列を削除 切断 - 利用するには次の画面にてSimpleXに対する 電気省電力の設定をオフ for SimpleX してください。そうしないと通知が無効になります。 + 電気省電力の設定をオフ for SimpleX してください。そうしないと通知が無効になります。]]> データベースを起動できません。 通知のプレビュー メッセージ受信中… @@ -505,7 +505,7 @@ 接続待ち… %s として参加 画像送信済み - 現在、ファイルサイズの最上限は %1$s + 現在、ファイルサイズの最上限は %1$s。 大型ファイル! ファイルが見つかりません 連絡先がオンラインになったら受信されます。しばらくお待ちください。 @@ -518,9 +518,9 @@ 使い捨てリンクを発行する シークレットグループを作成する (グループのメンバーのみに保存されてます) - 💻 デスクトップ: 「QRコードを読み取る」経由でアプリに表示されるQRコードを読み取る - SimpleX Chat の招待リンクをもらったら、ブラウザで開けます: - 📱 携帯: 「アプリで開く」をタップし、 アプリ内で「接続」をタップする。 + 「QRコードを読み取る」経由でアプリに表示されるQRコードを読み取る]]> + SimpleX Chat の招待リンクをもらったら、ブラウザで開けます: + 「アプリで開く」をタップし、 アプリ内で「接続」をタップする。]]> 拒否しても、相手には知らされません。 拒否 チャットを消しますか? @@ -543,7 +543,7 @@ 作成 表示の名前 フルネーム (任意): - 色付き + 色付き 応答 分散型 スパムや悪質送信を完全防止 @@ -590,7 +590,7 @@ プライベートなファイル名 電池使用量低減 メンバー除名にエラー発生 - 関節 (%1$s) + 関節 (%1$s) シークレットモード シークレットモードとは、メインのプロフィールとプロフィール画像を守るために、新しい連絡先を追加する時に、その連絡先に対してランダムなプロフィールが作成されるという対策です。 いいえ @@ -627,7 +627,7 @@ 脱退しました。 %s の役割を %s に変えました。 役割を %s に変えました。 - 招待された %1$s + 招待された %1$s アドレスを変更いたします: %s オーナー 接続待ち @@ -644,14 +644,14 @@ グループプロフィールを更新しました 脱退しました。 あなたのメインプロフィールで参加してるグループにシークレットモードのプロフィールで繋がってる連絡先を招待しようとしてます。 - あなた: %1$s + あなた: %1$s 役割 経由で送信 システム 連絡相手にシークレットモードのプロフィールを共有すると、その連絡相手に招待されたグループでも同じプロフィールが使われます。 テーマ 音声メッセージ - SimpleX + SimpleX このリンクのグループに参加し、そのメンバーに繋がります。 この連絡先から受信するメッセージのサーバに既に接続してます。 ファイル送信機能がまだ実装されてません @@ -663,7 +663,7 @@ チャットを閉じる 未読 送信失敗 - ようこそ %1$s + ようこそ %1$s! 音声メッセージ セキュリティコードを確認 ライブメッセージを送信 @@ -695,7 +695,7 @@ アプリが定期的に新しいメッセージを受信します。一日の電池使用量が約3%で、プッシュ通知に頼らずに、あなたの端末のデータをサーバに送ることはありません。 SimpleXロック 通知を受けるには、データベースの暗証フレーズを入力してください。 - SimpleX Chat サービス + SimpleX Chat サービス SimpleXロック:オン 起動時、または非アクティブ状態で30秒が経った後に戻ると、認証する必要となります。 共有する @@ -712,13 +712,13 @@ ライブメッセージを送信 (入力しながら宛先の画面で更新される) (連絡先に共有) (クリップボードから読み込むか、貼り付ける) - SimpleX Chatをご利用いただきありがとうございます! + SimpleX Chatをご利用いただきありがとうございます! カメラ 繋がりを承認しました 連絡先に招待を送りました 承認ずみの接続がキャンセルされます! あなたからリンクを受けた連絡先が接続できなくなります! - SimpleXアドレス + SimpleXアドレス QRコードを表示 このリンクは有効な接続リンクではありません! このQRコードはリンクではありません! @@ -758,11 +758,11 @@ あなたのプロフィール、連絡先、送信したメッセージがご自分の端末に保存されます。 プロフィールは連絡先にしか共有されません。 メッセージの書式をマークダウンで編集できます。 - シークレット - 取り消し線 + シークレット + 取り消し線 接続中… 次世代のプライバシー・メッセンジャー - あなたがメッセージの受信サーバを決められます。あなたの連絡先が同じく、自分に対する受信サーバを決められます。 + 受信サーバを決められます。あなたの連絡先が同じく、自分に対する受信サーバを決められます。]]> ビデオ通話 アプリが稼働中に WebRTC ICEサーバ @@ -793,7 +793,7 @@ %sの役割を次に変えました:%s ダイレクトメッセージを送信 %d 連絡先が選択中 - 除名しました: %1$s + 除名しました: %1$s 切り替える 役割が「%s」となります。グループの全員に通知が出ます。 サーバ @@ -826,16 +826,16 @@ メッセージを送る… ファイル共有… 音声メッセージ… - 音声メッセージ (%1$s) + 音声メッセージ (%1$s) メッセージを送信 設定 - SimpleX開発チーム + SimpleX開発チーム このストリングは接続リンクではありません! 質問やアイデアを送る GithubでStar - あなたのプロフィールはご自分の端末に保存され、あなたの連絡先のみに共有されます。 SimpleXのサーバには開示されません。 + あなたのプロフィールはご自分の端末に保存され、あなたの連絡先のみに共有されます。 SimpleXのサーバには開示されません。 あなたの通話 - %1$d飛ばしたメッセージ + %1$d飛ばしたメッセージ リンクのプレビューを送信 暗証フレーズを設定してからエキスポート チャットを閉じますか? @@ -864,28 +864,28 @@ 画像が解読できません。別のイメージで試すか、開発者に伝えてください。 画像待ち 画像待ち - 向こうが最上限の大きさを超えるファイルを送ろうとしました (%1$s)。 + 向こうが最上限の大きさを超えるファイルを送ろうとしました (%1$s)。 音声メッセージは使用禁止です! 新しいチャットを始める - SimpleX Chatの開発者と繋がれば、質問したり、速報を受けたりすることができます + SimpleX Chatの開発者と繋がれば、質問したり、速報を受けたりすることができます。]]> 新しいチャットを始めるには ボタンをタップ ミュート解除 連絡先を設定 はあなたと繋がりたいです! - リンクをクリックすることでも接続できます。ブラウザが起動すれば Open in mobile app (アプリで開く)ボタンをクリックしてください。 + Open in mobile app (アプリで開く)ボタンをクリックしてください。]]> あなたのチャットプロフィール サーバのQRコードを読み込む テストに失敗したサーバがあります: - SimpleX Chatサーバを使いますか? - SimpleX Chatを使っています。 + SimpleX Chatサーバを使いますか? + SimpleX Chatを使っています。 リンクを送る simplexmq: バージョン%s (%2s) 応答待ち… 確認待ち… 世界初のユーザーIDのないプラットフォーム|設計も元からプライベート チャット - %1$sは次の方法であなたと繋がりたいです: + %1$sは次の方法であなたと繋がりたいです: ビデオ通話 (非エンドツーエンド暗号化) 表示 スピーカーオン @@ -910,21 +910,21 @@ SIMPLEX CHATを支援 テストサーバ 開発中の機能です!相手のクライアントが4.2でなければ機能しません。アドレス変更が完了すると、会話にメッセージが出ます。連絡相手 (またはグループのメンバー) からメッセージを受信できないかをご確認ください。 - あなたのプライバシーを守るために、このアプリはプッシュ通知の変わりに SimpleX バックグラウンド・サービス を使ってます。一日の電池使用量は約3%です。 - あなたのプライバシーを守るために、他のアプリと違って、ユーザーIDの変わりに SimpleX メッセージ束毎にIDを配布し、各連絡先が別々と扱います。 + SimpleX バックグラウンド・サービス を使ってます。一日の電池使用量は約3%です。]]> + あなたのプライバシーを守るために、他のアプリと違って、ユーザーIDの変わりに SimpleX メッセージ束毎にIDを配布し、各連絡先が別々と扱います。 あなたのチャットプロフィールが他のグループメンバーに送られます。 エンドツーエンド暗号化を確認するには、ご自分の端末と連絡先の端末のコードを比べます (スキャンします)。 - このコンタクトから受信するメッセージのサーバに接続しようとしてます。(エラー: %1$s)。 + このコンタクトから受信するメッセージのサーバに接続しようとしてます。(エラー: %1$s)。 使用済みリンク、または連絡先による接続の削除ではなければ、バッグの可能性があります。開発者にお伝えください。 \n繋がるには、連絡先に新しくリンクを発行してもらって、電波が安定かどうかご確認ください。 接続を完了するには、連絡相手がオンラインになる必要があります。 \nこの接続をキャンセルして、連絡先を削除をすることもできます (後でやり直すこともできます)。 セキュリティコードを確認 - %1$s経由 - SimpleXロゴ + %1$s経由 + SimpleXロゴ 音声メッセージを送るには、連絡相手からの音声メッセージを許可しなければなりません。 あなたの最新データベースを1つの端末にしか使わなければ、一部の連絡先からメッセージが届きかねます。 - 既に繋がってます: %1$s + 既に繋がってます: %1$s シークレットモードのプロフィールでこのグループに参加しています。メインのプロフィールを守るために、招待することができません。 使い捨てリンクを送りました リンクを送ってくれた連絡先にあなたのプロフィールを送ります。 @@ -945,7 +945,7 @@ %sのアドレスを変えました 連絡先を選択 今はメンバーを招待しません - %1$sメンバー + %1$sメンバー XFTPサーバ ウェルカムメッセージを保存しますか? 次から表示しない @@ -970,7 +970,7 @@ ダークテーマ 画像 SimpleXアドレスについて - ユーザーガイドで詳細を見る + ユーザーガイドで詳細を見る]]> SimpleXアドレス ポート %d ウェルカムメッセージを入力…(オプション) @@ -1024,7 +1024,7 @@ あなたはオブザーバーです グループの管理者に連絡してください。 動画は相手がアップロードを完了した時点で受信するができます。 - SOCKSプロキシがサポートしていない場合、.onion hostを使用する、は「いいえ」に設定します。 + .onion hostを使用する、は「いいえ」に設定します。]]> SOCKSプロキシーを使用 チャットのプロフィールを開く 連絡先がアップロードを完了した時点で、ファイルを受信します。 @@ -1072,8 +1072,8 @@ 開発者に報告してください。 このエラーはこの接続では永続的なものです。再接続してください。 1GBまでのビデオとファイル - %1$d メッセージの復号化に失敗しました。 - %1$d メッセージをスキップしました + %1$d メッセージの復号化に失敗しました。 + %1$d メッセージをスキップしました SMP サーバーのロード中にエラーが発生しました ユーザーパスワード保存エラー XFTP サーバーのロード中にエラーが発生しました @@ -1211,6 +1211,7 @@ 詳細読み込みエラー 履歴 情報 + 検索 受信したメッセージ 送信済みメッセージ カスタム時間 @@ -1260,4 +1261,5 @@ ユーザーに感謝します – Weblate 経由で貢献してください! ついに、私たちはそれらを手に入れました! 🚀 より良いメッセージ + オフ \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-ko/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml similarity index 93% rename from apps/multiplatform/android/src/main/res/values-ko/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml index 18d7126357..03fd372a25 100644 --- a/apps/multiplatform/android/src/main/res/values-ko/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ko/strings.xml @@ -1,5 +1,5 @@ - + 연결됨 연결 중 그룹 링크를 통해 연결하시겠습니까\? @@ -27,7 +27,7 @@ 컨텍스트 아이콘 연결됨 뒤로 - 새 대화 상대 추가 : 대화를 위한 일회용 QR 코드 만들기 + 새 대화 상대 추가 : 대화를 위한 일회용 QR 코드 만들기]]> 취소 라이브 메시지 취소 파일 선택 @@ -58,9 +58,9 @@ 앱 버전 : v%s 코어 버전 : v%s 전화 응답 - 굵게 + 굵게 전화 연결 중 - 색깔 + 색깔 암호 확인 전화 연결 중… 생성 @@ -69,7 +69,7 @@ 연결됨 연결 중… 내 프로필 생성 - 배터리에 좋음. 백그라운드 서비스는 10분마다 메시지를 확인합니다. 전화나 긴급 메시지를 놓칠 수 있습니다. + 배터리에 좋음. 백그라운드 서비스는 10분마다 메시지를 확인합니다. 전화나 긴급 메시지를 놓칠 수 있습니다.]]> 통화가 이미 종료되었습니다! 항상 릴레이 사용 음성 통화 @@ -88,7 +88,7 @@ 채팅이 작동 중 채팅 채팅 데이터베이스를 가져옴 - 주의: 비밀구절(passphrase)을 분실하면 복구하거나 비밀번호 변경을 할 수 없어요. + 주의: 비밀구절(passphrase)을 분실하면 복구하거나 비밀번호 변경을 할 수 없어요.]]> 데이터베이스 암호구절(passphrase)을 바꾸시겠습니까\? 새로운 암호구절(passphrase) 확인… 채팅 기록 보관함 @@ -135,7 +135,7 @@ 일회용 초대 링크 생성 주소 생성 1일 - SimpleX Chat에 대하여 + SimpleX Chat에 대하여 강조 응답 연결 요청을 수락하시겠습니까\? @@ -162,7 +162,7 @@ 앱 데이터 백업 앱 아이콘 이 링크를 받은 사람한테 랜덤으로 만들어진 익명 프로필이 전송됩니다. - 별도로 분리된 TCP 연결(그리고 SOCKS 자격 증명)이 각각의 채팅 프로필에 사용될 겁니다. + 각각의 채팅 프로필에 사용될 겁니다.]]> 별도로 분리된 TCP 연결(및 SOCKS 자격 증명)이 각각의 대화 상대 및 그룹 구성원에게 사용될 겁니다. \n참고: 연결이 많은 경우 배터리 및 트래픽 소비가 높을 수 있고 일부 연결이 실패할 수 있습니다. 이미지 수신 요청됨 @@ -170,13 +170,13 @@ 음성 통화 (종단간 암호화 아님) 인증을 사용할 수 없음 배터리 최적화가 활성화되어, 백그라운드 서비스 및 새 메시지에 대한 주기적 요청이 꺼집니다. 설정을 통해 다시 활성화할 수 있습니다. - 배터리에 가장 좋음. 앱이 실행 중일 때만 알림을 받게 됩니다 (백그라운드에서 실행되지 않음). - 설정을 통해 비활성화할 수 있습니다. – 앱이 실행되는 동안 알림이 표시됩니다. + 배터리에 가장 좋음. 앱이 실행 중일 때만 알림을 받게 됩니다 (백그라운드에서 실행되지 않음).]]> + 설정을 통해 비활성화할 수 있습니다. – 앱이 실행되는 동안 알림이 표시됩니다.]]> 당신과 대화 상대 모두 사라지는 메시지를 보낼 수 있습니다. - QR 코드 스캔: QR 코드를 보여주는 사람과 대화할 수 있습니다. + QR 코드 스캔: QR 코드를 보여주는 사람과 대화할 수 있습니다.]]> 데이터베이스 암호를 저장하고 있는 Keystore에 접근할 수 없습니다. - 배터리 더욱 사용! 백그라운드 서비스가 항상 실행됩니다. - 메시지를 수신되는 즉시 알림이 표시됩니다. - 통화 종료됨 %1$s + 배터리 더욱 사용! 백그라운드 서비스가 항상 실행됩니다. - 메시지를 수신되는 즉시 알림이 표시됩니다.]]> + 통화 종료됨 %1$s 전화 중… 전화 연결 중 링크 미리보기 취소 @@ -198,12 +198,12 @@ 연결 연결 중 (도입) 연결 오류 - 연결 %1$d + 연결 %1$d 링크를 통해 연결하시겠습니까\? 대화 상대와 모든 메시지가 삭제됩니다. - 삭제 후 되돌릴 수 없습니다! 대화 상대와 종단간 암호화됨 대화 상대와 아직 연결되지 않았습니다! - %1$s에 생성 완료 + %1$s에 생성 완료 일회용 초대 링크 생성 비밀 그룹 생성 익명 수락 @@ -217,11 +217,11 @@ 메시지를 삭제할까요\? 나에게서만 삭제 멤버의 메시지를 삭제할까요\? - 현재 지원되는 최대 파일 크기는 %1$s 입니다. + 현재 지원되는 최대 파일 크기는 %1$s 입니다. 디코딩 오류 대화 상대 삭제 연락처를 삭제할까요\? - 💻 데스크톱: QR 코드 스캔을 통해 앱에서 표시된 QR 코드를 스캔해 주세요. + QR 코드 스캔을 통해 앱에서 표시된 QR 코드를 스캔해 주세요.]]> 삭제 삭제 대기 중인 연결을 삭제할까요\? @@ -317,7 +317,7 @@ 다른 이름, 아바타 그리고 전송 격리. 다시 보지 않기 이 대화 상대로부터의 메시지를 수신할 서버와 연결되었어요. - SimpleX + SimpleX 앱 업데이트 후 개발자에게 연락해 주세요. 대화 상대가 나갔거나 초대 링크가 이미 사용된 경우가 아니면 버그일 수 있어요. 이 경우 개발자에게 알려주세요. \n대화 상대에게 다른 초대 링크 만들도록 부탁하고 네트워크 연결이 안정적인지 확인하세요. @@ -344,7 +344,7 @@ 그룹 나가기 1:1 채팅 시작하기 서버 - 인다이렉트 (%1$s) + 인다이렉트 (%1$s) 허용함 꺼짐 켜짐 @@ -359,7 +359,7 @@ 릴레이를 경유 만료된 초대 링크에요! - %1$s님이 다음을 통해 연결하려고 해요 : + %1$s님이 다음을 통해 연결하려고 해요 : 설정에서 잠금 화면에서 바로 전화를 받을 수 있도록 설정할 수 있어요. 연결을 완료하려면 대화 상대가 온라인 상태여야 해요. \n연결 요청을 취소하고 대화 상대를 삭제할 수 있어요 (그리고 새 링크로 재시도). @@ -376,7 +376,7 @@ 사용 안 함 질문이나 아이디어 보내기 (스캔하거나 클립보드에서 붙여넣기) - 대화 상대가 현재 지원되는 최대 크기(%1$s)보다 큰 파일을 보냈습니다. + 대화 상대가 현재 지원되는 최대 크기(%1$s)보다 큰 파일을 보냈습니다. 초대를 받았어요. 프로필 생성 오류! 그룹 링크로 익명 채팅 @@ -491,7 +491,7 @@ 강퇴됨 역할 선택지 펼치기 파일 & 미디어 - 그룹으로 초대 %1$s + 그룹으로 초대 %1$s 그룹 링크 환영 메시지 보여지는 그룹 이름 @@ -506,19 +506,19 @@ 멤버 초대하기 비활성 그룹 관찰자 - 나 : %1$s - %1$s 멤버 + 나 : %1$s + %1$s 멤버 파일 저장됨 대화 상대가 업로드를 완료하면 파일이 저장되어요. 대화 상대가 온라인 상태일 때 파일이 전송되어요. 대화 상대가 온라인이 되기를 기다리거나 나중에 다시 확인해 주세요! 음성 메시지 녹화하기 갤러리에서 프로필 이미지 플레이스 홀더 - SimpleX 주소 + SimpleX 주소 설명서 내 서버 사용법 마크다운 사용법 - SimpleX 작동 방식 + SimpleX 작동 방식 그룹 초대가 만료되었어요. 그룹 멤버는 보낸 메시지를 영구 삭제할 수 있어요. 그룹 멤버는 음성 메시지를 보낼 수 있어요. @@ -552,7 +552,7 @@ 동시에 최대 10개까지만 이미지를 보낼 수 있어요. 이미지 수가 너무 많아요! 거절해도 상대에게 알림이 전송되지 않아요. - 직접 만날 수 없다면 영상 통화에서 QR 코드를 보여주거나 링크를 공유해 주세요. + 영상 통화에서 QR 코드를 보여주거나 링크를 공유해 주세요.]]> 영상 전화 영상 끄기 스피커 켜기 @@ -567,15 +567,15 @@ 하나의 프로필로 여러 사람과 연락할 필요 없이 무수히 많은 익명 프로필로 연락할 수 있어요. 스팸 및 남용에 면역 무시하기 - SimpleX Chat 초대 링크를 받으면 브라우저에서 참여할 수 있어요 : + SimpleX Chat 초대 링크를 받으면 브라우저에서 참여할 수 있어요 : 링크 미리보기 이미지 QR 코드 - SimpleX - 직접 만날 수 없다면 영상 통화에서 QR 코드를 스캔하거나 상대에게 초대 링크를 공유할 수 있어요. + SimpleX 팀 + 영상 통화에서 QR 코드를 스캔하거나 상대에게 초대 링크를 공유할 수 있어요.]]> 동영상 보내짐 동영상 수신 요청됨 동영상 기다리는 중 - SimpleX 로고 + SimpleX 로고 대화 상대가 온라인 상태일 때 이미지가 수신될 거예요. 기다리거나 나중에 확인하세요! 채팅 데이터베이스를 가져올까요\? 오류 @@ -584,7 +584,7 @@ 잘못된 메시지 형식 잘못된 연결 링크 알림 - %1$d 읽지 않은 메시지 + %1$d 읽지 않은 메시지 키체인 오류 그룹에 초대하기 로컬 네임 @@ -597,12 +597,12 @@ 그룹에 참여 중 익명 모드는 기본 프로필 이름과 사진과 같은 개인 정보를 보호해줘요. 새 대화 상대마다 새로운 랜덤 프로필이 만들어져요. %s 은(는) 인증되었어요. - 기울게 + 기울게 익명 프로필 사용 중 초대받은 그룹에 참여하면, 그 그룹에서도 동일한 익명 프로필이 사용되어요. 내 랜덤 프로필 음성 전화 옴 %s은(는) 인증되지 않았어요. - 터미널용 SimpleX Chat를 설치하세요 + 터미널용 SimpleX Chat를 설치하세요 영상 전화 옴 잘못된 마이그레이션 확인 익명 모드로 참여 @@ -613,7 +613,7 @@ %s에 의해 조정됨 라이브 조정됨 - %1$s 에서 네트워크 연결 상태를 확인한 후 다시 시도하세요. + %1$s 에서 네트워크 연결 상태를 확인한 후 다시 시도하세요. SimpleX 잠금 정보를 보호하려면 SimpleX 잠금을 켜세요. \n이 기능이 활성화하기 전에 인증을 완료하라는 메시지가 표시될 거예요. @@ -631,7 +631,7 @@ 모든 멤버에게서 메시지가 삭제될 거예요. 이 메시지는 모든 멤버에게 조정됨으로 표시될 거예요. 세부 정보 없음 - 📱 모바일: 모바일 앱에서 열기를 누른 다음 앱에서 연결을 누르세요. + 모바일 앱에서 열기를 누른 다음 앱에서 연결을 누르세요.]]> 확인됨으로 표시 네트워크 및 서버 새 데이터베이스 보관함 @@ -684,7 +684,7 @@ TCP 연결 유지 활성화 %s의 새로운 기능 마크다운 도움말 - 많은 사람들의 질문 : SimpleX에는 사용자 식별자가 없는데도 어떻게 메시지를 전달할 수 있어요\? + SimpleX에는 사용자 식별자가 없는데도 어떻게 메시지를 전달할 수 있어요\?]]> 그룹에서 나갈까요\? 데이터베이스 버전이 앱보다 최신이지만, 다음에 대한 다운 마이그레이션 없음: %s 멤버가 그룹에서 제거되어요. 이 작업은 되돌릴 수 없어요! @@ -706,7 +706,7 @@ 거절 비밀번호 표시 - 사용자 디바이스에만 2계층 종단 간 암호화 로 전송된 사용자 프로필, 연락처, 그룹 및 메시지를 저장되어요. + 2계층 종단 간 암호화 로 전송된 사용자 프로필, 연락처, 그룹 및 메시지를 저장되어요.]]> 자세한 내용은 GitHub에서 확인해 주세요. 개인 정보 및 보안 알림은 앱이 중지되기 전까지만 전달될 거예요! @@ -715,10 +715,10 @@ 음성 메시지 허용되지 않음. 사라지는 메시지 전송은 허용되지 않습니다. 이전 데이터베이스 기록 - %1$s 초대됨 + %1$s 초대됨 나감 강퇴됨 - %1$s 강퇴됨 + %1$s 강퇴됨 그룹 소유자만 그룹 설정을 변경할 수 있어요. 다음을 통해 수신 대화 상대만 사라지는 메시지를 보낼 수 있습니다. @@ -735,16 +735,16 @@ 프라이버시의 재정의 오픈 소스 프로토콜과 코드 - 누구나 자신만의 서버를 구축할 수 있어요. 앱이 실행 중일 때 - ㅍ자세한 내용은 \u0020GitHub 에서 확인해 주세요. + GitHub 에서 확인해 주세요.]]> 릴레이 서버는 IP 주소를 숨겨주지만, 통화 시간을 관찰 할 수 있어요. 그룹 링크로 초대 설정을 통해 나중에 변경할 수 있어요. 비공개 알림 거절 - SimpleX Chat을 열어 전화 받기 + SimpleX Chat을 열어 전화 받기 열기 앱 잠금 - %1$s님, 환영합니다! + %1$s님, 환영합니다! (그룹 구성원에게만 저장됨) 아래 칸에 받은 링크를 붙여넣기하여 대화 상대와 연결해 주세요. 앱 평가하기 @@ -802,7 +802,7 @@ 파일 만들기 파일 보내기는 아직 지원되지 않아요. - %1$s를 통해 + %1$s를 통해 SimpleX 연락처 주소 SimpleX 그룹 링크 SimpleX 일회용 초대 링크 @@ -816,7 +816,7 @@ 알림 미리보기 알림 서비스 메시지 받는 중… - SimpleX 채팅 서비스 + SimpleX 채팅 서비스 파일 공유… 이미지 공유… 메시지 공유… @@ -845,7 +845,7 @@ 서버 사용하기 새로운 대화에 사용 잘못된 서버 주소에요! - 비밀 + 비밀 종단 간 암호화 안 됨 테마 내 역할이 %s로 변경되었어요. @@ -876,7 +876,7 @@ 미리 설정된 서버 주소 내 서버 내 서버 주소 - %1$s을(를) 강퇴했어요. + %1$s을(를) 강퇴했어요. 채팅 데이터베이스를 내보내기, 가져오기 또는 삭제 하려면 채팅 기능을 중지해 주세요. 채팅 기능이 중지된 동안에는 메시지를 주고받을 수 없어요. 비밀번호를 모르면 변경하거나 찾을 수 없으므로 비밀번호를 안전하게 보관해 주세요. 제출하기 @@ -943,4 +943,6 @@ 잘못된 메시지 아이디 당신과 대화 상대 모두 전화를 걸 수 있습니다. 앱 패스코드 + 검색 + 꺼짐 \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-lt/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml similarity index 94% rename from apps/multiplatform/android/src/main/res/values-lt/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml index 083c517f72..52a866dddb 100644 --- a/apps/multiplatform/android/src/main/res/values-lt/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/lt/strings.xml @@ -1,8 +1,8 @@ - + 1 mėnuo 1 savaitė - Apie SimpleX Chat + Apie SimpleX Chat 1 diena a + b Apie SimpleX @@ -28,8 +28,8 @@ Leisti balso žinutes tik tuo atveju, jei jūsų adresatas jas leidžia. Leisti Leisti balso žinutes\? - pusjuodis - skambutis baigtas %1$s + pusjuodis + skambutis baigtas %1$s garso skambutis Garso ir vaizdo skambučiai bloga žinutės maiša @@ -44,7 +44,7 @@ Garso ir vaizdo skambučiai Leisti jūsų adresatams siųsti išnykstančias žinutes. Tapatybės nustatymas neprieinamas - Turėkite omenyje: jeigu prarasite slaptafrazę, NEBEGALĖSITE jos atkurti ar pakeisti. + Turėkite omenyje: jeigu prarasite slaptafrazę, NEBEGALĖSITE jos atkurti ar pakeisti.]]> Atsisakyti jungiamasi… Prisijungti @@ -108,7 +108,7 @@ Atsakyti Ištrinti žinutę\? Failas - Šiuo metu didžiausias palaikomas failo dydis yra %1$s. + Šiuo metu didžiausias palaikomas failo dydis yra %1$s. Failas nerastas Failas įrašytas Atsijungta @@ -186,7 +186,7 @@ Duomenų bazės ID Klaida keičiant vaidmenį tiesioginis - netiesioginis (%1$s) + netiesioginis (%1$s) Sukurti slaptą grupę Klaida įrašant grupės profilį Daugiau neberodyti @@ -221,7 +221,7 @@ Ištrinti nuorodą Ištrinti nuorodą\? Klaida kuriant grupės nuorodą - Kaip SimpleX veikia + Kaip SimpleX veikia Duomenų bazė šifruota! kūrėjas Ištrinti grupę\? @@ -265,7 +265,7 @@ Rodyti QR kodą Bendrinti pakvietimo nuorodą SMP serveriai - Naudoti SimpleX Chat serverius\? + Naudoti SimpleX Chat serverius\? Naudoti tiesioginį interneto ryšį\? Atnaujinti Atnaujinti tinklo nustatymus\? @@ -276,7 +276,7 @@ Stabdyti pokalbį Bendrinti žinutę… Kamera - Dėkojame, kad įdiegėte SimpleX Chat! + Dėkojame, kad įdiegėte SimpleX Chat! Naudoti serverį Naudoti SOCKS įgaliotąjį serverį\? simplexmq: v%s (%2s) @@ -302,18 +302,18 @@ Jūsų privatumas JŪS Neteisinga slaptafrazė! - SimpleX + SimpleX jūs per grupės nuorodą per adresato adreso nuorodą per vienkartinę nuorodą - per %1$s + per %1$s Per naršyklę Laukiama failo - Balso žinutė (%1$s) + Balso žinutė (%1$s) Balso žinutė… Rodyti saugumo kodą - SimpleX adresas + SimpleX adresas Jūsų SMP serveriai Jūsų ICE serveriai Pridėti profilį @@ -321,15 +321,15 @@ Sveiki! Pridėti Jūs negalite siųsti žinučių! - SimpleX logotipas + SimpleX logotipas Jūsų nustatymai Jūsų serveris Jūsų serverio adresas Pridėti į kitą įrenginį - Naudojami SimpleX Chat serveriai. + Naudojami SimpleX Chat serveriai. Išplėstiniai tinklo nustatymai Jūsų dabartinis profilis - Jūsų profilis yra saugomas jūsų įrenginyje ir bendrinamas tik su jūsų adresatais. SimpleX serveriai negali matyti jūsų profilio. + Jūsų profilis yra saugomas jūsų įrenginyje ir bendrinamas tik su jūsų adresatais. SimpleX serveriai negali matyti jūsų profilio. vaizdo skambutis Jūsų skambučiai WebRTC ICE serveriai @@ -345,13 +345,13 @@ Jūs prisijungėte prie šios grupės Įspėjimas: galite prarasti tam tikrus duomenis! Jūs nustosite gauti žinutes iš šios grupės. Pokalbio istorija bus išsaugota. - jūs: %1$s - Sveiki, %1$s! + jūs: %1$s + Sveiki, %1$s! Pokalbiai Neteisinga duomenų bazės slaptafrazė Vaizdo įrašas išsiųstas Balso žinutė - SimpleX komanda + SimpleX komanda Kas naujo Įrašyti ir pranešti grupės nariams gautas patvirtinimas… @@ -389,8 +389,8 @@ Gali būti, kad liudijimo kontrolinis kodas serverio adrese yra neteisingas Ištrinti failą Dekodavimo klaida - Pridėti naują adresatą: norėdami sukurti adresatui vienkartinį QR kodą. - Skenuoti QR kodą: norėdami prisijungti prie adresato, kuris jums rodo QR kodą. + Pridėti naują adresatą: norėdami sukurti adresatui vienkartinį QR kodą.]]> + Skenuoti QR kodą: norėdami prisijungti prie adresato, kuris jums rodo QR kodą.]]> Išvalyti pokalbį Įjungti pranešimus Neteisingas QR kodas @@ -432,12 +432,12 @@ Neteisingas serverio adresas! Pokalbio profilis Profilis yra bendrinamas tik su jūsų adresatais. - Išsamiau skaitykite mūsų „GitHub“ saugykloje. + „GitHub“ saugykloje.]]> SOCKS ĮGALIOTASIS SERVERIS Įrašyti slaptafrazę ir atverti pokalbį Atkurti atsarginę duomenų bazės kopiją Atkurti atsarginę duomenų bazės kopiją\? - pakvietimas į %1$s grupę + pakvietimas į %1$s grupę Išeiti keičiamas adresas… keičiamas %s adresas… @@ -528,4 +528,6 @@ \nPrieinama versijoje v5.1" Vaizdo įrašas Vaizdo įrašai ir failai iki 1GB + Ieškoti + Išjungta \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-ml/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml similarity index 78% rename from apps/multiplatform/android/src/main/res/values-ml/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml index ede867e864..ac903ff708 100644 --- a/apps/multiplatform/android/src/main/res/values-ml/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ml/strings.xml @@ -1,5 +1,5 @@ - + ബന്ധിപ്പിക്കുന്നു ഉടനെ അനുവദിക്കുക @@ -10,7 +10,7 @@ ഇല്ലാതാക്കുക സുഹൃത്തുക്കളെ ക്ഷണിക്കുക വിലാസം ഇല്ലാതാക്കുക - ഇറ്റാലിക് + ഇറ്റാലിക് SimpleX-നെ കുറിച്ച് ബന്ധിപ്പിച്ചിരിക്കുന്നു ബന്ധിപ്പിക്കുന്നു… @@ -91,7 +91,7 @@ ഇല്ലാതാക്കുക വിലാസം ഇല്ലാതാക്കണോ\? അറിയിപ്പ് സേവനം - രഹസ്യം + രഹസ്യം വിലാസം സൃഷ്ടിക്കുന്നതിൽ പിശക് വിലാസം മാറ്റുന്നതിൽ പിശക് മറയ്ക്കുക @@ -146,13 +146,13 @@ പുതിയ അംഗങ്ങൾക്ക് കാണിക്കുന്ന സന്ദേശം സജ്ജമാക്കുക! സംഘത്തിലെ സ്വാഗത സന്ദേശം അവസാനമായി, ഞങ്ങൾക്ക് അവയുണ്ട്! 🚀 - ശബ്ദ സന്ദേശം (%1$s) + ശബ്ദ സന്ദേശം (%1$s) മറയ്ക്കുക പങ്കിടുക ക്രമീകരണങ്ങൾ സ്വാഗത സന്ദേശം ഇല്ല - സ്വാഗതം %1$s! + സ്വാഗതം %1$s! സന്ദേശം പങ്കിടുക… മറയ്ക്കുക: കാണിക്കുക: @@ -175,7 +175,7 @@ സന്ദേശം അയച്ചു നേരിട്ട് ക്രമീകരണം മാറ്റുന്നതിൽ പിശക് - നിങ്ങൾ: %1$s + നിങ്ങൾ: %1$s നിങ്ങൾക്കായി സംഘം ഇല്ലാതാക്കപ്പെടും - ഇത് പഴയപടിയാക്കാനാകില്ല! രൂപം ആവശ്യമാണ് @@ -214,7 +214,7 @@ വൃത്തിയാക്കുക വൃത്തിയാക്കുക കൂടുതലറിയുക - ഉപയോക്തൃ മാര്‍ഗ്ഗദര്‍ശിയിൽ കൂടുതൽ വായിക്കുക. + ഉപയോക്തൃ മാര്‍ഗ്ഗദര്‍ശിയിൽ കൂടുതൽ വായിക്കുക.]]> സെർവർ വിലാസം പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക. നിങ്ങളുടെ SMP സെർവറുകൾ ബന്ധം @@ -222,7 +222,7 @@ തുടരുക SimpleX വിലാസം സൃഷ്ടിക്കുക സൃഷ്ടിക്കുക - നിറമുള്ള + നിറമുള്ള അവസാനിച്ചു നിങ്ങളുടെ വിളികൾ സമർപ്പിക്കുക @@ -260,7 +260,7 @@ %s റദ്ദാക്കി ബ്ലൂടൂത്തും മറ്റ് മെച്ചപ്പെടുത്തലുകളും പിന്തുണയ്ക്കുക. മികച്ച സന്ദേശങ്ങൾ - %1$s നീക്കം ചെയ്തു + %1$s നീക്കം ചെയ്തു അപ്രത്യക്ഷമാകുന്ന സന്ദേശം അയയ്ക്കുക ഓരോ 10 നിമിഷവും ഒരു നിമിഷം വരെ പുതിയ സന്ദേശങ്ങൾ പരിശോധിക്കുന്നു നിങ്ങൾക്ക് ഇത് പിന്നീട് സൃഷ്ടിക്കാൻ കഴിയും @@ -275,7 +275,7 @@ നിങ്ങളുടെ സെർവർ വിലാസം എന്ന വിലാസത്തിൽ അയച്ചു നിങ്ങളുടെ XFTP സെർവറുകൾ - കുറിച്ച് SimpleX Chat + കുറിച്ച് SimpleX Chat എല്ലാ സംഭാഷണങ്ങളും സന്ദേശങ്ങളും ഇല്ലാതാക്കപ്പെടും - ഇത് പഴയപടിയാക്കാനാകില്ല! സംഘത്തിലെ എല്ലാ അംഗങ്ങളുടെ ബന്ധം നിലനിർത്തും. നിങ്ങളെ പരിശോധിക്കാൻ കഴിഞ്ഞില്ല; ദയവായി വീണ്ടും ശ്രമിക്കുക. @@ -337,4 +337,87 @@ കൂടുതൽ വായിക്കുക ഗതാഗത ഒറ്റപ്പെടൽ തിരഞ്ഞെടുക്കുക + വിലാസം മാറ്റുന്നത് നിർത്തണോ\? + സ്വാഗത സന്ദേശം നൽകുക… + പിശക്: %s + തൽക്ഷണ അറിയിപ്പുകൾ! + പൂർണ്ണമായ പേര്: + നിങ്ങൾ നിരസിക്കാൻ തിരഞ്ഞെടുക്കുകയാണെങ്കിൽ അയച്ചയാളെ അറിയിക്കില്ല. + ചിത്രം അയച്ചു + ഇതെങ്ങനെ ഉപയോഗിക്കണം + വിലാസ മാറ്റം നിർത്തുന്നതിൽ പിശക് + തിരുത്തുക + വിവരം + ഇല്ലാതാക്കുക + എല്ലാവർക്കും + നിഷ്‌ഫലമാക്കുക + അപ്രത്യക്ഷമാകുന്ന സന്ദേശം + സെർവർ ഇല്ലാതാക്കുക + നിങ്ങളുടെ സെർവറുകൾ എങ്ങനെ ഉപയോഗിക്കാം + സ്വാഗത സന്ദേശം നൽകുക... (ഇച്ഛാനുസൃതമായ) + സംരക്ഷിക്കാതെ പുറത്ത് പോവുക + ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു + SimpleX എങ്ങനെ പ്രവർത്തിക്കുന്നു + കൃത്യസമയം + പ്രവർത്തനരഹിതമാക്കുക + എന്നതിൽ ഇല്ലാതാക്കി + %d ദിവസം + %d ദിവസങ്ങൾ + ഇല്ലാതാക്കി + വിവരണം + സന്ദേശം അയയ്ക്കുന്നതിൽ പിശക് + വിലാസം ക്രമീകരിക്കുന്നതിൽ പിശക് + തൽക്ഷണ അറിയിപ്പുകൾ + സന്ദേശം ഇല്ലാതാക്കണോ\? + ഇമെയിൽ + എങ്ങനെ + സന്ദേശങ്ങൾ ഇല്ലാതാക്കുക + കര്‍ത്തവ്യം തിരഞ്ഞെടുക്കൽ വിപുലീകരിക്കുക + പ്രാരംഭ കര്‍ത്തവ്യം + കര്‍ത്തവ്യം മാറ്റുന്നതിൽ പിശക് + അംഗത്തെ നീക്കം ചെയ്യുന്നതിൽ പിശക് + വീണ്ടും കാണിക്കരുത് + അപ്രത്യക്ഷമാകുന്ന സന്ദേശങ്ങൾ + %d മാസം + %d മണിക്കൂർ + %d മാസങ്ങള്‍ + മണിക്കൂറുകൾ + വിലാസം സൃഷ്ടിക്കരുത് + ചിത്രം തിരുത്തുക + പരീക്ഷണാത്മക സവിശേഷതകൾ + വിലാസം മാറ്റുന്നത് നിർത്തുക + ദിവസങ്ങൾ + അപ്രത്യക്ഷമാകുന്ന സന്ദേശങ്ങൾ + ഈ സമയത്ത് അപ്രത്യക്ഷമാകുന്നു: %s + പ്രദർശന നാമം: + പരീക്ഷണാത്മകം + തൽക്ഷണ അറിയിപ്പുകൾ പ്രവർത്തനരഹിതമാക്കി! + ദയവായി അത് വികസിപ്പിക്കുന്നവരെ അറിയിക്കുക. + ക്ഷണം കാലഹരണപ്പെട്ടു! + സന്ദേശ വാചകം + പ്രിയപ്പെട്ടത് + വായിച്ചു എന്ന് അടയാളപ്പെടുത്തുക + ശൃംഖലയുടെ ക്രമീകരണങ്ങൾ + ശൃംഖലയുടെ നില + സന്ദേശം ഇല്ലാതാക്കപ്പെടും - ഇത് പഴയപടിയാക്കാനാകില്ല! + ചേരുക + %s ആയി ചേരുക + ഒരേ സമയം 10 ചിത്രങ്ങൾ മാത്രമേ അയക്കാൻ കഴിയൂ + കൂടുതൽ + പരിശോധിച്ചു എന്ന് അടയാളപ്പെടുത്തുക + പുതിയ പ്രദർശന നാമം: + പുതിയ അംഗ കർത്തവ്യം + ഉടമ + പൂര്‍വ്വദര്‍ശനം + നിങ്ങൾക്ക് മാത്രമേ സന്ദേശ പ്രതികരണങ്ങൾ ചേർക്കാൻ കഴിയൂ. + കൂടുതൽ മെച്ചപ്പെടുത്തലുകൾ ഉടൻ വരുന്നു! + നിമിഷങ്ങള്‍ + മാസങ്ങൾ + %1$s ക്ഷണിച്ചു + സന്ദേശം ഇല്ലാതാക്കാൻ അടയാളപ്പെടുത്തും. സ്വീകർത്താവിന്(കൾക്ക്) ഈ സന്ദേശം വെളിപ്പെടുത്താൻ കഴിയും. + അടയാളപ്പെടുത്തിയത് ഇല്ലാതാക്കി + വായിച്ചിട്ടില്ല എന്ന് അടയാളപ്പെടുത്തുക + %s വാഗ്ദാനം ചെയ്തു + തിരയുക + ഓഫാണ് \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-night/themes.xml b/apps/multiplatform/common/src/commonMain/resources/MR/night/themes.xml similarity index 100% rename from apps/multiplatform/android/src/main/res/values-night/themes.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/night/themes.xml diff --git a/apps/multiplatform/android/src/main/res/values-nl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-nl/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml index 04e55d2976..3697081620 100644 --- a/apps/multiplatform/android/src/main/res/values-nl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/nl/strings.xml @@ -1,5 +1,5 @@ - + oproepfout bellen… Oproepen op vergrendelscherm: @@ -58,7 +58,7 @@ Verificatie niet beschikbaar Terug Contact verzoeken automatisch accepteren - vetgedrukt + vetgedrukt Er wordt een willekeurig profiel naar uw contactpersoon verzonden Bijvoegen Sta het onomkeerbaar verwijderen van berichten alleen toe als uw contactpersoon dit toestaat. @@ -66,14 +66,14 @@ Sta toe dat uw contacten spraak berichten verzenden. Al uw contacten blijven verbonden. Spraak berichten toestaan\? - Goed voor de batterij. Achtergrondservice controleert berichten elke 10 minuten. Mogelijk mist u oproepen of dringende berichten. + Goed voor de batterij. Achtergrondservice controleert berichten elke 10 minuten. Mogelijk mist u oproepen of dringende berichten.]]> Onjuiste bericht hash - Scan QR-code: om verbinding te maken met uw contactpersoon die u de QR-code laat zien. + Scan QR-code: om verbinding te maken met uw contactpersoon die u de QR-code laat zien.]]> Onjuiste bericht ID Oproep al beëindigd! 1 maand Over SimpleX - Over SimpleX Chat + Over SimpleX Chat hier boven, dan: Alle gesprekken en berichten worden verwijderd, dit kan niet ongedaan worden gemaakt! Alle berichten worden verwijderd, dit kan niet ongedaan worden gemaakt! De berichten worden ALLEEN voor jou verwijderd. @@ -93,21 +93,21 @@ APP ICON App versie App versie: v%s - Er wordt een aparte TCP-verbinding (en SOCKS-referentie) gebruikt voor elk chat profiel dat je in de app hebt . + voor elk chat profiel dat je in de app hebt .]]> audio oproep (niet e2e versleuteld) Achtergrondservice is altijd actief, meldingen worden weergegeven zodra de berichten beschikbaar zijn. - Nieuw contact toevoegen: om een eenmalige QR-code voor uw contact te maken. + Nieuw contact toevoegen: om een eenmalige QR-code voor uw contact te maken.]]> Oproep beëindigd Batterijoptimalisatie is actief, waardoor achtergrondservice en periodieke verzoeken om nieuwe berichten worden uitgeschakeld. Je kunt ze weer inschakelen via instellingen. - Het beste voor de batterij. U ontvangt alleen meldingen wanneer de app wordt uitgevoerd (GEEN achtergrondservice). - Het kan worden uitgeschakeld via instellingen, meldingen worden nog steeds weergegeven terwijl de app actief is. + Het beste voor de batterij. U ontvangt alleen meldingen wanneer de app wordt uitgevoerd (GEEN achtergrondservice).]]> + Het kan worden uitgeschakeld via instellingen, meldingen worden nog steeds weergegeven terwijl de app actief is.]]> Zowel jij als je contactpersoon kunnen verzonden berichten onherroepelijk verwijderen. Zowel jij als je contactpersoon kunnen verdwijnende berichten sturen. Zowel jij als je contactpersoon kunnen spraak berichten verzenden. - Let op: u kunt het wachtwoord NIET herstellen of wijzigen als u het kwijt raakt. - Gebruikt meer batterij! Achtergrondservice wordt altijd uitgevoerd - meldingen worden weergegeven zodra berichten beschikbaar zijn. + Let op: u kunt het wachtwoord NIET herstellen of wijzigen als u het kwijt raakt.]]> + Gebruikt meer batterij! Achtergrondservice wordt altijd uitgevoerd - meldingen worden weergegeven zodra berichten beschikbaar zijn.]]> link voorbeeld annuleren - oproep beëindigd %1$s + oproep beëindigd %1$s Kan de database niet initialiseren adres wijzigen voor %s… Kan contact niet uitnodigen! @@ -135,7 +135,7 @@ Contact gecontroleerd Verbonden Verbinden… - verbinding %1$d + verbinding %1$d Verbindingsfout verbinden (geïntroduceerd) verbinden (introductie uitnodiging) @@ -163,7 +163,7 @@ Contact naam Contact verborgen: Decodeerfout - De momenteel maximaal ondersteunde bestandsgrootte is %1$s. + De momenteel maximaal ondersteunde bestandsgrootte is %1$s. Contact en alle berichten worden verwijderd, dit kan niet ongedaan worden gemaakt! Verbonden Bevestigen @@ -206,7 +206,7 @@ Verbind Maak verbinding via link Maak een eenmalige uitnodiging link - gekleurd + gekleurd Oproep verbinden… Maak Maak een profiel aan @@ -220,7 +220,7 @@ Huidige wachtwoord… Database versleuteld! is toegetreden - Gemaakt op %1$s + Gemaakt op %1$s compleet Wissen verbonden @@ -260,7 +260,7 @@ Groep verwijderen Link verwijderen\? Wachtende verbinding verwijderen\? - 💻 desktop: scan weergegeven QR-code vanuit de app, via Scan QR-code. + Scan QR-code.]]> Ontwikkel gereedschap Apparaatverificatie is uitgeschakeld. SimpleX Vergrendelen uitschakelen. Weergavenaam @@ -407,7 +407,7 @@ nieuw bericht Afbeelding verzonden Live bericht! - Als je een uitnodiging link voor SimpleX Chat hebt ontvangen, kun je deze in je browser openen: + Als je een uitnodiging link voor SimpleX Chat hebt ontvangen, kun je deze in je browser openen: Dit kan later worden gewijzigd via instellingen. Deelnemen aan groep\? Nodig leden uit @@ -422,8 +422,8 @@ Markeer gelezen Markeer als ongelezen Dempen - Als u elkaar niet persoonlijk kunt ontmoeten, kunt u de QR-code scannen in het video gesprek , of uw contactpersoon kan een uitnodiging link delen. - Als je elkaar niet persoonlijk kunt ontmoeten, toon je de QR-code in het video gesprek of deel je de link. + de QR-code scannen in het video gesprek , of uw contactpersoon kan een uitnodiging link delen.]]> + toon je de QR-code in het video gesprek of deel je de link.]]> Ongeldige QR-code Meer Onjuiste beveiligingscode! @@ -433,11 +433,11 @@ Markdown in berichten Netwerk instellingen Markdown gebruiken - cursief + cursief Hoe het werkt gemiste oproep - Hoe SimpleX werkt - Veel mensen vroegen: als SimpleX geen gebruikers ID\'s heeft, hoe kan het dan berichten bezorgen\? + Hoe SimpleX werkt + als SimpleX geen gebruikers ID\'s heeft, hoe kan het dan berichten bezorgen\?]]> Inkomende audio oproep Inkomend video gesprek Negeren @@ -472,11 +472,11 @@ Meer verbeteringen volgen snel! Nodig leden uit Verberg contact en bericht - Om het te gebruiken batterijoptimalisatie uitschakelen voor SimpleX in het volgende dialoogvenster. Anders worden de meldingen uitgeschakeld. + batterijoptimalisatie uitschakelen voor SimpleX in het volgende dialoogvenster. Anders worden de meldingen uitgeschakeld.]]> Als u ervoor kiest om te weigeren, wordt de afzender NIET op de hoogte gesteld. Onmiddellijk - heeft %1$s uitgenodigd - uitnodiging voor groep %1$s + heeft %1$s uitgenodigd + uitnodiging voor groep %1$s Uitnodigen voor groep Doe incognito mee lid worden als %s @@ -490,7 +490,7 @@ link voorbeeld afbeelding GEBRUIKER BERICHTEN EN BESTANDEN - 📱 mobiel: tik op Openen in mobiele app en tik vervolgens op Verbinden in de app. + Openen in mobiele app en tik vervolgens op Verbinden in de app.]]> Gebruiker wordt uit de groep verwijderd, dit kan niet ongedaan worden gemaakt! Fout bij bezorging van bericht Bericht wordt gemarkeerd voor verwijdering. De ontvanger(s) kunnen dit bericht onthullen. @@ -504,7 +504,7 @@ De incognito modus beschermt de privacy van uw hoofdprofielnaam en afbeelding, voor elk nieuw contact wordt een nieuw willekeurig profiel gemaakt. Nieuw database archief geen details - indirect (%1$s) + indirect (%1$s) k Bericht tekst Meldingsvoorbeeld @@ -512,7 +512,7 @@ Meldingen Ongeldige link! Ongeldig server adres! - Installeer SimpleX Chat voor terminal + Installeer SimpleX Chat voor terminal Hoe Hoe u uw servers gebruikt Netwerk & servers @@ -544,7 +544,7 @@ profielfoto Privacy opnieuw gedefinieerd Privacy en beveiliging - Controleer uw netwerkverbinding met %1$s en probeer het opnieuw. + Controleer uw netwerkverbinding met %1$s en probeer het opnieuw. Mogelijk is de certificaat vingerafdruk in het server adres onjuist Periodieke meldingen Chat console openen @@ -558,7 +558,7 @@ Plak de ontvangen link Periodiek Open - Open SimpleX Chat om de oproep te accepteren + Open SimpleX Chat om de oproep te accepteren peer-to-peer Meldingen worden alleen afgeleverd totdat de app stopt! Wachtwoord niet gevonden in de Keychain, voer deze handmatig in. Dit kan zijn gebeurd als u de gegevens van de app hebt hersteld met een back-up tool. Als dit niet het geval is, neem dan contact op met de ontwikkelaars. @@ -608,7 +608,7 @@ Oproep in behandeling Het openen van de link in de browser kan de privacy en beveiliging van de verbinding verminderen. Niet vertrouwde SimpleX links worden rood weergegeven. Werk de app bij en neem contact op met de ontwikkelaars. - Alleen client apparaten slaan gebruikers profielen, contacten, groepen en berichten op die zijn verzonden met 2-laags end-to-end codering. + 2-laags end-to-end codering.]]> De afzender heeft mogelijk het verbindingsverzoek verwijderd. Schakel SimpleX Vergrendelen in om uw informatie te beschermen. \nU wordt gevraagd de authenticatie te voltooien voordat deze functie wordt ingeschakeld. @@ -618,7 +618,7 @@ Stuur een livebericht Om een nieuw gesprek te starten Dempen opheffen - SimpleX-Team + SimpleX-Team Deze QR-code is geen link! Deze link is geen geldige link! Eenmalige link delen @@ -628,7 +628,7 @@ Jij beheert je gesprek! Uw profiel, contacten en afgeleverde berichten worden op uw apparaat opgeslagen. beginnen… - U bepaalt via welke server(s) je de berichten ontvangt, uw contacten de servers die u gebruikt om ze berichten te sturen. + ontvangt, uw contacten de servers die u gebruikt om ze berichten te sturen.]]> Video aan Deze actie kan niet ongedaan worden gemaakt. Uw profiel, contacten, berichten en bestanden gaan onomkeerbaar verloren. Deze instelling is van toepassing op berichten in uw huidige chat profiel @@ -637,12 +637,12 @@ verwijderd Uw chat profiel wordt verzonden naar de groepsleden Je hebt al een chat profiel met dezelfde weergave naam. Kies een andere naam. - U bent al verbonden met %1$s. + U bent al verbonden met %1$s. Test mislukt bij stap %s. Veilige wachtrij De database werkt niet goed. Tik voor meer informatie Voer het wachtwoord van de database in om meldingen te ontvangen - SimpleX Chat service + SimpleX Chat service Berichten ontvangen… Toon contact en bericht Toon alleen contactpersoon @@ -688,9 +688,9 @@ QR code Instellingen wil met je in contact komen! - SimpleX Adres + SimpleX Adres Toon QR-code - SimpleX-Logo + SimpleX-Logo Je chat profiel wordt verzonden naar uw contactpersoon Je wordt verbonden met de groep wanneer het apparaat van de groep host online is, even geduld a.u.b. of controleer het later! U wordt verbonden wanneer uw verbindingsverzoek wordt geaccepteerd, even geduld a.u.b. of controleer later! @@ -700,7 +700,7 @@ %s is niet geverifieerd %s is geverifieerd Vergelijk (of scan) de code op uw apparaten om end-to-end codering met uw contactpersoon te verifiëren. - U kunt ook verbinding maken door op de link te klikken. Als het in de browser wordt geopend, klikt u op de knop Openen in mobiele app . + Openen in mobiele app .]]> Uw chat profiel wordt naar uw contactpersoon verzonden Uw chat profielen Uw SimpleX adres @@ -715,7 +715,7 @@ Server test Beoordeel de app Gebruik server - Gebruik van SimpleX Chat servers. + Gebruik van SimpleX Chat servers. Uw server adres Uw server Transport isolation @@ -724,20 +724,20 @@ Je huidige profiel Opslaan en Contacten melden Opslaan en Groepsleden melden - staking + staking Het berichten- en applicatieplatform dat uw privacy en veiligheid beschermt. Het profiel wordt alleen gedeeld met uw contacten. We slaan geen van uw contacten of berichten (eenmaal afgeleverd) op de servers op. U kunt markdown gebruiken voor opmaak in berichten: geweigerde oproep - geheim + geheim De volgende generatie privéberichten wachten op antwoord… - Om de privacy te beschermen, heeft SimpleX in plaats van gebruikers ID\'s die door alle andere platforms worden gebruikt, ID\'s voor berichten wachtrijen, afzonderlijk voor elk van uw contacten. + Om de privacy te beschermen, heeft SimpleX in plaats van gebruikers ID\'s die door alle andere platforms worden gebruikt, ID\'s voor berichten wachtrijen, afzonderlijk voor elk van uw contacten. Gebruik chat Wanneer de app actief is video gesprek (niet e2e versleuteld) - %1$s wil met je in contact komen via + %1$s wil met je in contact komen via Afwijzen video oproep Uw oproepen @@ -772,10 +772,10 @@ Je gebruikt een incognito profiel voor deze groep. Om te voorkomen dat je je hoofdprofiel deelt, is het niet toegestaan om contacten uit te nodigen Je hebt de groep uitnodiging afgewezen Je bent lid geworden van deze groep - verwijderd %1$s + verwijderd %1$s heeft je verwijderd - jij: %1$s - %1$s LEDEN + jij: %1$s + %1$s LEDEN U kunt een link of een QR-code delen. Iedereen kan lid worden van de groep. U verliest geen leden van de groep als u deze later verwijdert. Wijzig De rol wordt gewijzigd in \"%s\". Iedereen in de groep wordt op de hoogte gebracht. @@ -835,7 +835,7 @@ Controleer de verbindingsbeveiliging Dank aan de gebruikers – draag bij via Weblate! Transport isolation - SimpleX + SimpleX U bent verbonden met de server die wordt gebruikt om berichten van dit contact te ontvangen. Je profiel wordt verzonden naar het contact van wie je deze link hebt ontvangen. U wordt lid van de groep waar deze link naar verwijst en maakt verbinding met de groepsleden. @@ -845,14 +845,14 @@ Start periodiek Spraakbericht Spraakbericht… - Spraakbericht (%1$s) + Spraakbericht (%1$s) Contactnaam instellen… Spraak berichten verboden! Resetten Verstuur Stuur een live bericht, het wordt bijgewerkt voor de ontvanger(s) terwijl u het typt (om te delen met uw contact) - Bedankt voor het installeren van SimpleX Chat! + Bedankt voor het installeren van SimpleX Chat! Camera Gebruik voor nieuwe verbindingen Star on GitHub @@ -908,25 +908,25 @@ Scan server QR-code Deze string is geen verbinding link! Deze actie kan niet ongedaan worden gemaakt, de berichten die eerder zijn verzonden en ontvangen dan geselecteerd, worden verwijderd. Het kan enkele minuten duren. - Deze functie is experimenteel! Het werkt alleen als op de andere client versie 4.2 is geïnstalleerd. U zou het bericht in het gesprek moeten zien zodra de adreswijziging is voltooid. Controleer of u nog steeds berichten van dit contact (of groepslid) kunt ontvangen. - Om je privacy te behouden, heeft de app in plaats van push meldingen een SimpleX achtergrond service - deze gebruikt een paar procent van de batterij per dag. + Het ontvangstadres wordt gewijzigd naar een andere server. Adres wijziging wordt voltooid nadat de afzender online is. + SimpleX achtergrond service - deze gebruikt een paar procent van de batterij per dag.]]> Jij staat toe Je bent uitgenodigd voor de groep - U kunt verbinding maken met SimpleX Chat ontwikkelaars om vragen te stellen en updates te ontvangen. + verbinding maken met SimpleX Chat ontwikkelaars om vragen te stellen en updates te ontvangen.]]> Tenzij uw contactpersoon de verbinding heeft verwijderd of deze link al is gebruikt, kan het een bug zijn. Meld het alstublieft. \nOm verbinding te maken, vraagt u uw contactpersoon om een andere verbinding link te maken en te controleren of u een stabiele netwerkverbinding heeft. .onion hosts-instelling updaten\? - SimpleX Chat servers gebruiken\? + SimpleX Chat servers gebruiken\? Spraak berichten zijn verboden in deze groep. - Welkom %1$s! + Welkom %1$s! U kunt de chat starten via app Instellingen / Database of door de app opnieuw op te starten. je hebt het adres gewijzigd voor %s - je hebt %1$s verwijderd - Je contactpersoon heeft een bestand verzonden dat groter is dan de momenteel ondersteunde maximale grootte (%1$s). + je hebt %1$s verwijderd + Je contactpersoon heeft een bestand verzonden dat groter is dan de momenteel ondersteunde maximale grootte (%1$s). Uw huidige chatdatabase wordt VERWIJDERD en VERVANGEN door de geïmporteerde. \nDeze actie kan niet ongedaan worden gemaakt. Uw profiel, contacten, berichten en bestanden gaan onomkeerbaar verloren. Je probeert een contact met wie je een incognito profiel hebt gedeeld, uit te nodigen voor de groep waarin je je hoofdprofiel gebruikt - Uw profiel wordt op uw apparaat opgeslagen en alleen gedeeld met uw contacten. SimpleX servers kunnen uw profiel niet zien. + Uw profiel wordt op uw apparaat opgeslagen en alleen gedeeld met uw contacten. SimpleX servers kunnen uw profiel niet zien. U moet zich authenticeren wanneer u de app na 30 seconden op de achtergrond start of hervat. Te veel afbeeldingen! Luidspreker uit @@ -940,20 +940,20 @@ SimpleX links Eenmalige SimpleX uitnodiging Proberen verbinding te maken met de server die wordt gebruikt om berichten van dit contact te ontvangen. - Er wordt geprobeerd verbinding te maken met de server die wordt gebruikt om berichten van dit contact te ontvangen (fout: %1$s). + Er wordt geprobeerd verbinding te maken met de server die wordt gebruikt om berichten van dit contact te ontvangen (fout: %1$s). onbekend berichtformaat Via browser via contact adres link via groep link via een eenmalige link - via %1$s + via %1$s jij je hebt een eenmalige link gedeeld je hebt een eenmalige link incognito gedeeld Tik op de knop - Lees meer in onze GitHub repository. + GitHub repository.]]> Lees meer in onze GitHub repository. - %1$d bericht(en) overgeslagen + %1$d bericht(en) overgeslagen gemodereerd gemodereerd door %s Bericht van lid verwijderen\? @@ -1054,7 +1054,7 @@ Poort SOCKS proxy instellingen Gebruik SOCKS proxy - Stel Use .onion hosts in op Nee als de SOCKS-proxy deze niet ondersteunt. + Use .onion hosts in op Nee als de SOCKS-proxy deze niet ondersteunt.]]> Bestand maken Fout bij het laden van SMP servers Zorg ervoor dat XFTP server adressen de juiste indeling hebben, regel gescheiden zijn en niet gedupliceerd zijn. @@ -1091,7 +1091,7 @@ Systeem Decodering fout De hash van het vorige bericht is anders. - %1$d berichten overgeslagen. + %1$d berichten overgeslagen. Het kan gebeuren wanneer u of uw verbinding de oude databaseback-up gebruikte. Meld het alsjeblieft aan de ontwikkelaars. Deze fout is permanent voor deze verbinding, maak opnieuw verbinding. @@ -1099,7 +1099,7 @@ Onjuiste bericht ID De ID van het volgende bericht is onjuist (minder of gelijk aan het vorige). \nHet kan gebeuren vanwege een bug of wanneer de verbinding is aangetast. - %1$d-berichten konden niet worden ontsleuteld. + %1$d-berichten konden niet worden ontsleuteld. Geen spaties! Het ontvangen van het bestand wordt gestopt. Intrekken @@ -1179,7 +1179,7 @@ Fout bij importeren thema Zorg ervoor dat het bestand de juiste YAML-syntaxis heeft. Exporteer het thema om een voorbeeld te hebben van de themabestandsstructuur. Database openen… - Lees meer in de Gebruikershandleiding. + Gebruikershandleiding.]]> THEMA KLEUREN U kunt uw adres delen als een link of QR-code - iedereen kan verbinding met u maken. Uw contacten in SimpleX zullen het zien. @@ -1266,4 +1266,21 @@ Herstarten Afsluiten Meldingen werken niet meer totdat u de app opnieuw start + Fout bij het afbreken van adres wijziging + Adres wijziging afbreken\? + Adres wijziging wordt afgebroken. Het oude ontvangstadres wordt gebruikt. + Annuleer het wijzigen van het adres + Afbreken + Geen gefilterde gesprekken + Alleen groepseigenaren kunnen bestanden en media inschakelen. + Bestanden en media zijn verboden in deze groep. + Favoriet + Bestanden en media verboden! + Niet favoriet + Bestanden en media + Verbied het verzenden van bestanden en media. + Sta toe om bestanden en media te verzenden. + Groepsleden kunnen bestanden en media verzenden. + Zoeken + Uit \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-pl/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-pl/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml index 7d4474bc0f..552f41ffe9 100644 --- a/apps/multiplatform/android/src/main/res/values-pl/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pl/strings.xml @@ -1,5 +1,5 @@ - + Uwierzytelnianie urządzenia jest wyłączone. Wyłączanie blokady SimpleX. Uwierzytelnianie urządzenia nie jest włączone. Możesz włączyć blokadę SimpleX w Ustawieniach po włączeniu uwierzytelniania urządzenia. Bezpośrednie wiadomości @@ -8,7 +8,7 @@ łączenie łączenie… połączenie ustanowione - połączenie %1$d + połączenie %1$d Połączyć się przez link kontaktowy\? Połącz się przez link grupowy\? Połączyć się przez link zapraszający\? @@ -26,9 +26,9 @@ wysyłanie plików nie jest jeszcze obsługiwane odbieranie plików nie jest jeszcze obsługiwane Próbowanie połączenia z serwerem używanym do odbierania wiadomości od tego kontaktu. - Próbowanie połączenia z serwerem używanym do odbierania wiadomości od tego kontaktu (błąd: %1$s). + Próbowanie połączenia z serwerem używanym do odbierania wiadomości od tego kontaktu (błąd: %1$s). nieznany format wiadomości - SimpleX + SimpleX Ty Jesteś połączony z serwerem używanym do odbierania wiadomości od tego kontaktu. Twój profil zostanie wysłany do kontaktu, od którego otrzymałeś ten link. @@ -45,7 +45,7 @@ Link grupy SimpleX Linki SimpleX Przez przeglądarkę - przez %1$s + przez %1$s Błąd aktualizacji konfiguracji sieci Nie można odebrać pliku Błąd połączenia @@ -153,7 +153,7 @@ nieautoryzowane wysyłanie oznacz jako nieprzeczytane Witaj! - Witaj %1$s! + Witaj %1$s! jesteś zaproszony do grupy Nie masz czatów Czaty @@ -181,7 +181,7 @@ jesteś obserwatorem Nie możesz wysyłać wiadomości! Połączony - Obecnie maksymalny obsługiwany rozmiar pliku to %1$s . + Obecnie maksymalny obsługiwany rozmiar pliku to %1$s . Usuń kontakt Usunąć kontakt\? Rozłączony @@ -197,13 +197,13 @@ Nagraj wiadomość głosową Wyślij wiadomość Ustaw nazwę kontaktu… - Przełączyć adres odbioru\? + Zmienić adres odbioru\? Weryfikuj kod bezpieczeństwa Pokaż kod bezpieczeństwa Wiadomość głosowa Wiadomość głosowa… Wiadomości głosowe zabronione! - Wiadomość głosowa (%1$s) + Wiadomość głosowa (%1$s) Oczekiwanie na plik Musisz zezwolić Twojemu kontaktowi na wysyłanie wiadomości głosowych, aby móc je wysyłać. Anuluj @@ -229,7 +229,7 @@ Akceptuj Akceptuj incognito Wszystkie wiadomości zostaną usunięte - nie można tego cofnąć! Wiadomości zostaną usunięte TYLKO dla Ciebie. - Zeskanuj kod QR: aby połączyć się z kontaktem, który pokaże Ci kod QR. + Zeskanuj kod QR: aby połączyć się z kontaktem, który pokaże Ci kod QR.]]> anuluj podgląd linku Wyczyść Wyczyść @@ -239,11 +239,11 @@ Kontakt nie jest jeszcze połączony! Usuń Usunąć oczekujące połączenie\? - 💻 komputer: zeskanuj wyświetlony kod QR z aplikacji, przez Zeskanuj kod QR. + Zeskanuj kod QR.]]> link podglądu obrazu Oznacz jako przeczytane Oznacz jako nieprzeczytane - 📱 telefon: dotknij Otwórz w aplikacji mobilnej, a następnie dotknij Połącz w aplikacji. + Otwórz w aplikacji mobilnej, a następnie dotknij Połącz w aplikacji.]]> Wycisz zdjęcie profilowe miejsce na zdjęcie profilowe @@ -265,7 +265,7 @@ Połącz się przez link Email pomoc - Jeśli nie możesz spotkać się osobiście, pokaż kod QR w rozmowie wideo, lub udostępnij link. + pokaż kod QR w rozmowie wideo, lub udostępnij link.]]> Nieprawidłowy kod bezpieczeństwa! Nieprawidłowy link! Nieprawidłowy kod QR @@ -284,9 +284,9 @@ %s jest zweryfikowany Ten kod QR nie jest linkiem! Ten ciąg nie jest linkiem połączenia! - Adres SimpleX - Logo SimpleX - Możesz też połączyć się klikając w link. Jeśli otworzy się on w przeglądarce, kliknij przycisk Otwórz w aplikacji mobilnej. + Adres SimpleX + Logo SimpleX + Otwórz w aplikacji mobilnej.]]> Twój profil czatu zostanie wysłany \ndo Twojego kontaktu Twój profil czatu zostanie wysłany do Twojego kontaktu @@ -324,7 +324,7 @@ Przetestuj serwery Serwery dla nowych połączeń bieżącego profilu czatu Użyj serwera - Używanie serwerów SimpleX Chat. + Używanie serwerów SimpleX Chat. Twoje profile czatu Twoje serwery ICE Twój serwer @@ -337,7 +337,7 @@ Wygląd Wersja aplikacji Wersja aplikacji: v%s - Oddzielne połączenie TCP (i poświadczenia SOCKS) będą używane dla każdego profilu czatu, który masz w aplikacji. + dla każdego profilu czatu, który masz w aplikacji.]]> Oddzielne połączenie TCP (i poświadczenia SOCKS) będą używane dla każdego kontaktu i członka grupy. \nUwaga: jeśli masz wiele połączeń, zużycie baterii i ruchu może być znacznie wyższe, a niektóre połączenia mogą się nie udać. Profil czatu @@ -400,12 +400,12 @@ a + b O SimpleX zaakceptowane połączenie - pogrubiona - połączenie zakończone %1$s + pogrubiona + połączenie zakończone %1$s błąd połączenia dzwonie… połączenie w toku - kolorowy + kolorowy połączony łączenie… łączenie połączenia… @@ -415,7 +415,7 @@ Pełna nazwa (opcjonalna) Jak korzystać z markdown Odporność na spam i nadużycia - kursywa + kursywa nieodebrane połączenie Otwarto źródłowy protokół i kod - każdy może uruchomić serwery. Ludzie mogą się z Tobą połączyć tylko poprzez linki, które udostępniasz. @@ -423,9 +423,9 @@ otrzymano odpowiedź… otrzymano potwierdzenie… odrzucone połączenie - sekret + sekret uruchamianie… - strajk + strajk Pierwsza platforma bez żadnych identyfikatorów użytkowników – z założenia prywatna. Następna generacja prywatnych wiadomości oczekiwanie na odpowiedź… @@ -433,20 +433,20 @@ Możesz używać markdown do formatowania wiadomości: Utwórz swój profil Jak to działa - Jak SimpleX działa + Jak SimpleX działa Natychmiastowy Można to później zmienić w ustawieniach. Nawiąż prywatne połączenie - Wiele osób pytało: jeśli SimpleX nie ma identyfikatora użytkownika, jak może dostarczać wiadomości\? - Tylko urządzenia klienckie przechowują profile użytkowników, kontakty, grupy i wiadomości wysyłane za pomocą 2-warstwowego szyfrowania end-to-end. + jeśli SimpleX nie ma identyfikatora użytkownika, jak może dostarczać wiadomości\?]]> + 2-warstwowego szyfrowania end-to-end.]]> Okresowo Prywatne powiadomienia - Przeczytaj więcej na naszym repozytorium GitHub. + repozytorium GitHub.]]> Przeczytaj więcej na naszym repozytorium GitHub. Użyj czatu Gdy aplikacja jest uruchomiona - Kontrolujesz przez który serwer(y) odbierać wiadomości, Twoje kontakty - serwery, których używasz do wysyłania im wiadomości. - Zużywa więcej baterii! Usługa zawsze działa w tle - powiadomienia są wyświetlane, gdy tylko wiadomości są dostępne. + odbierać wiadomości, Twoje kontakty - serwery, których używasz do wysyłania im wiadomości.]]> + Zużywa więcej baterii! Usługa zawsze działa w tle - powiadomienia są wyświetlane, gdy tylko wiadomości są dostępne.]]> Przychodzące połączenie audio Przychodzące połączenie wideo Wklej otrzymany link @@ -487,7 +487,7 @@ Nieodebrane połączenie brak szyfrowania e2e Otwórz - Otwórz SimpleX Chat, aby przyjąć połączenie. + Otwórz SimpleX Chat, aby przyjąć połączenie. peer-to-peer Oczekujące połączenie Odrzucone połączenie @@ -497,7 +497,7 @@ przez przekaźnik Wideo wyłączone Wideo włączone - %1$d wiadomość(i) pominięta(e) + %1$d wiadomość(i) pominięta(e) Może to nastąpić, gdy: \n1. Wiadomości wygasły w wysyłającym kliencie po 2 dniach lub na serwerze po 30 dniach. \n2. Odszyfrowanie wiadomości nie powiodło się, ponieważ Ty lub Twój kontakt użyliście starej kopii zapasowej bazy danych. @@ -581,7 +581,7 @@ Twoja baza danych czatu nie jest szyfrowana - ustaw hasło, aby ją chronić. Android Keystore służy do bezpiecznego przechowywania hasła - umożliwia działanie usługi powiadomień. Android Keystore będzie używany do bezpiecznego przechowywania hasła po ponownym uruchomieniu aplikacji lub zmianie hasła - pozwoli to na otrzymywanie powiadomień. - Uwaga: NIE będziesz w stanie odzyskać ani zmienić hasła, jeśli je zgubisz. + Uwaga: NIE będziesz w stanie odzyskać ani zmienić hasła, jeśli je zgubisz.]]> Nie można uzyskać dostępu do Keystore w celu zapisania hasła bazy danych Zmienić hasło bazy danych\? Hasło szyfrowania bazy danych zostanie zaktualizowane. @@ -656,14 +656,14 @@ Zaproszenie do grupy wygasło zaktualizowano profil grupy zaproszony przez Twój link grupy - zaproszony %1$s + zaproszony %1$s opuścił opuścił członek obserwator właściciel usunięty - usunięto %1$s + usunięto %1$s usunął cię Dotknij, aby dołączyć Dotknij, aby dołączyć w trybie incognito @@ -710,7 +710,7 @@ Opuść grupę Wiadomość powitalna Próbujesz zaprosić osobę, z którą masz wspólny profil incognito do grupy, w której używasz swojego głównego profilu - ty: %1$s + ty: %1$s Zmień Zmienić rolę grupy\? Zmień rolę @@ -742,7 +742,7 @@ Wysyłanie przez SERWERY Przełącz - Przełącz adres odbioru + Zmień adres odbioru Grupa jest w pełni zdecentralizowana – jest widoczna tylko dla członków. Rola zostanie zmieniona na \"%s\". Członek otrzyma nowe zaproszenie. Wiadomość powitalna @@ -900,7 +900,7 @@ Podziękowania dla użytkowników - wkład za pośrednictwem Weblate! Podziękowania dla użytkowników - wkład za pośrednictwem Weblate! Zezwól swoim kontaktom na nieodwracalne usuwanie wysłanych wiadomości. - O SimpleX Chat + O SimpleX Chat powyżej, wtedy: Zaakceptować prośbę o połączenie\? Akcent @@ -921,11 +921,11 @@ Uwierzytelnianie niedostępne Dołącz Wstecz - Dodaj nowy kontakt: aby stworzyć swój jednorazowy kod QR dla kontaktu. + Dodaj nowy kontakt: aby stworzyć swój jednorazowy kod QR dla kontaktu.]]> Optymalizacja baterii jest aktywna, wyłącza usługi w tle i okresowe żądania nowych wiadomości. Możesz je ponownie włączyć za pośrednictwem ustawień. - Można je wyłączyć poprzez ustawienia - powiadomienia nadal będą pokazywane podczas działania aplikacji. - Najlepsze dla baterii. Będziesz otrzymywać powiadomienia tylko wtedy, gdy aplikacja jest uruchomiona (NIE w tle). - Dobry dla baterii. Usługa w tle sprawdza wiadomości co 10 minut. Możesz przegapić połączenia lub pilne wiadomości. + Można je wyłączyć poprzez ustawienia - powiadomienia nadal będą pokazywane podczas działania aplikacji.]]> + Najlepsze dla baterii. Będziesz otrzymywać powiadomienia tylko wtedy, gdy aplikacja jest uruchomiona (NIE w tle).]]> + Dobry dla baterii. Usługa w tle sprawdza wiadomości co 10 minut. Możesz przegapić połączenia lub pilne wiadomości.]]> Zarówno Ty, jak i Twój kontakt możecie wysyłać wiadomości głosowe. Według profilu czatu (domyślnie) lub połączenia (BETA). Nie można zaprosić kontaktów! @@ -936,7 +936,7 @@ Kontakt i wszystkie wiadomości zostaną usunięte - nie można tego cofnąć! Błąd połączenia (UWIERZYTELNIANIE) Połącz się przez link / kod QR - Utworzony na %1$s + Utworzony na %1$s Utwórz jednorazowy link do zaproszenia Utwórz tajną grupę Utwórz tajną grupę @@ -969,25 +969,25 @@ Członkowie grupy mogą wysyłać wiadomości głosowe. Grupa zostanie usunięta dla wszystkich członków - nie można tego cofnąć! Jak korzystać z Twoich serwerów - Jeśli nie możesz spotkać się osobiście, możesz zeskanować kod QR w rozmowie wideo, lub Twój rozmówca może udostępnić link z zaproszeniem. + zeskanować kod QR w rozmowie wideo, lub Twój rozmówca może udostępnić link z zaproszeniem.]]> Jeśli odrzucisz nadawca NIE zostanie powiadomiony. incognito poprzez link adresu kontaktowego - Jeśli otrzymałeś link do zaproszenia SimpleX Chat, możesz go otworzyć w swojej przeglądarce: + Jeśli otrzymałeś link do zaproszenia SimpleX Chat, możesz go otworzyć w swojej przeglądarce: Zaimportować bazę danych czatu\? Tryb Incognito nie jest tutaj obsługiwany - główny profil zostanie wysłany do członków grupy. Tryb incognito chroni prywatność nazwy i obrazu głównego profilu — dla każdego nowego kontaktu tworzony jest nowy losowy profil. - pośrednie (%1$s) - Aby z niej skorzystać, należy wyłączyć optymalizację baterii dla SimpleX w następnym oknie dialogowym. W przeciwnym razie powiadomienia zostaną wyłączone. - Zainstaluj SimpleX Chat na terminal + pośrednie (%1$s) + wyłączyć optymalizację baterii dla SimpleX w następnym oknie dialogowym. W przeciwnym razie powiadomienia zostaną wyłączone.]]> + Zainstaluj SimpleX Chat na terminal Nieprawidłowe potwierdzenie migracji - zaproszenie do grupy %1$s + zaproszenie do grupy %1$s Nieodwracalne usuwanie wiadomości Upewnij się, że adresy serwerów WebRTC ICE są w poprawnym formacie, rozdzielone liniami i nie są zduplikowane. Upewnij się, że adresy serwerów SMP są w poprawnym formacie, rozdzielone liniami i nie są zduplikowane. Poproś Twój kontakt o włączenie wysyłania wiadomości głosowych. Sprawdź, czy użyłeś prawidłowego linku lub poproś Twój kontakt o przesłanie innego. Wiadomość zostanie usunięta - nie można tego cofnąć! - Proszę sprawdzić połączenie sieciowe za pomocą %1$s i spróbuj ponownie. + Proszę sprawdzić połączenie sieciowe za pomocą %1$s i spróbuj ponownie. Prosimy o bezpieczne przechowywanie hasła, w przypadku jego utraty NIE będzie można go zmienić. Zabroń wysyłania wiadomości głosowych. Najprawdopodobniej ten kontakt usunął połączenie z Tobą. @@ -1006,38 +1006,38 @@ Zatrzymaj czat, aby wyeksportować, zaimportować lub usunąć bazę danych czatu. Podczas zatrzymania chatu nie będzie można odbierać ani wysyłać wiadomości. Niektóre serwery nie przeszły testu: Powinien istnieć co najmniej jeden profil użytkownika. - Dziękujemy za zainstalowanie SimpleX Chat! + Dziękujemy za zainstalowanie SimpleX Chat! Powinien istnieć co najmniej jeden widoczny profil użytkownika. Wiadomość zostanie oznaczona jako moderowana dla wszystkich członków. Rola zostanie zmieniona na \"%s\". Wszyscy w grupie zostaną powiadomieni. Tego działania nie można cofnąć - wszystkie odebrane i wysłane pliki oraz media zostaną usunięte. Obrazy o niskiej rozdzielczości pozostaną. - Ta funkcja jest eksperymentalna! Będzie działać tylko wtedy, gdy drugi klient ma zainstalowaną wersję 4.2. Po zakończeniu zmiany adresu powinieneś zobaczyć wiadomość w konwersacji - sprawdź, czy nadal możesz otrzymywać wiadomości od tego kontaktu (lub członka grupy). + Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online. Ten link nie jest prawidłowym linkiem połączenia! Aby znaleźć profil używany do połączenia incognito, dotknij nazwę kontaktu lub grupy w górnej części czatu. - Aby zachować prywatność, zamiast powiadomień push aplikacja posiada usługę w tle SimpleX - zużywa ona kilka procent baterii dziennie. - Aby chronić prywatność, zamiast identyfikatorów użytkowników używanych przez wszystkie inne platformy, SimpleX ma identyfikatory dla kolejek wiadomości, oddzielne dla każdego z Twoich kontaktów. + SimpleX - zużywa ona kilka procent baterii dziennie.]]> + Aby chronić prywatność, zamiast identyfikatorów użytkowników używanych przez wszystkie inne platformy, SimpleX ma identyfikatory dla kolejek wiadomości, oddzielne dla każdego z Twoich kontaktów. Aby zweryfikować szyfrowanie end-to-end z Twoim kontaktem porównaj (lub zeskanuj) kod na waszych urządzeniach. Użyj dla nowych połączeń O ile Twój kontakt nie usunął połączenia lub ten link był już użyty, może to być błąd - zgłoś go. \nAby się połączyć, poproś Twój kontakt o utworzenie kolejnego linku połączenia i sprawdź, czy masz stabilne połączenie z siecią. - Używać serwerów SimpleX Chat\? - Drużyna SimpleX + Używać serwerów SimpleX Chat\? + Drużyna SimpleX Gdy dostępny Z opcjonalną wiadomością powitalną. - %1$s CZŁONKÓW - serwis SimpleX Chat - %1$s chce się z Tobą połączyć przez - Jesteś już połączony z %1$s. - Możesz połączyć się z deweloperami SimpleX Chat aby zadać wszelkie pytania i otrzymywać aktualizacje. + %1$s CZŁONKÓW + serwis SimpleX Chat + %1$s chce się z Tobą połączyć przez + Jesteś już połączony z %1$s. + połączyć się z deweloperami SimpleX Chat aby zadać wszelkie pytania i otrzymywać aktualizacje.]]> Możesz udostępnić link lub kod QR - każdy będzie mógł dołączyć do grupy. Nie stracisz członków grupy, jeśli później ją usuniesz. Musisz używać najnowszej wersji bazy danych czatu TYLKO na jednym urządzeniu, w przeciwnym razie możesz przestać otrzymywać wiadomości od niektórych kontaktów. Możesz rozpocząć czat poprzez Ustawienia aplikacji / Bazę danych lub poprzez ponowne uruchomienie aplikacji. Twoje ustawienia Twoja obecna baza danych czatu zostanie USUNIĘTA i ZASTĄPIONA zaimportowaną. \nTej czynności nie można cofnąć - Twój profil, kontakty, wiadomości i pliki zostaną nieodwracalnie utracone. - Twój kontakt wysłał plik, który jest większy niż obecnie obsługiwany maksymalny rozmiar (%1$s). - usunąłeś %1$s - Twój profil jest przechowywany na Twoim urządzeniu i udostępniany tylko Twoim kontaktom. Serwery SimpleX nie widzą Twojego profilu. + Twój kontakt wysłał plik, który jest większy niż obecnie obsługiwany maksymalny rozmiar (%1$s). + usunąłeś %1$s + Twój profil jest przechowywany na Twoim urządzeniu i udostępniany tylko Twoim kontaktom. Serwery SimpleX nie widzą Twojego profilu. udostępniłeś jednorazowy link incognito Dołączysz do grupy, do której odnosi się ten link i połączysz się z jej członkami. Twoje serwery SMP @@ -1056,7 +1056,7 @@ Host Port port %d - Ustaw Użyj hostów .onion na Nie jeśli proxy SOCKS ich nie obsługuje. + Użyj hostów .onion na Nie jeśli proxy SOCKS ich nie obsługuje.]]> Ustawienia PROXY SOCKS Użyj proxy SOCKS Upewnij się, że adresy serwerów XFTP są w poprawnym formacie, rozdzielone liniami i nie są zduplikowane. @@ -1096,9 +1096,9 @@ Hash poprzedniej wiadomości jest inny. Identyfikator następnej wiadomości jest nieprawidłowy (mniejszy lub równy poprzedniej). \nMoże się to zdarzyć z powodu jakiegoś błędu lub gdy połączenie jest skompromitowane. - Nie udało się odszyfrować %1$d wiadomości. + Nie udało się odszyfrować %1$d wiadomości. Ten błąd jest trwały dla tego połączenia, proszę o ponowne połączenie. - %1$d pominiętych wiadomości. + %1$d pominiętych wiadomości. Może się to zdarzyć, gdy Ty lub Twoje połączenie użyło starej kopii zapasowej bazy danych. Prosimy o zgłaszanie tego do deweloperów. Połączenia audio/wideo są zabronione. @@ -1163,7 +1163,7 @@ Otwórz profile czatu O adresie SimpleX 1-razowy link - Przeczytaj więcej w Podręczniku Użytkownika. + Podręczniku Użytkownika.]]> Adres SimpleX Kiedy ludzie proszą o połączenie, możesz je zaakceptować lub odrzucić. Nie stracisz kontaktów, jeśli później usuniesz swój adres. @@ -1267,4 +1267,21 @@ Powiadomienia przestaną działać do momentu ponownego uruchomienia aplikacji. Wyłączenie Wyłączyć\? + Przerwij zmianę adresu + Zmiana adresu zostanie przerwana. Użyty zostanie stary adres odbiorczy. + Błąd przerwania zmiany adresu + Przerwać zmianę adresu\? + Przerwij + Ulubione + Pliki i media + Pliki i media zabronione! + Pozwól na wysyłanie plików i mediów. + Brak filtrowanych czatów + Nieulubione + Członkowie grupy mogą wysyłać pliki i media. + Zakaz wysyłania plików i mediów. + Pliki i media są zabronione w tej grupie. + Tylko właściciele grup mogą włączać pliki i media. + Szukaj + Wyłączono \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-pt-rBR/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml similarity index 93% rename from apps/multiplatform/android/src/main/res/values-pt-rBR/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml index e12e60ac0a..ccd12968c1 100644 --- a/apps/multiplatform/android/src/main/res/values-pt-rBR/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pt-rBR/strings.xml @@ -1,6 +1,6 @@ - - Sobre o SimpleX Chat + + Sobre o SimpleX Chat Sobre o SimpleX 1 dia 1 semana @@ -14,7 +14,7 @@ Mudar Um perfil aleatório será enviado para o contato do qual você recebeu este link Você e seu contato podem excluir mensagens enviadas de forma irreversível. - Pode ser desativado nas configurações – as notificações ainda serão exibidas enquanto o aplicativo estiver em execução. + Pode ser desativado nas configurações – as notificações ainda serão exibidas enquanto o aplicativo estiver em execução.]]> Você e seu contato podem enviar mensagens de voz. O aplicativo pode receber notificações apenas quando estiver em execução, nenhum serviço em segundo plano será iniciado Sempre ativada @@ -25,8 +25,8 @@ Cancelar mensagem ao vivo Voltar Arquivo - Adicionar novo contato: para criar seu QR code de uso único para seu contato. - Escanear código QR: para se conectar ao seu contato que mostra o código QR para você. + Adicionar novo contato: para criar seu QR code de uso único para seu contato.]]> + Escanear código QR: para se conectar ao seu contato que mostra o código QR para você.]]> Aceitar Limpar chat\? Limpar @@ -44,13 +44,13 @@ Atender ligação hash de mensagem incorreto ID de mensagem incorreta - Observação: você NÃO poderá recuperar ou alterar a senha se a perder. + Observação: você NÃO poderá recuperar ou alterar a senha se a perder.]]> Não é possível receber o arquivo Cancelar visualização da imagem Botão Fechar Limpar verificação Versão do App - negrito + negrito erro de chamada Chamadas de áudio e vídeo Aceitar @@ -76,9 +76,9 @@ Cancelar Console de chat Verifique o endereço do servidor e tente novamente. - Uma conexão TCP separada (e credencial SOCKS) será usada para cada perfil de chat que você tiver no aplicativo. - Melhor para bateria. Você receberá notificações apenas quando o aplicativo estiver em execução (sem segundo plano). - Consome mais bateria! O serviço em segundo plano está sempre em execução - as notificações são exibidas assim que as mensagens estiverem disponíveis. + para cada perfil de chat que você tiver no aplicativo.]]> + Melhor para bateria. Você receberá notificações apenas quando o aplicativo estiver em execução (sem segundo plano).]]> + Consome mais bateria! O serviço em segundo plano está sempre em execução - as notificações são exibidas assim que as mensagens estiverem disponíveis.]]> CHATS ÍCONE DO APP BANCO DE DADOS DE CHAT @@ -95,8 +95,8 @@ O serviço em segundo plano está sempre em execução - as notificações serão exibidas assim que as mensagens estiverem disponíveis. Uma conexão TCP separada (e credencial SOCKS) será usada para cada contato e membro do grupo. \nObservação: se você tiver muitas conexões, o consumo de bateria e tráfego pode ser substancialmente maior e algumas conexões podem falhar. - Bom para bateria. O serviço em segundo plano procura por mensagens a cada 10 minutos. Você pode perder chamadas ou mensagens urgentes. - chamda encerrada %1$s + Bom para bateria. O serviço em segundo plano procura por mensagens a cada 10 minutos. Você pode perder chamadas ou mensagens urgentes.]]> + chamda encerrada %1$s Chat com os desenvolvedores Criar link de grupo Criar link @@ -206,7 +206,7 @@ Senha do banco de dados é diferente da salva na Keystore. completo ID do banco de dados - colorido + colorido conectado Conectado Conectado @@ -221,9 +221,9 @@ Conexão Erro de conexão (AUTH) conexão estabelecida - conexão %1$d - Criado em %1$s - Atualmente, o tamanho máximo de arquivo suportado é %1$s. + conexão %1$d + Criado em %1$s + Atualmente, o tamanho máximo de arquivo suportado é %1$s. Excluir Ssnha de criptografia do banco de dados será atualizada e armazenada na Keystore. Excluir endereço @@ -249,7 +249,7 @@ Por perfil de chat (padrão) ou por conexão (BETA). Aceitar anônimo Excluir mensagens após - 💻 desktop: Scaneie o código QR exibido no aplicativo, via Scan QR code + Scan QR code]]> Excluir conexão pendente\? Descrição Excluir servidor @@ -364,7 +364,7 @@ Grupo não encontrado! O grupo será excluído para você - isso não pode ser desfeito! Grupo - indireto (%1$s) + indireto (%1$s) Anônimo Mensagens que desaparecem Preferências de grupo @@ -393,21 +393,21 @@ Ocultar contato e mensagem Como usar Como usar markdown - Se você não puder se encontrar pessoalmente, mostre o código QR na videochamada ou compartilhe o link. - Se você não puder encontrar pessoalmente, você pode escanear o código QR na videochamada ou seu contato pode compartilhar um link de convite. + mostre o código QR na videochamada ou compartilhe o link.]]> + escanear o código QR na videochamada ou seu contato pode compartilhar um link de convite.]]> Se você confirmar, os servidores de mensagens poderão ver seu endereço IP e seu provedor - e quais servidores você está se conectando. Imagem - Se você recebeu o link de convite SimpleX Chat, você pode abri-lo em seu navegador: + Se você recebeu o link de convite SimpleX Chat, você pode abri-lo em seu navegador: Imagem salva na galeria O modo de navegação anônima não é suportado aqui - seu perfil principal será enviado aos membros do grupo anônimo via link do grupo Chamada de vídeo recebida - Para usá-lo, por favor desative a otimização da bateria para SimpleX na próxima caixa de diálogo. Caso contrário, as notificações serão desativadas. + desative a otimização da bateria para SimpleX na próxima caixa de diálogo. Caso contrário, as notificações serão desativadas.]]> Gerar um link de convite de uso único Arquivo não encontrado Se você optar por rejeitar o remetente NÃO será notificado. Código de segurança incorreto! - Instale o SimpleX para terminal + Instale o SimpleX para terminal Nome Completo (opcional) Como funciona Imune a spam e abuso @@ -430,7 +430,7 @@ O arquivo será recebido quando seu contato estiver online, aguarde ou verifique mais tarde! O perfil do grupo é armazenado nos dispositivos dos membros, não nos servidores. ajuda - Como SimpleX funciona + Como SimpleX funciona Servidores ICE (um por linha) Ignorar A imagem será recebida quando seu contato estiver online, aguarde ou verifique mais tarde! @@ -458,7 +458,7 @@ Escanear QR Code Rejeitar ofereceu %s - Endereço SimpleX + Endereço SimpleX ofereceu %s: %2s Cole o link que você recebeu na caixa abaixo para conectar com o seu contato. Novo em %s @@ -469,7 +469,7 @@ Restaurar o backup do banco de dados\? moderado O remetente cancelou a transferência de arquivos. - Por favor, cheque sua conexão com a rede com%1$s e tente de novo. + Por favor, cheque sua conexão com a rede com%1$s e tente de novo. Recebendo mensagens… Aruivo grande! Marcado como lido @@ -534,13 +534,13 @@ Convite expirado! Você deixará de receber mensagens deste grupo. O histórico do chat será preservado. removeu você - convidado%1$s + convidado%1$s você alterou o endereço para %s observador membro Sair do grupo - %1$s MEMBROS - você%1$s + %1$s MEMBROS + você%1$s Nome local Salvar perfil do grupo Intervalo de PING @@ -569,7 +569,7 @@ O remetente pode ter excluído a solicitação de conexão. Notificações periódicas estão desativadas! As notificações instantâneas estão desativadas! - Para preservar sua privacidade, em vez de notificações push, o aplicativo tem umSimpleXserviço em segundo plano - ele usa uma porcentagem da bateria por dia. + SimpleXserviço em segundo plano - ele usa uma porcentagem da bateria por dia.]]> Executa quando o aplicativo está aberto enviado o envio falhou @@ -604,9 +604,9 @@ Markdown em mensagens Servidores SMP Endereço do servidor pré-definido - Muitos perguntaram: se SimpleX não tem identificadores de usuários, como ele pode mandar mensagens\? + se SimpleX não tem identificadores de usuários, como ele pode mandar mensagens\?]]> Rejeitar - %1$d mensagens ignoradas + %1$d mensagens ignoradas Proteger a tela do app Enviar prévias de links Privacidade e segurança @@ -659,9 +659,9 @@ Os hosts Onion serão necessários para a conexão. Os hosts Onion serão necessários para a conexão. Versão principal: v%s - Leia mais no nosso repositório do GitHub. + repositório do GitHub.]]> Pode ser mudado mais tarde via configurações. - %1$s quer se conectar com você via + %1$s quer se conectar com você via sem criptografia ponta-a-ponta Abrir O servidor de relay é usado apenas se necessário. Terceiros podem observar seu endereço IP. @@ -674,7 +674,7 @@ Erro na restauração do banco de dados Abrir chat Salvar senha e abrir chat - removido%1$s + removido%1$s Tempo limite do protocolo recebido, proibido Ocultar @@ -687,7 +687,7 @@ VOCÊ MENSAGENS E ARQUIVOS Seu banco de dados de chat - Você removeu %1$s + Você removeu %1$s removido saiu proprietário @@ -740,8 +740,8 @@ Avalie o app IDs de banco de dados e opção de isolamento de transporte. O perfil é compartilhado apenas com seus contatos. - segredo - Itálico + segredo + Itálico chamada perdida Você pode usar markdown para formatar mensagens: chamada rejeitada @@ -762,7 +762,7 @@ Chamada perdida Salvar senha na Keystore Seu banco de dados de chat não está criptografado - defina uma senha para protegê-lo. - convite para o grupo%1$s + convite para o grupo%1$s Você esta usando um perfil anônimo para este grupo - para evitar compartilhar seu perfil principal, convidar contatos não é permitido Confirmação de migração inválida Migrações: %s @@ -793,7 +793,7 @@ Excesso de vídeos! Solicitou receber o vídeo Apenas 10 vídeos podem ser enviados ao mesmo tempo - Seu contato enviou um arquivo maior que o tamanho máximo permitido (%1$s). + Seu contato enviou um arquivo maior que o tamanho máximo permitido (%1$s). O arquivo será recebido quando seu contato concluir o upload. Alguns servidores falharam o teste: Salvar servidores @@ -820,7 +820,7 @@ Não Usar conexão direta com a internet\? Ocultar: - Seu perfil é guardado no seu diapositivo e é compartilhado somente com seus contatos. Servidores SimpleX não podem ver seu perfil. + Seu perfil é guardado no seu diapositivo e é compartilhado somente com seus contatos. Servidores SimpleX não podem ver seu perfil. Salvar preferências\? Salvar e notificar membros do grupo Erro ao salvar a senha do usuário @@ -841,7 +841,7 @@ Salvar Estrela no GitHub Seu contato precisa estar online para completar a conexão. Você pode cancelar esta conexão e remover o contato (e tentar mais tarde com um novo link). - SimpleX + SimpleX Somente o proprietários de grupo podem ativar mensagens de voz você compartilhou um link de uso único Você será conectado quando sua solicitação de conexão for aceita, aguarde ou verifique mais tarde! @@ -860,11 +860,11 @@ chamada de vídeo (não criptografada ponta-a-ponta) Parar chat\? Pelo navegador - Você já está conectado a%1$s. + Você já está conectado a%1$s. O banco de dados não está funcionando corretamente. Toque para saber mais Aguardando imagem Mostrar código QR - Você também pode se conectar clicando no link. Se abrir no navegador, clique em Abrir no aplicativo móvel. + Abrir no aplicativo móvel.]]> Servidores de teste Atualizar o modo de isolamento de transporte\? Vídeo ativado @@ -892,7 +892,7 @@ Para proteger o fuso horário, os arquivos de imagem/voz usam UTC. formato de mensagem desconhecido via link de grupo - via %1$s + via %1$s A menos que seu contato tenha excluído a conexão ou este link já tenha sido usado, pode ser um bug - por favor, relate-o. \nPara se conectar, peça ao seu contato para criar outro link de conexão e verifique se você tem uma conexão de rede estável. O teste falhou na etapa %s. @@ -908,9 +908,9 @@ Trocar O grupo é totalmente descentralizado – é visível apenas para os membros. você é um observador - Mensagem de voz (%1$s) + Mensagem de voz (%1$s) Compartilhar link - Para proteger a privacidade, em vez dos IDs de usuário usados por todas as outras plataformas, SimpleX tem identificadores para filas de mensagens, separados para cada um de seus contatos. + Para proteger a privacidade, em vez dos IDs de usuário usados por todas as outras plataformas, SimpleX tem identificadores para filas de mensagens, separados para cada um de seus contatos. chamada de vídeo Mostrar Servidores ICE WebRTC @@ -918,7 +918,7 @@ Atualizar O app busca novas mensagens periodicamente – ele usa alguns por cento da bateria por dia. O aplicativo não usa notificações por push – os dados do seu dispositivo não são enviados para os servidores. Para receber notificações, por favor, digite a senha do banco de dados - Serviço SimpleX + Serviço SimpleX Mostrar prévia Mostrar contato e mensagem Mostrar somente contato @@ -935,7 +935,7 @@ Mensagem de voz… Alterar endereço de recebimento\? Desmutar - Logo SimpleX + Logo SimpleX Esse link não é válido! Servidor de teste simplexmq: v%s (%2s) @@ -959,12 +959,12 @@ Mostrar Desmutar Mensagens de voz - Você pode se conectar aos desenvolvedores doSimpleX para fazer qualquer pergunta e receber atualizações. + se conectar aos desenvolvedores doSimpleX para fazer qualquer pergunta e receber atualizações.]]> A conexão que você aceitou será cancelada! O contato com o qual você compartilhou este link NÃO será capaz de se conectar! - Equipe SimpleX - Usar servidoresSimpleX\? - Usando servidores SimpleX. + Equipe SimpleX + Usar servidoresSimpleX\? + Usando servidores SimpleX. Mostrar opções para desenvolvedores Suporte bluetooth e outras melhorias. Para revelar seu perfil oculto, digite uma senha em um campo de busca em sua página de perfis de chat. @@ -973,7 +973,7 @@ Você rejeitou um convite de grupo não lida Compartilhar mensagem… - Bem-vindo%1$s! + Bem-vindo%1$s! você está convidado para o grupo Atualizar configuração de hosts .onion\? Usar chat @@ -997,7 +997,7 @@ Toque para ativar o perfil. Mostrar perfil de chat Mostrar perfil - Tentando se conectar ao servidor utilizado para receber mensagens deste contato (erro:%1$s). + Tentando se conectar ao servidor utilizado para receber mensagens deste contato (erro:%1$s). Tentando se conectar ao servidor utilizado para receber mensagens deste contato. Você está conectado ao servidor usado para receber mensagens desse contato. Seu servidor @@ -1017,13 +1017,13 @@ Endereço de contato Link do grupo Convite de uso único - 📱 móvel: toque em Abrir no aplicativo móvel e toque em Conectar no aplicativo. + Abrir no aplicativo móvel e toque em Conectar no aplicativo.]]> Chamadas Mensagens Bloqueio SimpleX Ajuda com Markdown Instantânea - Abrao chat do SimpleX para aceitar a chamada + Abrao chat do SimpleX para aceitar a chamada via relay desativado Desatualizar e abrir o chat @@ -1031,11 +1031,11 @@ APOIE SIMPLEX Esta ação não pode ser desfeita - as mensagens enviadas e recebidas antes do selecionado serão excluídas. Pode levar vários minutos. Confirme as atualizações do banco de dados - Perfis de usuário, contatos, grupos e mensagens enviadas com criptografia de ponta-a-ponta são armazenados somente no seu dispositivo. - Obrigado por instalar SimpleX! + criptografia de ponta-a-ponta são armazenados somente no seu dispositivo.]]> + Obrigado por instalar SimpleX! A plataforma de mensagens que protege sua privacidade e segurança. Você está tentando convidar um contato com quem compartilhou um perfil anônimo para o grupo no qual está usando seu perfil principal - Você controla por meio de qual(is) servidor(es) receber as mensagens, seus contatos controlam os servidores que você usa para enviar mensagens. + receber as mensagens, seus contatos controlam os servidores que você usa para enviar mensagens.]]> Fila segura imagem de perfil temporária Erro ao carregar servidores SMP @@ -1069,7 +1069,7 @@ Configurações de proxy SOCKS Usar proxy SOCKS Hospedar - Definir Usar hosts .onion para não se o proxy SOCKS não oferecer suporte a eles. + Usar hosts .onion para não se o proxy SOCKS não oferecer suporte a eles.]]> Migrar Confirmar senha Senha incorreta @@ -1088,7 +1088,7 @@ Você pode ativar o bloqueio SimpleX via Configurações. Hash de mensagem incorreta O hash da mensagem anterior é diferente. - descriptografia das mensagens falhou + %1$d descriptografia das mensagens falhou ID de mensagem incorreta A ID da próxima mensagem está incorreta (menor ou igual à anterior). \nIsso pode acontecer por causa de algum bug ou quando a conexão está comprometida. @@ -1105,7 +1105,7 @@ Revogar arquivo\? Sem espaços! Este erro é permanente para esta conexão, por favor, reconecte. - mensagens ignoradas + %1$d mensagens ignoradas Chamadas de áudio/vídeo Chamadas de áudio/vídeo são proibidas. " @@ -1173,7 +1173,7 @@ Prévia Secundária Importar tema - Leia mais em Guia do Usuário. + Guia do Usuário.]]> Digite a mensagem de boas-vindas... (opcional) Salvar configurações de aceitação automática Abrindo banco de dados… @@ -1259,4 +1259,6 @@ Se você digitar sua senha de auto-destruição ao abrir o aplicativo: Sem texto Alguns erros não-fatais ocurreram durante importação - pode ver o console de Chat para mais detalhes. + Pesquisar + Desativado \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-pt/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-pt/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml index 6c8bef2c55..3a1e5ba55d 100644 --- a/apps/multiplatform/android/src/main/res/values-pt/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/pt/strings.xml @@ -1,5 +1,5 @@ - + Código QR Colar Cole a ligação que você recebeu na caixa abaixo para se conectar ao seu contato. @@ -100,7 +100,7 @@ Você aceitou a conexão Sobre o SimpleX Definições de rede avançadas - Sobre o SimpleX Chat + Sobre o SimpleX Chat acima, então: Todas as conversas e mensagens serão apagadas - esta ação não pode ser revertida! Todos os membros do grupo permanecerão conectados. @@ -173,7 +173,7 @@ Mensagens de voz são proibidas neste chat. Mensagens de voz são proibidas neste grupo. Mensagens de voz proibidas! - Mensagem de voz (%1$s) + Mensagem de voz (%1$s) Versão da aplicação: v%s O Android Keystore é usado para armazenar com segurança a senha - permite que o serviço de notificações funcione. O Android Keystore será usado para armazenar com segurança a senha depois de voçê reiniciar a aplicação ou alterar a senha - irá permitir receber notificações. @@ -193,43 +193,43 @@ SERVIDORES O servidor requer autorização para fazer upload, verifique a senha Um perfil aleatório será enviado para o seu contato - Defina Usar hosts .onion como Não se o proxy SOCKS não o suportar. + Usar hosts .onion como Não se o proxy SOCKS não o suportar.]]> Usar hosts .onion Usar servidor Chamadas de áudio e vídeo Anexar Preservar o último rascunho da mensagem, com anexos. Solicitada a recepção do vídeo - Uma conexão TCP separada (e credencial SOCKS) será usada para cada perfil de conversa que você tiver na aplicação . + para cada perfil de conversa que você tiver na aplicação .]]> Uma conexão TCP separada (e credencial SOCKS) será usada para cada contato e membro do grupo. \n Por favor note: se você tiver muitas conexões, o seu consumo de bateria e consumo de tráfego pode ser substancialmente maior e algumas conexões podem falhar. Solicitada a recepção da imagem Autenticação indisponível - negrito + negrito Você e o seu contato podem eliminar irreversivelmente as mensagens enviadas. Você já tem um perfil de chat com o mesmo nome para exibição. Por favor, escolha outro nome. Você está convidado para o grupo - Você também se pode conectar clicando na ligação. Se ele abrir no navegador, clique no botão Abrir na aplicação móvel. + Abrir na aplicação móvel.]]> Você está convidado para o grupo. Junte-se para se conectar com os membros do grupo. Grupo Áudio ligado Autenticação cancelada - Adicionar novo contato: para criar o seu código QR de utilização única para o seu contato. - Bom para a bateria . O serviço em segundo plano verifica se há mensagens a cada 10 minutos. Você pode perder chamadas ou mensagens urgentes. + Adicionar novo contato: para criar o seu código QR de utilização única para o seu contato.]]> + Bom para a bateria . O serviço em segundo plano verifica se há mensagens a cada 10 minutos. Você pode perder chamadas ou mensagens urgentes.]]> A otimização da bateria está ativa, desativando o serviço em segundo plano e os pedidos periódicos de novas mensagens. Você pode reativá-los através das definições. - Melhor para a bateria. Apenas receberá notificações enquanto a app estiver em execução (SEM serviço em segundo plano) - Pode ser desativado nas definições – as notificações ainda serão exibidas enquanto a aplicação estiver em execução. - Consome mais bateria! O serviço em segundo plano está sempre em execução - as notificações serão exibidas assim que as mensagens estiverem disponíveis. + Melhor para a bateria. Apenas receberá notificações enquanto a app estiver em execução (SEM serviço em segundo plano)]]> + Pode ser desativado nas definições – as notificações ainda serão exibidas enquanto a aplicação estiver em execução.]]> + Consome mais bateria! O serviço em segundo plano está sempre em execução - as notificações serão exibidas assim que as mensagens estiverem disponíveis.]]> Chamadas de áudio e vídeo Áudio desligado - Por favor note : você NÃO será capaz de recuperar ou alterar a senha se a perder. + Por favor note : você NÃO será capaz de recuperar ou alterar a senha se a perder.]]> Chamadas de áudio/vídeo Tanto você como o seu contato podem enviar mensagens de voz. Chamadas de áudio/vídeo são proibidas. O serviço em segundo plano está sempre em execução - as notificações serão exibidas assim que as mensagens estiverem disponíveis. Autenticar - Leia o código QR : para se conectar ao seu contato que lhe mostra o código QR. - chamada finalizada %1$s + Leia o código QR : para se conectar ao seu contato que lhe mostra o código QR.]]> + chamada finalizada %1$s a chamar… erro de chamada chamada em curso @@ -278,7 +278,7 @@ Erro ao alterar função O contato permite Preferências de conversa - SimpleX + SimpleX m Conectar através da ligação de contato\? Conectar via convite de ligação\? @@ -334,7 +334,7 @@ Pedido de conexão enviado! Criar endereço Criar - colorido + colorido conectando… Conectando chamada conectando (aceite) @@ -361,13 +361,13 @@ Contribuir Copiar Versão principal: v%s - Criado a %1$s + Criado a %1$s Criar ligação de grupo Ligações de grupo conectando chamada… Conectar via ligação Erro de conexão - conexão %1$d + conexão %1$d O contato já existe Criar convite de ligação de utilização única Convite de ligação de utilização única @@ -382,10 +382,10 @@ você partilhou ligação anónima de utilização única Ligação de conexão inválida Salvar - Se você recebeu convite de ligação do SimpleX Chat, você pode abri-lo no seu navegador: + Se você recebeu convite de ligação do SimpleX Chat, você pode abri-lo no seu navegador: Toque para entrar em modo anónimo Salvar senha na Keystore - Se não se poderem encontrar pessoalmente, mostre o código QR na chamada de vídeo ou partilhe a ligação. + mostre o código QR na chamada de vídeo ou partilhe a ligação.]]> Salvar definições de aceitação automática Aceitar automaticamente Salvar e atualizar o perfil do grupo @@ -412,7 +412,7 @@ Contato e todas as mensagens serão eliminadas - esta acção não pode ser revertida! ligação de visualização de imagem Ligação inválida! - Leia mais em Guia de Utilizador. + Guia de Utilizador.]]> Conexão Crie um endereço para permitir que as pessoas se conectem consigo. Salvar e notificar contato @@ -433,7 +433,7 @@ Ligação para 1 utilização Criar ligação Apagar ligação\? - Se não puderem encontrar-se pessoalmente, você pode ler o código QR na chamada de vídeo , ou o seu contato pode partilhar um convite de ligação. + ler o código QR na chamada de vídeo , ou o seu contato pode partilhar um convite de ligação.]]> Se não se poderem encontrar pessoalmente, mostre o código QR numa chamada de vídeo ou partilhe a ligação. As pessoas podem se conectar a si apenas por meio das ligações que você partilhe. Verifique se você usou a ligação correta ou peça ao seu contato para enviar outra. @@ -441,7 +441,7 @@ Enviar pré-visualizações de ligações (ler ou colar da área de transferência) Partilhar ligação de utilização única - Leia mais no nosso repositório GitHub. + GitHub.]]> Criar perfil Criar perfil %d contato(s) selecionado(s) @@ -475,7 +475,7 @@ Criar fila Eliminar para mim Desabilitar o bloqueio do SimpleX - Atualmente o tamanho máximo de ficheiro suportado é %1$s. + Atualmente o tamanho máximo de ficheiro suportado é %1$s. Eliminar contato Criar grupo secreto Eliminar servidor @@ -493,7 +493,7 @@ Descentralizado mensagem duplicada Ficheiro: %s - você: %1$s + você: %1$s %ds %d seg %dw @@ -513,12 +513,12 @@ Você pode esconder ou silenciar um perfil de utilizador - pressione-o para o menu. Vídeo ligado Servidores XFTP - %1$s quer conectar-se consigo via + %1$s quer conectar-se consigo via Junte-se Sair Deixar o grupo\? esquerda - %1$s MEMBROS + %1$s MEMBROS Deixar o grupo sim via ligação de grupo @@ -538,23 +538,23 @@ Você deixará de receber mensagens deste grupo. O histórico de mensagens será preservado. Juntar-se ao grupo\? Com mensagem de boas-vindas opcional. - via %1$s - Já está conectado a %1$s. - SimpleX Chat service + via %1$s + Já está conectado a %1$s. + SimpleX Chat service Ficheiro grande! Imagem enviada - Você pode conectar-se com os desenvolvedores do SimpleX Chat para fazer quaisquer perguntas e receber atualizações. + conectar-se com os desenvolvedores do SimpleX Chat para fazer quaisquer perguntas e receber atualizações.]]> Imagem Vídeo - Endereço SimpleX - Equipa SimpleX + Endereço SimpleX + Equipa SimpleX Saiba mais Quando as pessoas solicitam conexão, você pode aceitá-la ou rejeitá-la. Você pode criá-lo mais tarde Vamos conversar no SimpleX Chat Vídeo desligado - %1$d mensagem(s) ignoradas - %1$d mensagens ignoradas. + %1$d mensagem(s) ignoradas + %1$d mensagens ignoradas. Importar base de dados As suas definições DEFINIÇÕES @@ -639,7 +639,7 @@ Pode acontecer quando você ou sua conexão usaram o backup de base de dados antigo. encriptado ponta a ponta desligado - 💻 desktop: leia o código QR exibido a partir do aplicação, via Ler código QR. + Ler código QR.]]> Sem espaços! contato não tem encriptação ponta a ponta oferecido %s: %2s @@ -658,7 +658,7 @@ Ler o código de segurança a partir da aplicação do seu contacto. Ler o código QR do servidor Hosts Onion não serão usados. - Apenas dispositivos cliente armazenam perfis de utilizador, contatos, grupos e mensagens enviadas com encriptação de ponta a ponta de 2 camadas. + encriptação de ponta a ponta de 2 camadas.]]> contato tem encriptação ponta a ponta sem encriptação ponta a ponta criador @@ -743,4 +743,6 @@ activado activado para contacto activado para si + Pesquisar + Desativado \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-ru/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml similarity index 93% rename from apps/multiplatform/android/src/main/res/values-ru/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml index 6ecbc40e9b..e7a82a1146 100644 --- a/apps/multiplatform/android/src/main/res/values-ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -1,6 +1,6 @@ - - SimpleX + + SimpleX т Соединиться через ссылку-контакт? @@ -14,7 +14,7 @@ ошибка соединяется Установлено соединение с сервером, через который Вы получаете сообщения от этого контакта. - Устанавливается соединение с сервером, через который Вы получаете сообщения от этого контакта (ошибка: %1$s). + Устанавливается соединение с сервером, через который Вы получаете сообщения от этого контакта (ошибка: %1$s). Устанавливается соединение с сервером, через который Вы получаете сообщения от этого контакта. удалено @@ -25,7 +25,7 @@ неизвестный формат сообщения неверный формат сообщения - connection %1$d + connection %1$d соединение установлено приглашение соединиться соединяется… @@ -41,7 +41,7 @@ SimpleX ссылка-контакт SimpleX одноразовая ссылка SimpleX ссылка группы - через %1$s + через %1$s SimpleX ссылки Описание Полная ссылка @@ -54,7 +54,7 @@ Превышено время соединения Ошибка соединения - Пожалуйста, проверьте Ваше соединение с сервером %1$s и попробуйте еще раз. + Пожалуйста, проверьте Ваше соединение с сервером %1$s и попробуйте еще раз. Ошибка при отправке сообщения Ошибка при добавлении членов группы Ошибка при вступлении в группу @@ -63,7 +63,7 @@ Ошибка при получении файла Ошибка при создании адреса Существующий контакт - Вы уже соединены с контактом %1$s. + Вы уже соединены с контактом %1$s. Ошибка в ссылке контакта Пожалуйста, проверьте, что Вы использовали правильную ссылку, или попросите Ваш контакт отправить Вам новую. Ошибка соединения (AUTH) @@ -88,9 +88,9 @@ Мгновенные уведомления Мгновенные уведомления! Мгновенные уведомления выключены! - Чтобы защитить Ваши личные данные, вместо уведомлений от сервера приложение запускает фоновый сервис SimpleX, который потребляет несколько процентов батареи в день. - Он может быть выключен через Настройки – Вы продолжите получать уведомления о сообщениях пока приложение запущено. - Для использования этой функции, пожалуйста, отключите оптимизацию батареи для SimpleX в следующем диалоге. Иначе уведомления будут выключены. + фоновый сервис SimpleX, который потребляет несколько процентов батареи в день.]]> + Он может быть выключен через Настройки – Вы продолжите получать уведомления о сообщениях пока приложение запущено.]]> + Для использования этой функции, пожалуйста, отключите оптимизацию батареи для SimpleX в следующем диалоге. Иначе уведомления будут выключены. Оптимизация батареи включена, поэтому сервис уведомлений выключен. Вы можете снова включить его через Настройки. Периодические уведомления Периодические уведомления выключены! @@ -100,7 +100,7 @@ Ошибка базы данных Ошибка при инициализации базы данных. Нажмите чтобы узнать больше - SimpleX Chat сервис + SimpleX Chat сервис Приём сообщений… Скрыть @@ -128,7 +128,7 @@ Соединен(а) Блокировка SimpleX - Чтобы защитить Вашу информацию, включите блокировку SimpleX Chat. + Чтобы защитить Вашу информацию, включите блокировку SimpleX Chat. \nВам будет нужно пройти аутентификацию для включения блокировки. Включить @@ -169,7 +169,7 @@ ошибка при отправке не прочитано - Здравствуйте %1$s! + Здравствуйте %1$s! Здравствуйте! Этот текст можно найти в Настройках Чаты @@ -204,8 +204,8 @@ Файл Большой файл! - Ваш контакт отправил файл, размер которого превышает поддерживаемый в настоящее время максимальный размер (%1$s). - В настоящее время максимальный поддерживаемый размер файла составляет %1$s. + Ваш контакт отправил файл, размер которого превышает поддерживаемый в настоящее время максимальный размер (%1$s). + В настоящее время максимальный поддерживаемый размер файла составляет %1$s. Ожидается прием файла Файл будет принят, когда Ваш контакт будет в сети, подождите или проверьте позже! Файл сохранен @@ -213,7 +213,7 @@ Ошибка сохранения файла Голосовое сообщение - Голосовое сообщение (%1$s) + Голосовое сообщение (%1$s) Голосовое сообщение… Уведомления @@ -262,17 +262,17 @@ Видео Файл - Спасибо, что установили SimpleX Chat! - Вы можете соединиться с разработчиками, чтобы задать любые вопросы или получать уведомления о новых версиях. + Спасибо, что установили SimpleX Chat! + соединиться с разработчиками, чтобы задать любые вопросы или получать уведомления о новых версиях.]]> Чтобы начать новый чат Нажмите кнопку сверху, затем: - Добавить новый контакт: чтобы создать одноразовый QR код/ссылку для Вашего контакта. - Сканировать QR код: чтобы соединиться с контактом, который показывает Вам QR код. + Добавить новый контакт: чтобы создать одноразовый QR код/ссылку для Вашего контакта.]]> + Сканировать QR код: чтобы соединиться с контактом, который показывает Вам QR код.]]> Чтобы соединиться через ссылку - Если Вы получили ссылку с приглашением из SimpleX Chat, Вы можете открыть ее в браузере: - 💻 на компьютере: сосканируйте показанный QR код из приложения через Сканировать QR код. - 📱 на мобильном: намжите кнопку Open in mobile app на веб странице, затем нажмите Соединиться в приложении. + Если Вы получили ссылку с приглашением из SimpleX Chat, Вы можете открыть ее в браузере: + Сканировать QR код.]]> + Open in mobile app на веб странице, затем нажмите Соединиться в приложении.]]> Принять запрос на соединение? Отправителю НЕ будет послано уведомление, если Вы отклоните запрос на соединение. @@ -313,10 +313,10 @@ удалить превью ссылки Настройки QR код - SimpleX адрес + SimpleX адрес Помощь - SimpleX команда - SimpleX логотип + SimpleX команда + SimpleX логотип Email Больше @@ -330,10 +330,10 @@ Соединение с группой будет установлено, когда хост группы будет онлайн. Пожалуйста, подождите или проверьте позже! Соединение будет установлено, когда Ваш запрос будет принят. Пожалуйста, подождите или проверьте позже! Соединение будет установлено, когда Ваш контакт будет онлайн. Пожалуйста, подождите или проверьте позже! - Если Вы не можете встретиться лично, Вы можете показать QR код во время видеозвонка или поделиться ссылкой. + показать QR код во время видеозвонка или поделиться ссылкой.]]> Ваш профиль будет отправлен \nВашему контакту - Если Вы не можете встретиться лично, Вы можете сосканировать QR код во время видеозвонка, или Ваш контакт может отправить Вам ссылку. + сосканировать QR код во время видеозвонка, или Ваш контакт может отправить Вам ссылку.]]> Поделиться одноразовой ссылкой Чтобы соединиться, вставьте в это поле ссылку, полученную от Вашего контакта. Ваш профиль будет отправлен Вашему контакту @@ -347,7 +347,7 @@ Настройки Ваш адрес SimpleX Пароль и экспорт базы - Информация о SimpleX Chat + Информация о SimpleX Chat Как использовать Форматирование сообщений Форматирование сообщений @@ -375,13 +375,13 @@ Ошибка в адресе сервера! Проверьте адрес сервера и попробуйте снова. Удалить сервер - SimpleX Chat для терминала + SimpleX Chat для терминала Поставить звездочку в GitHub Внести свой вклад Оценить приложение - Использовать серверы предосталенные SimpleX Chat? + Использовать серверы предосталенные SimpleX Chat? Ваши SMP серверы - Используются серверы предоставленные SimpleX Chat. + Используются серверы предоставленные SimpleX Chat. Инфо Как использовать серверы Сохраненные WebRTC ICE серверы будут удалены. @@ -420,7 +420,7 @@ Имя профиля: "Полное имя: Ваш активный профиль - Ваш профиль хранится на Вашем устройстве и отправляется только Вашим контактам. SimpleX серверы не могут получить доступ к Вашему профилю. + Ваш профиль хранится на Вашем устройстве и отправляется только Вашим контактам. SimpleX серверы не могут получить доступ к Вашему профилю. Поменять аватар Удалить аватар Сохранить предпочтения? @@ -443,15 +443,15 @@ Как форматировать Вы можете форматировать сообщения: - жирный - курсив - зачеркнуть + жирный + курсив + зачеркнуть a + b - цвет - секрет + цвет + секрет Соединиться через ссылку Эта строка не является ссылкой-приглашением! - Вы также можете соединиться, открыв ссылку там, где Вы её получили. Если ссылка откроется в браузере, нажмите кнопку Открыть в приложении. + Открыть в приложении.]]> входящий звонок… пропущенный звонок @@ -459,7 +459,7 @@ принятый звонок звонок соединяется… активный звонок - звонок завершён %1$s + звонок завершён %1$s ошибка звонка инициализация… @@ -482,13 +482,13 @@ Добавьте контакт Как это работает - Как SimpleX работает - Много пользователей спросили: как SimpleX доставляет сообщения без идентификаторов пользователей? - Чтобы защитить Вашу конфиденциальность, вместо ID пользователей, которые есть в других платформах, SimpleX использует ID для очередей сообщений, разные для каждого контакта. - Вы определяете через какие серверы Вы получаете сообщения, Ваши контакты - серверы, которые Вы используете для отправки. - Только пользовательские устройства хранят контакты, группы и сообщения, которые отправляются с двухуровневым end-to-end шифрованием. + Как SimpleX работает + как SimpleX доставляет сообщения без идентификаторов пользователей?]]> + Чтобы защитить Вашу конфиденциальность, вместо ID пользователей, которые есть в других платформах, SimpleX использует ID для очередей сообщений, разные для каждого контакта. + получаете сообщения, Ваши контакты - серверы, которые Вы используете для отправки.]]> + с двухуровневым end-to-end шифрованием.]]> Узнайте больше из нашего GitHub репозитория. - Узнайте больше из нашего GitHub репозитория. + GitHub репозитория.]]> Использовать чат @@ -496,7 +496,7 @@ Входящий видеозвонок Входящий аудиозвонок - %1$s хочет связаться с Вами через + %1$s хочет связаться с Вами через видеозвонок (не e2e зашифрованный) e2e зашифрованный видеозвонок аудиозвонок (не e2e зашифрованный) @@ -520,7 +520,7 @@ Relay сервер защищает Ваш IP адрес, но может отслеживать продолжительность звонка. Relay сервер используется только при необходимости. Другая сторона может видеть Ваш IP адрес. - Откройте SimpleX Chat\nчтобы принять звонок + Откройте SimpleX Chat\nчтобы принять звонок Вы можете разрешить принимать звонки на экране блокировки через Настройки. Открыть @@ -547,7 +547,7 @@ Звонок завершен Принять звонок - %1$d пропущенных сообщений + %1$d пропущенных сообщений ошибка хэш сообщения ошибка ID сообщения повторное сообщение @@ -645,7 +645,7 @@ База данных НЕ зашифрована. Установите пароль, чтобы защитить Ваши данные. Android Keystore используется для безопасного хранения пароля - это позволяет стабильно получать уведомления в фоновом режиме. База данных зашифрована случайным паролем, Вы можете его поменять. - Внимание: Вы не сможете восстановить или поменять пароль, если потеряете его. + Внимание: Вы не сможете восстановить или поменять пароль, если потеряете его.]]> Пароль базы данных будет безопасно сохранен в Android Keystore после запуска чата или изменения пароля - это позволит стабильно получать уведомления. Пароль не сохранен на устройстве — Вы будете должны ввести его при каждом запуске чата. Зашифровать базу данных? @@ -688,10 +688,10 @@ АРХИВ ЧАТА Сохранить архив Удалить архив - Дата создания %1$s + Дата создания %1$s Удалить архив чата? - приглашение в группу %1$s + приглашение в группу %1$s Вступить в группу? Вы приглашены в группу. Вступите, чтобы соединиться с членами группы. Вступить @@ -718,19 +718,19 @@ Вы отклонили приглашение в группу Приглашение в группу истекло - пригласил(а) %1$s + пригласил(а) %1$s соединен(а) покинул(а) группу поменял(а) роль члена %s на: %s поменял(а) Вашу роль на: %s - удалил(а) %1$s + удалил(а) %1$s удалил(а) Вас из группы удалил(а) группу обновил(а) профиль группы приглашен(а) через Вашу ссылку группы Вы поменяли роль члена %s на: %s Вы поменяли роль себе на: %s - Вы удалили %1$s + Вы удалили %1$s Вы покинули группу профиль группы обновлен @@ -772,8 +772,8 @@ Вы пытаетесь пригласить инкогнито контакт в группу, где Вы используете свой основной профиль Пригласить членов группы - ЧЛЕНОВ ГРУППЫ: %1$s - Вы: %1$s + ЧЛЕНОВ ГРУППЫ: %1$s + Вы: %1$s Удалить группу Удалить группу? Группа будет удалена для всех членов - это действие нельзя отменить! @@ -811,7 +811,7 @@ Группа Соединение прямое - непрямое (%1$s) + непрямое (%1$s) СЕРВЕРЫ Получение через @@ -907,13 +907,13 @@ Необратимое удаление сообщений запрещено в этой группе. Члены группы могут отправлять голосовые сообщения. Голосовые сообщения запрещены в этой группе. - Минимальный расход батареи. Вы получите уведомления только когда приложение запущено, без фонового сервиса. + Минимальный расход батареи. Вы получите уведомления только когда приложение запущено, без фонового сервиса.]]> Уведомления Когда приложение запущено Периодически Мгновенно - Больше расход батареи! Фоновый сервис постоянно запущен - уведомления будут показаны как только есть сообщения. - Меньше расход батареи. Фоновый сервис проверяет сообщения каждые 10 минут. Вы можете пропустить звонки и срочные сообщения. + Больше расход батареи! Фоновый сервис постоянно запущен - уведомления будут показаны как только есть сообщения.]]> + Меньше расход батареи. Фоновый сервис проверяет сообщения каждые 10 минут. Вы можете пропустить звонки и срочные сообщения.]]> Можно изменить позже в настройках. LIVE Отправить живое сообщение @@ -1012,7 +1012,7 @@ Версия приложения: v%s Отдельное TCP-соединение (и авторизация SOCKS) будет использоваться для каждого контакта и члена группы. \nОбратите внимание: если у Вас много контактов, потребление батареи и трафика может быть значительно выше, и некоторые соединения могут не работать. - Отдельное TCP-соединение (и авторизация SOCKS) будет использоваться для каждого профиля чата, который Вы имеете в приложении. + для каждого профиля чата, который Вы имеете в приложении.]]> Версия ядра: v%s Удалить профиль чата\? Удалить профиль чата для @@ -1135,7 +1135,7 @@ Загрузка файла XFTP серверы Ваши XFTP серверы - Установите Использовать .onion хосты в Нет если SOCKS прокси их не поддерживает. + Использовать .onion хосты в Нет если SOCKS прокси их не поддерживает.]]> Ошибка аутентификации Нет кода доступа Ввод кода доступа @@ -1156,7 +1156,7 @@ Аутентификация отменена Системная %d секунд - %1$d сообщений не удалось расшифровать. + %1$d сообщений не удалось расшифровать. Ошибка расшифровки Блокировка SimpleX не включена! Ошибка хэш сообщения @@ -1185,7 +1185,7 @@ Неправильный ID предыдущего сообщения (меньше или равен предыдущему). \nЭто может произойти из-за ошибки программы, или когда соединение компроментировано. Эта ошибка постоянная для этого соединения, пожалуйста, соединитесь снова. - %1$d сообщений пропущено. + %1$d сообщений пропущено. Разрешить звонки, только если их разрешает Ваш контакт. Разрешить Вашим контактам звонить Вам. Аудио/видео звонки @@ -1272,7 +1272,7 @@ Чтобы соединиться с Вами, Ваш контакт может отсканировать QR-код или использовать ссылку в приложении. Вы не потеряете контакты, если позже удалите Ваш адрес. Вы можете поделиться своим адресом в виде ссылки или QR-кода - любой может соединиться с Вами. - Узнать больше в Руководстве пользователя. + Руководстве пользователя.]]> Ваши контакты сохранятся. Настроить тему Создайте адрес, чтобы можно было соединиться с Вами. @@ -1344,4 +1344,6 @@ Запись обновлена Во время импорта произошли некоторые ошибки - для получения более подробной информации вы можете обратиться к консоли. нет текста + Поиск + Отключено \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-th/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml similarity index 93% rename from apps/multiplatform/android/src/main/res/values-th/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml index f19d43a145..3f704f2a9f 100644 --- a/apps/multiplatform/android/src/main/res/values-th/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/th/strings.xml @@ -1,11 +1,11 @@ - + 1 นาที 30 วินาที ด้านบน, จากนั้น: รับ ยอมรับโหมดไม่ระบุตัวตน - เกี่ยวกับ SimpleX Chat + เกี่ยวกับ SimpleX Chat รับสาย รับ 1 สัปดาห์ @@ -33,9 +33,8 @@ ลักษณะ โปรไฟล์แบบสุ่มจะถูกส่งไปยังผู้ติดต่อที่คุณได้รับลิงก์นี้จาก โปรไฟล์แบบสุ่มจะถูกส่งไปยังผู้ติดต่อของคุณ - การเชื่อมต่อ TCP (และข้อมูลรับรอง SOCKS) แบบแยกต่างหาก จะถูกใช้ สําหรับแต่ละโปรไฟล์แชทที่คุณมีในแอป - การเชื่อมต่อ TCP (และข้อมูลรับรอง SOCKS) แบบแยกต่างหาก จะถูกใช้ <b> สําหรับผู้ติดต่อแต่ละคนและสมาชิกกลุ่มแต่ละคน </b> -\n</b>โปรดทราบ </b>: หากคุณมีการเชื่อมต่อจํานวนมากแบตเตอรี่และปริมาณการใช้การจราจรของคุณอาจสูงขึ้นอย่างมากและการเชื่อมต่อบางอย่างอาจล้มเหลว + สําหรับแต่ละโปรไฟล์แชทที่คุณมีในแอป ]]> + การเชื่อมต่อ TCP (และข้อมูลรับรอง SOCKS) แบบแยกต่างหาก จะถูกใช้ สําหรับผู้ติดต่อแต่ละคนและสมาชิกกลุ่มแต่ละคน \nโปรดทราบ : หากคุณมีการเชื่อมต่อจํานวนมากแบตเตอรี่และปริมาณการใช้การจราจรของคุณอาจสูงขึ้นอย่างมากและการเชื่อมต่อบางอย่างอาจล้มเหลว แนบ การโทรด้วยเสียงและวิดีโอ ยอมรับอัตโนมัติ @@ -105,28 +104,28 @@ ทั้งคุณและผู้ติดต่อของคุณสามารถส่งข้อความเสียงได้ การโทรล้มเหลว ตามโปรไฟล์แชท (การตั้งค่าเริ่มต้น) หรือโดยการเชื่อมต่อ (เบต้า) - สิ้นสุดการโทร %1$s + สิ้นสุดการโทร %1$s กําลังโทร โทร การเพิ่มประสิทธิภาพแบตเตอรี่ทํางานอยู่ บริการพื้นหลังและคําขอข้อความใหม่เป็นระยะจะถูกปิด คุณสามารถเปิดใช้งานอีกครั้งผ่านการตั้งค่า - ดีที่สุดสําหรับแบตเตอรี่ คุณจะได้รับการแจ้งเตือนเฉพาะเมื่อแอปกําลังทํางานอยู่ (ไม่มีบริการพื้นหลัง) - ดีสำหรับแบตเตอรี่ บริการพื้นหลังจะตรวจสอบข้อความทุกๆ 10 นาที คุณอาจไม่ได้รับสายหรือข้อความด่วน - สามารถปิดใช้งานผ่านการตั้งค่า - การแจ้งเตือนจะยังคงปรากฏขึ้นในขณะที่แอปกําลังทํางานอยู่ + ดีที่สุดสําหรับแบตเตอรี่ คุณจะได้รับการแจ้งเตือนเฉพาะเมื่อแอปกําลังทํางานอยู่ (ไม่มีบริการพื้นหลัง)]]> + ดีสำหรับแบตเตอรี่ บริการพื้นหลังจะตรวจสอบข้อความทุกๆ 10 นาที คุณอาจไม่ได้รับสายหรือข้อความด่วน]]> + สามารถปิดใช้งานผ่านการตั้งค่า - การแจ้งเตือนจะยังคงปรากฏขึ้นในขณะที่แอปกําลังทํางานอยู่]]> ทั้งคุณและผู้ติดต่อของคุณสามารถเพิ่มปฏิกิริยาของข้อความได้ ทั้งคุณและผู้ติดต่อของคุณสามารถลบข้อความที่ส่งแล้วอย่างถาวรได้ กล้อง - เพิ่มผู้ติดต่อใหม่ : เพื่อสร้างรหัส QR แบบใช้ครั้งเดียวสําหรับผู้ติดต่อของคุณ - สแกนรหัส QR: เพื่อเชื่อมต่อกับผู้ติดต่อที่แสดงรหัส QR ให้คุณ + เพิ่มผู้ติดต่อใหม่ : เพื่อสร้างรหัส QR แบบใช้ครั้งเดียวสําหรับผู้ติดต่อของคุณ]]> + สแกนรหัส QR: เพื่อเชื่อมต่อกับผู้ติดต่อที่แสดงรหัส QR ให้คุณ]]> เกี่ยวกับที่อยู่ SimpleX - ตัวหนา + ตัวหนา กำลังโทร… กําลังโทร - ใช้แบตเตอรี่มากขึ้น ! บริการพื้นหลังจะทํางานเสมอ - การแจ้งเตือนจะปรากฏขึ้นทันทีที่มีข้อความ + ใช้แบตเตอรี่มากขึ้น ! บริการพื้นหลังจะทํางานเสมอ - การแจ้งเตือนจะปรากฏขึ้นทันทีที่มีข้อความ]]> สิ้นสุดการโทรแล้ว! โทรบนหน้าจอล็อค: สิ้นสุดการโทร ID ข้อความที่ไม่ดี - โปรดทราบ: คุณจะไม่สามารถกู้คืนหรือเปลี่ยนรหัสผ่านได้หากคุณทำรหัสผ่านหาย + โปรดทราบ: คุณจะไม่สามารถกู้คืนหรือเปลี่ยนรหัสผ่านได้หากคุณทำรหัสผ่านหาย]]> พื้นหลัง ทั้งคุณและผู้ติดต่อของคุณสามารถส่งข้อความที่หายไปได้ ทั้งคุณและผู้ติดต่อของคุณสามารถโทรออกได้ @@ -166,8 +165,8 @@ หมดเวลาการเชื่อมต่อ เชื่อมต่อผ่านลิงค์กลุ่ม\? ผู้ติดต่อและข้อความทั้งหมดจะถูกลบ - ไม่สามารถยกเลิกได้! - สร้างเมื่อ %1$s - ขนาดไฟล์สูงสุดที่รองรับในปัจจุบันคือ %1$s + สร้างเมื่อ %1$s + ขนาดไฟล์สูงสุดที่รองรับในปัจจุบันคือ %1$s ธีมที่กำหนดเอง ID ฐานข้อมูลและตัวเลือกการแยกการส่งผ่าน ID ฐานข้อมูล @@ -177,7 +176,7 @@ เชื่อมต่อผ่านลิงค์เชิญ\? กำลังเชื่อมต่อ… สร้างการเชื่อมต่อแล้ว - การเชื่อมต่อ %1$d + การเชื่อมต่อ %1$d ผู้ติดต่อรายนี้มีอยู่แล้ว การเชื่อมต่อล้มเหลว (AUTH) เปรียบเทียบไฟล์ @@ -224,7 +223,7 @@ ดำเนินการต่อ สร้าง สร้างโปรไฟล์ - มีสี + มีสี กําลังเชื่อมต่อสาย… เชื่อมต่อสำเร็จ กำลังเชื่อมต่อ… @@ -351,7 +350,7 @@ ข้อความหายไป ไฟล์ จากแกลเลอรี - 💻 เดสก์ท็อป: สแกนรหัส QR ที่แสดงอยู่บนแอปผ่าน สแกนรหัส QR + สแกนรหัส QR ]]> ล้างแชท ลบ ลบ @@ -387,7 +386,7 @@ วิธีใช้มาร์กดาวน์ สิ้นสุดลงแล้ว มันทำงานอย่างไร - วิธีการ SimpleX ทํางานอย่างไร + วิธีการ SimpleX ทํางานอย่างไร กระจายอำนาจ การโทรเสียงแบบ encrypt จากต้นจนจบ การโทรวิดีแบบ encrypt จากต้นจนจบ @@ -531,15 +530,15 @@ เกิดข้อผิดพลาดในการรับไฟล์ หากคุณใส่รหัสผ่านนี้เมื่อเปิดแอป ข้อมูลแอปทั้งหมดจะถูกลบอย่างถาวร! หากคุณเลือกที่จะปฏิเสธ ผู้ส่งจะไม่ได้รับแจ้ง - หากคุณไม่สามารถพบกันในชีวิตจริงได้ คุณสามารถสแกนคิวอาร์โค้ดในวิดีโอคอล </b> หรือผู้ติดต่อของคุณสามารถแชร์ลิงก์เชิญได้ - หากคุณไม่สามารถพบกันในชีวิตจริงได้ ให้แสดงคิวอาร์โค้ดในวิดีโอคอล หรือแชร์ลิงก์ + หรือผู้ติดต่อของคุณสามารถแชร์ลิงก์เชิญได้]]> + ให้แสดงคิวอาร์โค้ดในวิดีโอคอล หรือแชร์ลิงก์]]> หากคุณไม่สามารถพบกันในชีวิตจริงได้ ให้แสดงคิวอาร์โค้ดในวิดีโอคอล หรือแชร์ลิงก์ หากคุณยืนยัน เซิร์ฟเวอร์การส่งข้อความจะสามารถเห็นที่อยู่ IP ของคุณและผู้ให้บริการของคุณ - ซึ่งคือเซิร์ฟเวอร์ใดที่คุณกำลังเชื่อมต่ออยู่ หากคุณใส่รหัสทำลายตัวเองขณะเปิดแอป: ไม่รองรับโหมดไม่ระบุตัวตนที่นี่ - โปรไฟล์หลักของคุณจะถูกส่งไปยังสมาชิกกลุ่ม โหมดไม่ระบุตัวตนปกป้องความเป็นส่วนตัวของชื่อและรูปภาพโปรไฟล์หลักของคุณ — สำหรับผู้ติดต่อใหม่แต่ละราย จะมีการสร้างโปรไฟล์ใหม่แบบสุ่ม - ทางอ้อม (%1$s) - ติดตั้ง SimpleX Chat สำหรับเทอร์มินัล + ทางอ้อม (%1$s) + ติดตั้ง SimpleX Chat สำหรับเทอร์มินัล มันสามารถเกิดขึ้นได้เมื่อ: \n1. ข้อความหมดอายุในไคลเอนต์ที่ส่งหลังจาก 2 วันหรือบนเซิร์ฟเวอร์หลังจาก 30 วัน \n2. การถอดรหัสข้อความล้มเหลว เนื่องจากคุณหรือผู้ติดต่อของคุณใช้การสำรองฐานข้อมูลเก่า @@ -558,7 +557,7 @@ การแจ้งเตือนทันที แจ้งเตือนทันที! ปิดการแจ้งเตือนทันทีแล้ว! - เพื่อให้สามารถใช้งานได้ โปรด <b xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">ปิดการใช้งานการเพิ่มประสิทธิภาพแบตเตอรี่</b> สำหรับ <xliff:g xmlns:xliff=\"urn:oasis: ชื่อ:tc:xliff:document:1.2\" id=\"appName\">SimpleX</xliff:g> ในกล่องโต้ตอบถัดไป มิฉะนั้น การแจ้งเตือนจะถูกปิดใช้งาน + ปิดการใช้งานการเพิ่มประสิทธิภาพแบตเตอรี่ สำหรับ SimpleX ในกล่องโต้ตอบถัดไป มิฉะนั้น การแจ้งเตือนจะถูกปิดใช้งาน]]> โดยทันที เข้าสู่ระบบโดยใช้ข้อมูลประจำตัวของคุณ ข้อมูล @@ -571,7 +570,7 @@ ไฟล์ขนาดใหญ่! ข้อความสด! ภาพ - หากคุณได้รับลิงก์เชิญ SimpleX Chat คุณสามารถเปิดได้ในเบราว์เซอร์ของคุณ: + หากคุณได้รับลิงก์เชิญ SimpleX Chat คุณสามารถเปิดได้ในเบราว์เซอร์ของคุณ: ภาพตัวอย่างลิงค์ รหัส QR ไม่ถูกต้อง ลิงค์ไม่ถูกต้อง! @@ -580,7 +579,7 @@ ที่อยู่เซิร์ฟเวอร์ไม่ถูกต้อง! เชิญเพื่อน ๆ มาพูดคุยกันใน SimpleX Chat - ตัวเอียง + ตัวเอียง ป้องกันจากสแปมและการละเมิด สร้างการเชื่อมต่อส่วนตัว สามารถเปลี่ยนแปลงได้ในภายหลังผ่านการตั้งค่า @@ -599,7 +598,7 @@ ข้อผิดพลาดของ Keychain เวอร์ชันฐานข้อมูลที่เข้ากันไม่ได้ การยืนยันการย้ายไม่ถูกต้อง - คำเชิญเข้าร่วมกลุ่ม %1$s + คำเชิญเข้าร่วมกลุ่ม %1$s เข้าร่วม เข้าร่วมกลุ่ม\? กำลังจะเข้าร่วมกลุ่ม @@ -607,7 +606,7 @@ ออกจากกลุ่ม\? คำเชิญหมดอายุแล้ว! เชิญสมาชิก - เชิญแล้ว %1$s + เชิญแล้ว %1$s ออกแล้ว เชิญผ่านลิงค์กลุ่มของคุณ เชิญ @@ -684,12 +683,12 @@ สายที่ไม่ได้รับ ผู้คนสามารถเชื่อมต่อกับคุณผ่านลิงก์ที่คุณแบ่งปันเท่านั้น โปรโตคอลและโค้ดโอเพ่นซอร์ส – ใคร ๆ ก็สามารถเปิดใช้เซิร์ฟเวอร์ได้ - เฉพาะอุปกรณ์ไคลเอ็นต์เท่านั้นที่จัดเก็บโปรไฟล์ผู้ใช้ ผู้ติดต่อ กลุ่ม และข้อความที่ส่งด้วย การเข้ารหัสแบบ encrypted จากต้นจนจบ 2 ชั้น + การเข้ารหัสแบบ encrypted จากต้นจนจบ 2 ชั้น]]> เป็นระยะ แปะลิงก์ที่ได้รับ ไม่มีการ encrypt จากต้นจนจบ เปิด - เปิด SimpleX Chat เพื่อรับสาย + เปิด SimpleX Chat เพื่อรับสาย เพื่อนต่อเพื่อน รอสาย สายที่ไม่ได้รับ @@ -760,24 +759,24 @@ ปฏิกิริยาของข้อความ นาที เดือน - 📱 มือถือ: แตะ เปิดในแอปมือถือ จากนั้นแตะ เชื่อมต่อ ในแอป + เปิดในแอปมือถือ จากนั้นแตะ เชื่อมต่อ ในแอป]]> กลั่นกรองโดย %s เป็นไปได้มากว่าผู้ติดต่อนี้ได้ลบการเชื่อมต่อกับคุณ ข้อผิดพลาดในการส่งข้อความ ตรวจสอบให้แน่ใจว่าที่อยู่เซิร์ฟเวอร์ SMP อยู่ในรูปแบบที่ถูกต้อง แยกบรรทัดและไม่ซ้ำกัน - หลายคนถามว่า: ถ้า SimpleX ไม่มีตัวระบุผู้ใช้ จะส่งข้อความได้อย่างไร\? + ถ้า SimpleX ไม่มีตัวระบุผู้ใช้ จะส่งข้อความได้อย่างไร\?]]> โฮสต์หัวหอมจะถูกใช้เมื่อมี ผู้ติดต่อของคุณเท่านั้นที่สามารถส่งข้อความเสียงได้ การเปิดลิงก์ในเบราว์เซอร์อาจลดความเป็นส่วนตัวและความปลอดภัยของการเชื่อมต่อ ลิงก์ SimpleX ที่ไม่น่าเชื่อถือจะเป็นสีแดง โปรดตรวจสอบว่าคุณใช้ลิงก์ที่ถูกต้องหรือขอให้ผู้ติดต่อของคุณส่งลิงก์ใหม่ให้คุณ - โปรดตรวจสอบการเชื่อมต่อเครือข่ายของคุณกับ %1$s แล้วลองอีกครั้ง + โปรดตรวจสอบการเชื่อมต่อเครือข่ายของคุณกับ %1$s แล้วลองอีกครั้ง โปรดอัปเดตแอปและติดต่อนักพัฒนาแอป อาจเป็นไปได้ว่าลายนิ้วมือของ certificate ในที่อยู่เซิร์ฟเวอร์ไม่ถูกต้อง ได้รับข้อความ ตัวยึดตำแหน่งรูปโปรไฟล์ รูปโปรไฟล์ คิวอาร์โค้ด - อ่านเพิ่มเติมใน คู่มือผู้ใช้ + คู่มือผู้ใช้ ]]> ที่อยู่เซิร์ฟเวอร์ที่ตั้งไว้ล่วงหน้า เซิร์ฟเวอร์ที่ตั้งไว้ล่วงหน้า ให้คะแนนแอป @@ -786,7 +785,7 @@ ได้รับคำตอบ… ได้รับการยืนยัน… นิยามความเป็นส่วนตัวใหม่ - อ่านเพิ่มเติมใน GitHub repository ของเรา + GitHub repository ของเรา]]> อ่านเพิ่มเติมใน GitHub repository ของเรา การแจ้งเตือนส่วนตัว โปรดรายงานไปยังผู้พัฒนาแอป @@ -852,7 +851,7 @@ คืนค่าฐานข้อมูลสำรองไหม\? กู้คืนข้อผิดพลาดของฐานข้อมูล บันทึกไฟล์เก็บถาวร - ลบแล้ว %1$s + ลบแล้ว %1$s ลบคุณออกแล้ว ถูกลบแล้ว บันทึกถูกอัปเดตเมื่อ @@ -877,7 +876,7 @@ บันทึกการตั้งค่า\? วินาที รหัสผ่านแบบทําลายตัวเอง - ความลับ + ความลับ การประเมินความปลอดภัย เปิดใช้งานรหัสผ่านแบบทําลายตัวเองแล้ว! ส่ง @@ -928,7 +927,7 @@ สแกนรหัส QR ของเซิร์ฟเวอร์ บันทึกเซิร์ฟเวอร์\? เซิร์ฟเวอร์ WebRTC ICE ที่บันทึกไว้จะถูกลบออก - ตั้งค่า ใช้โฮสต์ .onion เป็น ไม่ หากพร็อกซี SOCKS ไม่รองรับ + ใช้โฮสต์ .onion เป็น ไม่ หากพร็อกซี SOCKS ไม่รองรับ]]> แสดง: แสดงตัวเลือกสําหรับนักพัฒนาซอฟต์แวร์ แชร์ลิงก์ @@ -1000,7 +999,7 @@ แตะเพื่อเริ่มแชทใหม่ เปลี่ยนที่อยู่ผู้รับ\? เริ่มแชทใหม่ - ขอบคุณสำหรับการติดตั้ง SimpleX Chat! + ขอบคุณสำหรับการติดตั้ง SimpleX Chat! แตะปุ่ม การเชื่อมต่อที่คุณยอมรับจะถูกยกเลิก! ผู้ติดต่อที่คุณแชร์ลิงก์นี้ด้วยจะไม่สามารถเชื่อมต่อได้! @@ -1041,9 +1040,9 @@ การแยกการขนส่ง ยกเลิกการซ่อนโปรไฟล์การแชท อัปเดต - ใช้เซิร์ฟเวอร์ SimpleX Chat ไหม\? + ใช้เซิร์ฟเวอร์ SimpleX Chat ไหม\? การสนทนาทางวิดีโอ (ไม่ได้ encrypt จากต้นจนจบ) - กำลังใช้เซิร์ฟเวอร์ SimpleX Chatอยู่ + กำลังใช้เซิร์ฟเวอร์ SimpleX Chatอยู่ - ข้อความเสียงสูงสุด 5 นาที \n- เวลาที่กำหนดเองที่จะหายไป \n- ประวัติการแก้ไข @@ -1052,23 +1051,23 @@ เมื่อแอพกำลังทำงาน ตรวจสอบความปลอดภัยในการเชื่อมต่อ เมื่อคุณแชร์โปรไฟล์ที่ไม่ระบุตัวตนกับใครสักคน โปรไฟล์นี้จะใช้สำหรับกลุ่มที่พวกเขาเชิญคุณ - %1$s ต้องการเชื่อมต่อกับคุณผ่านทาง - ข้อความ %1$d ไม่สามารถ decrypt ได้ - %1$s สมาชิก - คุณสามารถ เชื่อมต่อกับ SimpleX Chat นักพัฒนาแอปเพื่อถามคำถามและรับการอัปเดต + %1$s ต้องการเชื่อมต่อกับคุณผ่านทาง + ข้อความ %1$d ไม่สามารถ decrypt ได้ + %1$s สมาชิก + เชื่อมต่อกับ SimpleX Chat นักพัฒนาแอปเพื่อถามคำถามและรับการอัปเดต]]> คุณสามารถแชร์ที่อยู่ของคุณเป็นลิงก์หรือรหัสคิวอาร์ - ใคร ๆ ก็สามารถเชื่อมต่อกับคุณได้ คุณเปลี่ยนที่อยู่ คุณเปลี่ยนบทบาทของตัวเองเป็น %s โปรไฟล์ปัจจุบันของคุณ คุณกำลังพยายามเชิญผู้ติดต่อที่คุณแบ่งปันโปรไฟล์ที่ไม่ระบุตัวตนไปยังกลุ่มที่คุณใช้โปรไฟล์หลักของคุณ ความเป็นส่วนตัวของคุณ - โปรไฟล์ของคุณจะถูกจัดเก็บไว้ในอุปกรณ์ของคุณและแชร์กับผู้ติดต่อของคุณเท่านั้น เซิร์ฟเวอร์ SimpleX ไม่สามารถดูโปรไฟล์ของคุณได้ + โปรไฟล์ของคุณจะถูกจัดเก็บไว้ในอุปกรณ์ของคุณและแชร์กับผู้ติดต่อของคุณเท่านั้น เซิร์ฟเวอร์ SimpleX ไม่สามารถดูโปรไฟล์ของคุณได้ คุณ คุณได้รับเชิญให้เข้าร่วมกลุ่ม โปรไฟล์แบบสุ่มของคุณ ธีม - กำลังพยายามเชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้รับข้อความจากผู้ติดต่อนี้ (ข้อผิดพลาด: %1$s) - SimpleX + กำลังพยายามเชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้รับข้อความจากผู้ติดต่อนี้ (ข้อผิดพลาด: %1$s) + SimpleX คุณเชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้รับข้อความจากผู้ติดต่อนี้ โปรไฟล์ของคุณจะถูกส่งไปยังผู้ติดต่อที่ส่งลิงก์นี้มาให้คุณ พยายามเชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้รับข้อความจากผู้ติดต่อนี้ @@ -1080,14 +1079,14 @@ คุณแชร์ลิงก์แบบใช้ครั้งเดียว คุณแชร์ลิงก์แบบใช้ครั้งเดียวโดยไม่ระบุตัวตน ผ่านเบราว์เซอร์ - ผ่าน %1$s + ผ่าน %1$s คุณมีโปรไฟล์แชทที่ใช้ชื่อแสดงเดียวกันอยู่แล้ว กรุณาเลือกชื่ออื่น - คุณเชื่อมต่อกับ %1$s แล้ว + คุณเชื่อมต่อกับ %1$s แล้ว เว้นแต่ผู้ติดต่อของคุณลบการเชื่อมต่อหรือลิงก์นี้ถูกใช้ไปแล้ว อาจเป็นข้อผิดพลาด โปรดรายงาน \nในการเชื่อมต่อ โปรดขอให้ผู้ติดต่อของคุณสร้างลิงก์การเชื่อมต่ออื่น และตรวจสอบว่าคุณมีการเชื่อมต่อเครือข่ายที่เสถียร อัปโหลดไฟล์ หากต้องการรับการแจ้งเตือน โปรดป้อนรหัสผ่านของฐานข้อมูล - บริการ SimpleX Chat + บริการ SimpleX Chat เพื่อปกป้องข้อมูลของคุณ ให้เปิด SimpleX Lock \nคุณจะได้รับแจ้งให้ยืนยันตัวตนให้เสร็จสมบูรณ์ก่อนที่จะเปิดใช้งานคุณลักษณะนี้ เปิด @@ -1099,7 +1098,7 @@ เปลี่ยนเป็นยังไม่ได้อ่าน ส่งโดยไม่ได้รับอนุญาต ยินดีต้อนรับ! - ยินดีต้อนรับ %1$s! + ยินดีต้อนรับ %1$s! คุณได้รับเชิญให้เข้าร่วมกลุ่ม คุณไม่มีการแชท แชท @@ -1114,10 +1113,10 @@ กำลังรอวิดีโอ กําลังรอวิดีโอ จะได้รับวิดีโอเมื่อผู้ติดต่อของคุณออนไลน์ โปรดรอหรือตรวจสอบในภายหลัง! - ผู้ติดต่อของคุณส่งไฟล์ที่ใหญ่กว่าขนาดสูงสุดที่รองรับในปัจจุบัน (%1$s) + ผู้ติดต่อของคุณส่งไฟล์ที่ใหญ่กว่าขนาดสูงสุดที่รองรับในปัจจุบัน (%1$s) ข้อความเสียง ข้อความเสียง… - ข้อความเสียง (%1$s) + ข้อความเสียง (%1$s) กำลังรอไฟล์ ตรวจสอบรหัสความปลอดภัย ดูรหัสความปลอดภัย @@ -1132,9 +1131,9 @@ ต้องการเชื่อมต่อกับคุณ! ผู้ติดต่อของคุณจะต้องออนไลน์เพื่อให้การเชื่อมต่อเสร็จสมบูรณ์ \nคุณสามารถยกเลิกการเชื่อมต่อนี้และลบผู้ติดต่อออก (และลองใหม่ในภายหลังด้วยลิงก์ใหม่) - ที่อยู่ SimpleX - โลโก้ SimpleX - SimpleX ทีม + ที่อยู่ SimpleX + โลโก้ SimpleX + SimpleX ทีม คุณจะเชื่อมต่อกับกลุ่มเมื่ออุปกรณ์โฮสต์ของกลุ่มออนไลน์อยู่ โปรดรอหรือตรวจสอบภายหลัง! คุณจะเชื่อมต่อเมื่อคำขอเชื่อมต่อของคุณได้รับการยอมรับ โปรดรอหรือตรวจสอบในภายหลัง! โปรไฟล์แชทของคุณจะถูกส่ง @@ -1142,7 +1141,7 @@ คุณจะเชื่อมต่อเมื่ออุปกรณ์ของผู้ติดต่อของคุณออนไลน์อยู่ โปรดรอหรือตรวจสอบภายหลัง! โปรไฟล์การแชทของคุณจะถูกส่งไปยังผู้ติดต่อของคุณ เมื่อมีคนขอเชื่อมต่อ คุณสามารถยอมรับหรือปฏิเสธได้ - คุณสามารถเชื่อมต่อได้โดยคลิกที่ลิงค์ หากเปิดในเบราว์เซอร์ ให้คลิกปุ่ม เปิดในแอปมือถือ + เปิดในแอปมือถือ]]> ในการตรวจสอบการเข้ารหัสแบบ encrypt จากต้นจนจบ กับผู้ติดต่อของคุณ ให้เปรียบเทียบ (หรือสแกน) รหัสบนอุปกรณ์ของคุณ การตั้งค่าของคุณ ที่อยู่ SimpleX ของคุณ @@ -1174,7 +1173,7 @@ โปรไฟล์ รายชื่อผู้ติดต่อ และข้อความที่ส่งของคุณจะถูกจัดเก็บไว้ในอุปกรณ์ของคุณ คุณสามารถใช้มาร์กดาวน์เพื่อจัดรูปแบบข้อความ: รอคำตอบ… - คุณควบคุมผ่านเซิร์ฟเวอร์ที่จะรับข้อความและผู้ติดต่อของคุณ – เซิร์ฟเวอร์ที่คุณใช้เพื่อส่งข้อความถึงพวกเขา + รับข้อความและผู้ติดต่อของคุณ – เซิร์ฟเวอร์ที่คุณใช้เพื่อส่งข้อความถึงพวกเขา]]> ใช้แชท การสนทนาทางวิดีโอ การโทรของคุณ @@ -1183,10 +1182,10 @@ ผ่านรีเลย์ ปิดวิดีโอ เปิดวิดีโอ - %1$d ข้อความที่ถูกข้าม + %1$d ข้อความที่ถูกข้าม ID ของข้อความถัดไปไม่ถูกต้อง (น้อยกว่าหรือเท่ากับข้อความก่อนหน้า) \nอาจเกิดขึ้นได้เนื่องจากข้อบกพร่องบางอย่างหรือเมื่อการเชื่อมต่อถูกบุกรุก - %1$d ข้อความ ถูกข้ามไป + %1$d ข้อความ ถูกข้ามไป ธีม ฐานข้อมูลการแชทของคุณ ฐานข้อมูลแชทปัจจุบันของคุณจะถูกลบและแทนที่ด้วยฐานข้อมูลที่นำเข้า @@ -1212,7 +1211,7 @@ อัปเดตโปรไฟล์กลุ่มแล้ว คุณเปลี่ยนบทบาทของ %s เป็น %s คุณออกไปแล้ว - คุณลบ %1$s + คุณลบ %1$s คุณเปลี่ยนที่อยู่สำหรับ %s ข้อความต้อนรับ คุณสามารถแชร์ลิงก์หรือคิวอาร์โค้ดได้ ทุกคนจะสามารถเข้าร่วมกลุ่มได้ คุณจะไม่สูญเสียสมาชิกของกลุ่มหากคุณลบในภายหลัง @@ -1244,9 +1243,9 @@ สัปดาห์ การดำเนินการนี้ไม่สามารถยกเลิกได้ - โปรไฟล์ ผู้ติดต่อ ข้อความ และไฟล์ของคุณจะสูญหายไปอย่างถาวร หากต้องการค้นหาโปรไฟล์ที่ใช้สำหรับการเชื่อมต่อแบบไม่ระบุตัวตน ให้แตะชื่อผู้ติดต่อหรือชื่อกลุ่มที่ด้านบนของแชท - เพื่อรักษาความเป็นส่วนตัวของคุณ แทนที่จะใช้การแจ้งเตือนแบบพุช แอปมีบริการพื้นหลัง SimpleX – ใช้แบตเตอรี่เพียงไม่กี่เปอร์เซ็นต์ต่อวัน - คุณ: %1$s - เพื่อปกป้องความเป็นส่วนตัว แทนที่จะใช้ ID ผู้ใช้เหมือนที่แพลตฟอร์มอื่นๆใช้ SimpleX มีตัวระบุสำหรับคิวข้อความ โดยแยกจากกันสำหรับผู้ติดต่อแต่ละราย + SimpleX – ใช้แบตเตอรี่เพียงไม่กี่เปอร์เซ็นต์ต่อวัน]]> + คุณ: %1$s + เพื่อปกป้องความเป็นส่วนตัว แทนที่จะใช้ ID ผู้ใช้เหมือนที่แพลตฟอร์มอื่นๆใช้ SimpleX มีตัวระบุสำหรับคิวข้อความ โดยแยกจากกันสำหรับผู้ติดต่อแต่ละราย คุณจะต้องยืนยันตัวตนเมื่อคุณเริ่มหรือกลับมาใช้แอปพลิเคชันอีกครั้งหลังจากผ่านไป 30 วินาทีในพื้นหลัง คุณจะเข้าร่วมกลุ่มที่ลิงก์นี้อ้างถึงและเชื่อมต่อกับสมาชิกในกลุ่ม ตัวบทนี้มีอยู่ในการตั้งค่า @@ -1265,4 +1264,6 @@ ไม่มีกลุ่มนี้แล้ว คุณจะยังได้รับสายเรียกเข้าและการแจ้งเตือนจากโปรไฟล์ที่ปิดเสียงเมื่อโปรไฟล์ของเขามีการใช้งาน ชื่อ + ค้นหา + ปิด \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-uk/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-uk/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml index 64ef76a4b1..3641fa2b3e 100644 --- a/apps/multiplatform/android/src/main/res/values-uk/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/uk/strings.xml @@ -1,5 +1,5 @@ - + 1 хвилина Про SimpleX Прийняти запит на підключення\? @@ -16,7 +16,7 @@ 1 місяць Про адресу SimpleX 1-разове посилання - Про SimpleX Chat + Про SimpleX Chat Додайте сервери, відсканувавши QR-коди. Всі чати та повідомлення будуть видалені - це неможливо скасувати! Дозволяйте дзвінки, тільки якщо ваш контакт дозволяє їх. @@ -74,15 +74,15 @@ Додаток може отримувати сповіщення лише під час роботи, жодні фонові служби не запускаються завжди Дозвольте вашим контактам телефонувати вам. - Для кожного профілю чату, який ви маєте в додатку</b>, буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис) <b>. + , буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис) .]]> Зовнішній вигляд Версія програми: v%s - Для кожного контакту і члена групи</b> буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис) <b>. -\n<b>Зверніть увагу</b>: якщо у вас багато з\'єднань, споживання заряду акумулятора і трафіку може бути значно вищим, а деякі з\'єднання можуть обірватися. + Для кожного контакту і члена групи буде використовуватися окреме TCP-з\'єднання (і SOCKS-обліковий запис). +\nЗверніть увагу: якщо у вас багато з\'єднань, споживання заряду акумулятора і трафіку може бути значно вищим, а деякі з\'єднання можуть обірватися. Активна оптимізація заряду батареї, яка вимикає фоновий сервіс і періодичні запити на нові повідомлення. Ви можете знову увімкнути їх через налаштування. Назад - жирний - Корисно для батареї. Фонова служба перевіряє повідомлення кожні 10 хвилин. Ви можете пропустити дзвінки або термінові повідомлення. + жирний + Корисно для батареї. Фонова служба перевіряє повідомлення кожні 10 хвилин. Ви можете пропустити дзвінки або термінові повідомлення.]]> Аудіо і відео дзвінки Звук вимкнено Автентифікація недоступна @@ -97,7 +97,7 @@ Звук увімкнено Реакції на повідомлення можете додавати як ви, так і ваш контакт. аудіовиклик - Найкраще для батареї. Ви отримуватимете сповіщення лише тоді, коли додаток працює (БЕЗ фонового сервісу). + Найкраще для батареї. Ви отримуватимете сповіщення лише тоді, коли додаток працює (БЕЗ фонового сервісу).]]> Аудіо та відеодзвінки Автентифікація Не вдалося пройти автентифікацію @@ -106,8 +106,8 @@ поганий хеш повідомлення помилковий ідентифікатор повідомлення Фон - Додайте новий контакт: для створення одноразового QR-коду для вашого контакту. - Його можна вимкнути в налаштуваннях - сповіщення все одно будуть показуватися під час роботи програми. + Додайте новий контакт: для створення одноразового QR-коду для вашого контакту.]]> + Його можна вимкнути в налаштуваннях - сповіщення все одно будуть показуватися під час роботи програми.]]> Фоновий сервіс працює постійно - сповіщення з\'являтимуться, щойно повідомлення стануть доступними. Попросили отримати зображення Прикріпити @@ -115,7 +115,7 @@ " \nДоступно у v5.1" Аудіо/відео дзвінки заборонені. - SimpleX + SimpleX Дзвонити можете як ви, так і ваш контакт. k Підключитися за контактним посиланням\? @@ -128,7 +128,7 @@ помилка підключення Ви підключені до сервера, який використовується для отримання повідомлень від цього контакту. - Спроба з\'єднатися з сервером, який використовується для отримання повідомлень від цього контакту (помилка: %1$s ). + Спроба з\'єднатися з сервером, який використовується для отримання повідомлень від цього контакту (помилка: %1$s ). видалено Спроба з\'єднатися з сервером, який використовується для отримання повідомлень від цього контакту. з позначкою видалено @@ -156,7 +156,7 @@ Контактна адреса SimpleX Одноразове запрошення SimpleX Посилання на групу SimpleX - через %1$s + через %1$s Посилання SimpleX Опис Повне посилання @@ -173,7 +173,7 @@ Помилка перемикання профілю! Тайм-аут з\'єднання Помилка підключення - Будь ласка, перевірте своє мережеве з\'єднання за допомогою %1$s і спробуйте ще раз. + Будь ласка, перевірте своє мережеве з\'єднання за допомогою %1$s і спробуйте ще раз. Контакт вже існує Помилка підключення (AUTH) Можливо, відправник видалив запит на підключення. @@ -223,7 +223,7 @@ ГАРАЗД Скопійовано в буфер обміну Підключитися за посиланням - 📱 мобільний: торкніться Відкрийте в мобільному додатку, потім торкніться Підключіть в додатку. + Відкрийте в мобільному додатку, потім торкніться Підключіть в додатку.]]> Вимкнути звук Увімкнути звук Ви запросили свого контакта @@ -231,7 +231,7 @@ заповнювач зображення профілю QR-код допомога - Якщо ви не можете зустрітися особисто, покажіть QR-код у відеодзвінку або поділіться посиланням. + покажіть QR-код у відеодзвінку або поділіться посиланням.]]> Ваш профіль чату буде надіслано \nдо вашого контакту Посилання на одноразове запрошення @@ -283,7 +283,7 @@ Динамік увімкнено Перевернути камеру Відхилений дзвінок - %1$d пропущено повідомлення(і) + %1$d пропущено повідомлення(і) ЧАТИ SOCKS PROXY Помилка запуску чату @@ -357,19 +357,19 @@ Невірне посилання! Це посилання не є дійсним посиланням для підключення! Запит на підключення відправлено! - Ви також можете підключитися за посиланням. Якщо воно відкриється в браузері, натисніть кнопку Відкрити в мобільному додатку. + Відкрити в мобільному додатку.]]> Створіть одноразове посилання-запрошення Сканувати код Відскануйте код безпеки з додатку вашого контакту. Неправильна адреса сервера! Перевірте адресу сервера та спробуйте ще раз. Сервери XFTP - Встановіть SimpleX Chat для терміналу + Встановіть SimpleX Chat для терміналу Зробити внесок Оцініть програму Ваші сервери SMP Ваші сервери XFTP - Використання серверів SimpleX Chat. + Використання серверів SimpleX Chat. Як зробити телефоную… пропущений дзвінок @@ -380,7 +380,7 @@ Дзвінки на екрані блокування: одноранговий Покласти слухавку - Створено на %1$s + Створено на %1$s Розширити вибір ролей Так Налаштування контактів @@ -417,10 +417,10 @@ чекаємо на підтвердження… Переосмислення конфіденційності Люди можуть підключатися до вас лише за посиланнями, якими ви ділитеся. - Як працює SimpleX + Як працює SimpleX Детальніше читайте в нашому репозиторії GitHub. e2e зашифрований аудіодзвінок - Відкрийте SimpleX Chat, щоб прийняти дзвінок + Відкрийте SimpleX Chat, щоб прийняти дзвінок e2e зашифрований Динамік вимкнено Дзвінок в очікуванні @@ -440,13 +440,13 @@ Поточна парольна фраза… База даних буде зашифрована, а пароль зберігатиметься у сховищі ключів. Ключову фразу шифрування бази даних буде оновлено і збережено у сховищі ключів. - запрошені %1$s + запрошені %1$s запрошені за посиланням у вашій групі ви змінили роль %s на %s ви змінили адресу для %s зміна адреси для %s… Не вдається запросити контакт! - %1$s УЧАСНИКИ + %1$s УЧАСНИКИ Видалити групу Посилання на групу Редагування профілю групи @@ -462,7 +462,7 @@ Встановіть його замість системної автентифікації. Вимкнути\? Поділіться з контактами - Ваш профіль зберігається на вашому пристрої та доступний лише вашим контактам. Сервери SimpleX не бачать ваш профіль. + Ваш профіль зберігається на вашому пристрої та доступний лише вашим контактам. Сервери SimpleX не бачать ваш профіль. Збереження та сповіщення контактів Збереження та сповіщення учасників групи Вихід без збереження @@ -517,10 +517,10 @@ днів Виберіть нестандартний - таємниця + таємниця Приєднуйтесь Роль - непрямі (%1$s) + непрямі (%1$s) Увімкнути звук Повинен бути принаймні один профіль користувача. Зробіть профіль приватним! @@ -532,12 +532,12 @@ зображення профілю Більше Створити профіль - Детальніше читайте в нашому репозиторії GitHub. + GitHub.]]> Відео включено Це може статися, коли ви або ваше підключення використовували стару резервну копію бази даних. Відновлення резервної копії бази даних Зберегти архів - запрошення до групи %1$s + запрошення до групи %1$s Вас запрошено до групи. Приєднуйтесь, щоб спілкуватися з учасниками групи. Реакції на повідомлення Встановлюється 1 день @@ -546,7 +546,7 @@ %ds хвилини Інтерфейс китайською та іспанською мовами - підключення %1$d + підключення %1$d Помилка завантаження серверів SMP Дублююче ім\'я користувача! Помилка надсилання повідомлення @@ -558,9 +558,9 @@ Створити файл Помилка видалення профілю користувача Помилка оновлення конфіденційності користувача - Щоб зберегти вашу конфіденційність, замість push-сповіщень програма має SimpleX фонову службу – вона використовує кілька відсотків заряду акумулятора на день. + SimpleX фонову службу – вона використовує кілька відсотків заряду акумулятора на день.]]> Періодичні сповіщення - Сервіс SimpleX Chat + Сервіс SimpleX Chat Перевіряє нові повідомлення кожні 10 хвилин протягом 1 хвилини Приховано Показати контакт та повідомлення @@ -583,7 +583,7 @@ Файл буде видалено з серверів. Відкликати несанкціонована відправка - Ласкаво просимо %1$s! + Ласкаво просимо %1$s! Ласкаво просимо! Цей текст доступний у налаштуваннях вас запрошують до групи @@ -599,8 +599,8 @@ Зображення буде отримано, коли ваш контакт буде онлайн, будь ласка, зачекайте або перевірте пізніше! Зображення збережено до Галереї Відео - Ваш контакт надіслав файл, розмір якого перевищує дозволений максимальний розмір (%1$s). - Наразі максимальний підтримуваний розмір файлу: %1$s . + Ваш контакт надіслав файл, розмір якого перевищує дозволений максимальний розмір (%1$s). + Наразі максимальний підтримуваний розмір файлу: %1$s . Ця функція є експериментальною! Вона працюватиме, тільки якщо на іншому клієнті встановлено версію 4.2. Після завершення зміни адреси ви побачите повідомлення в бесіді - будь ласка, перевірте, чи можете ви отримувати повідомлення від цього контакту (або члена групи). Підтвердіть код безпеки Відправити повідомлення @@ -608,9 +608,9 @@ (зберігається тільки учасниками групи) У дозволі відмовлено! Камера - Дякуємо, що встановили SimpleX Chat! - Відскануйте QR-код: щоб з\'єднатися з вашим контактом, який покаже вам QR-код. - Якщо ви отримали посилання на запрошення SimpleX Chat, ви можете відкрити його у своєму браузері: + Дякуємо, що встановили SimpleX Chat! + Відскануйте QR-код: щоб з\'єднатися з вашим контактом, який покаже вам QR-код.]]> + Якщо ви отримали посилання на запрошення SimpleX Chat, ви можете відкрити його у своєму браузері: Чисто Видалити Видалити @@ -621,7 +621,7 @@ Видалити очікуване з\'єднання\? Ваш контакт має бути онлайн, щоб з’єднання завершилося. \nВи можете скасувати це з’єднання та видалити контакт (і спробувати пізніше з новим посиланням). - SimpleX Логотип + SimpleX Логотип Електронна пошта Цей QR-код не є посиланням! Вас буде підключено до групи, коли пристрій хоста групи буде онлайн, зачекайте або перевірте пізніше! @@ -644,7 +644,7 @@ Попередньо встановлений сервер Ваша адреса сервера Сервери для нових підключень вашого поточного профілю чату - Використовуєте сервери SimpleX Chat\? + Використовуєте сервери SimpleX Chat\? Сервери ICE (по одному на лінію) Помилка збереження серверів ICE Для з\'єднання будуть потрібні хости onion. @@ -669,11 +669,11 @@ Ви можете використовувати розмітку для форматування повідомлень: Створіть свій профіль Створіть приватне з\'єднання - Багато людей запитували: якщо SimpleX не має ідентифікаторів користувачів, як він може доставляти повідомлення\? - Ви контролюєте, через який(і) сервер(и) отримувати повідомлення, ваші контакти - сервери, які ви використовуєте для надсилання їм повідомлень. - Лише клієнтські пристрої зберігають профілі користувачів, контакти, групи та повідомлення, надіслані за допомогою дворівневого наскрізного шифрування. + якщо SimpleX не має ідентифікаторів користувачів, як він може доставляти повідомлення\?]]> + отримувати повідомлення, ваші контакти - сервери, які ви використовуєте для надсилання їм повідомлень.]]> + дворівневого наскрізного шифрування.]]> Приватні сповіщення - Використовує більше заряду акумулятора! Завжди працює фоновий сервіс - сповіщення показуються, як тільки з\'являються повідомлення. + Використовує більше заряду акумулятора! Завжди працює фоновий сервіс - сповіщення показуються, як тільки з\'являються повідомлення.]]> Вставте отримане посилання Відео вимкнено Дзвінок завершено @@ -724,7 +724,7 @@ Запросити до групи Пропустити запрошення учасників %d вибрано контакт(и) - ви: %1$s + ви: %1$s Група буде видалена для всіх учасників - це неможливо скасувати! Група буде видалена для вас - це не може бути скасовано! Створити посилання @@ -805,7 +805,7 @@ секунд тижнів місяці - Ви вже підключені до %1$s. + Ви вже підключені до %1$s. Режим інкогніто СЕРВЕРИ Зберегти привітальне повідомлення\? @@ -828,7 +828,7 @@ Безпечна черга Видалити чергу Будь ласка, переконайтеся, що ви використали правильне посилання, або попросіть свого контакта надіслати вам інше. - Щоб скористатися нею, будь ласка, вимкніть оптимізацію батареї для SimpleX у наступному діалозі. Інакше сповіщення буде вимкнено. + вимкніть оптимізацію батареї для SimpleX у наступному діалозі. Інакше сповіщення буде вимкнено.]]> Миттєві сповіщення Контакт приховано: нове повідомлення @@ -874,8 +874,8 @@ Показати Вимкнути Сервер ретрансляції використовується лише за необхідності. Інша сторона може спостерігати за вашою IP-адресою. - %1$d повідомлення не вдалося розшифрувати. - %1$d повідомлення пропущені. + %1$d повідомлення не вдалося розшифрувати. + %1$d повідомлення пропущені. Будь ласка, повідомте про це розробникам. Надіслати попередній перегляд за посиланням Блокування після @@ -916,7 +916,7 @@ Дякуємо користувачам - зробіть свій внесок через Weblate! Режим SimpleX Lock Аутентифікація системи - Для захисту конфіденційності, замість ідентифікаторів користувачів, які використовуються на всіх інших платформах, SimpleX має ідентифікатори для черг повідомлень, окремі для кожного з ваших контактів. + Для захисту конфіденційності, замість ідентифікаторів користувачів, які використовуються на всіх інших платформах, SimpleX має ідентифікатори для черг повідомлень, окремі для кожного з ваших контактів. Коли додаток працює Періодичні контакт не має шифрування e2e @@ -929,7 +929,7 @@ Видаляти файли та медіа\? %d файл(и) загальним розміром %s Ваша база даних чату не зашифрована - встановіть парольну фразу, щоб захистити її. - Зверніть увагу: ви НЕ зможете відновити або змінити парольну фразу, якщо її втратите. + Зверніть увагу: ви НЕ зможете відновити або змінити парольну фразу, якщо її втратите.]]> Система Несумісна версія бази даних Підтвердити оновлення бази даних @@ -941,7 +941,7 @@ Ви більше не будете отримувати повідомлення від цієї групи. Історія чату буде збережена. Запросити учасників Група неактивна - ви видалили %1$s + ви видалили %1$s Натисніть, щоб активувати профіль. Не можу видалити профіль користувача! Заборонити надсилання голосових повідомлень. @@ -1023,7 +1023,7 @@ Відкрити профілі чату В очікуванні відео Очікування файлу - Голосове повідомлення (%1$s) + Голосове повідомлення (%1$s) Сповіщення Видалити контакт\? Скасувати повідомлення в прямому ефірі @@ -1035,7 +1035,7 @@ Ви будете з\'єднані, коли пристрій вашого контакту буде в мережі, будь ласка, зачекайте або перевірте пізніше! Ви не втратите свої контакти, якщо згодом видалите свою адресу. Коли люди звертаються із запитом на підключення, ви можете прийняти або відхилити його. - Докладніше в Посібнику користувача. + Посібнику користувача.]]> Адреса SimpleX Очистити верифікацію %s перевірено @@ -1073,7 +1073,7 @@ підключений закінчився Імунітет до спаму та зловживань - %1$s хоче зв\'язатися з вами через + %1$s хоче зв\'язатися з вами через e2e зашифрований відеодзвінок Ігнорувати Це може статися, коли: @@ -1140,7 +1140,7 @@ Встановити ім\'я контакту… Файл З галереї - SimpleX Команда + SimpleX Команда хоче зв\'язатися з вами! ЕКСПЕРИМЕНТАЛЬНИЙ Ви повинні використовувати найновішу версію вашої бази даних чату ЛИШЕ на одному пристрої, інакше ви можете перестати отримувати повідомлення від деяких контактів. @@ -1149,7 +1149,7 @@ Помилка: %s Пониження бази даних Групове запрошення більше не дійсне, воно було видалено відправником. - видалено %1$s + видалено %1$s підключення (вступне запрошення) підключення Немає контактів для додавання @@ -1188,8 +1188,8 @@ Забагато зображень! Забагато відео! ви спостерігач - кольорові - дзвінок закінчився %1$s + кольорові + дзвінок закінчився %1$s помилка виклику Наступне покоління приватних повідомлень Протокол і код з відкритим вихідним кодом - будь-хто може запускати сервери. @@ -1207,13 +1207,13 @@ Створити секретну групу (щоб поділитися з вашим контактом) (відсканувати або вставити з буфера обміну) - Ви можете <font xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" color=\"#0088ff\">зв\'язатися з <xliff:g id=\"appNameFull\">розробниками <xliff:g>SimpleX Chat</xliff:g>, щоб задати будь-які питання та отримати оновлення</font>. - 💻 десктоп: відскануйте відображений QR-код з додатку, за допомогою Відскануйте QR-код. - SimpleX Адреса + зв\'язатися з розробниками SimpleX Chat, щоб задати будь-які питання та отримати оновлення.]]> + Відскануйте QR-код.]]> + SimpleX Адреса Показати QR-код Приєднання до групи Ніяких пробілів! - курсив + курсив Сервери WebRTC ICE Увімкніть дзвінки з екрана блокування через Налаштування. Швидко і без очікування, поки відправник буде онлайн! @@ -1249,11 +1249,11 @@ видалив вас власник видалено - Якщо ви не можете зустрітися особисто, ви можете відсканувати QR-код у відеодзвінку, або ваш контакт може поділитися посиланням на запрошення. + відсканувати QR-код у відеодзвінку, або ваш контакт може поділитися посиланням на запрошення.]]> Вставте отримане посилання у поле нижче, щоб зв\'язатися з вашим контактом. Як ним користуватися Підключення - Встановіть Використовувати .onion хости на Ні, якщо SOCKS проксі не підтримує їх. + Використовувати .onion хости на Ні, якщо SOCKS проксі не підтримує їх.]]> Покажи: Приховати: Під час імпорту виникли деякі нефатальні помилки – ви можете переглянути консоль чату, щоб дізнатися більше. @@ -1265,4 +1265,6 @@ Пароль не знайдено у сховищі ключів, будь ласка, введіть його вручну. Це могло статися, якщо ви відновили дані програми за допомогою інструменту резервного копіювання. Якщо це не так, зверніться до розробників. Видалити профіль чату %d сек + Пошук + Вимкнено \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-zh-rCN/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-zh-rCN/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml index 82882bcda2..e90a1e4f60 100644 --- a/apps/multiplatform/android/src/main/res/values-zh-rCN/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rCN/strings.xml @@ -1,10 +1,10 @@ - + a + b 1天 关于 SimpleX 所有群组成员将保持连接。 - 关于 SimpleX Chat + 关于 SimpleX Chat 以上,然后: 接受 接受 @@ -26,7 +26,7 @@ 添加预设服务器 通过链接连接 已建立连接 - 连接 %1$d + 连接 %1$d 连接错误 连接超时 联系人已存在 @@ -70,7 +70,7 @@ 允许您的联系人不可撤回地删除已发送消息。 联系人允许 仅有您的联系人许可后才允许语音消息。 - 您: %1$s + 您: %1$s 允许您的联系人发送语音消息。 始终 始终开启 @@ -116,26 +116,26 @@ 关闭音频 开启音频 已要求接收图片 - 一个单独的TCP连接(和SOCKS凭证)将被用于,用于您在应用程序中的每个聊天资料 + ,用于您在应用程序中的每个聊天资料 。]]> 每个联系人和群组成员 将使用单独的 TCP 连接(和 SOCKS 凭证)。 \n请注意:如果您有很多连接,您的电池和流量消耗可能会大大增加,并且某些连接可能会失败。 返回 - 添加新联系人:为您的联系人创建一次性二维码。 - 最长续航 。您只会在应用程序运行时收到通知(无后台服务)。 - 较长续航 。后台服务每 10 分钟检查一次消息。您可能会错过来电或者紧急信息。 - 加粗 + 添加新联系人:为您的联系人创建一次性二维码。]]> + 最长续航 。您只会在应用程序运行时收到通知(无后台服务)。]]> + 较长续航 。后台服务每 10 分钟检查一次消息。您可能会错过来电或者紧急信息。]]> + 加粗 您和您的联系人都可以不可逆转地删除已发送的消息。 您和您的联系人都可以发送限时消息。 您和您的联系人都可以发送语音消息。 - 可以在设置里禁用它 - 应用程序运行时仍会显示通知。 - 使用更多电量 !后台服务始终运行——一旦收到消息,就会显示通知。 - 请注意:如果您丢失密码,您将无法恢复或者更改密码。 + 可以在设置里禁用它 - 应用程序运行时仍会显示通知。]]> + 使用更多电量 !后台服务始终运行——一旦收到消息,就会显示通知。]]> + 请注意:如果您丢失密码,您将无法恢复或者更改密码。]]> 通话已结束! - 扫描二维码 :与向您展示二维码的联系人联系。 + 扫描二维码 :与向您展示二维码的联系人联系。]]> 无法邀请联系人! 无法邀请联系人! 取消 - 通话结束 %1$s + 通话结束 %1$s 更改 通话结束 更改数据库密码? @@ -181,7 +181,7 @@ 重新定义隐私 改进的隐私和安全 隐身聊天 - 加入群组 + 加入群组中 加入隐身聊天 隐身模式 此处不支持隐身模式——您的主要个人资料将发送给群组成员 @@ -219,7 +219,7 @@ 在密匙库中没有找到密码,请手动输入。如果您使用备份工具恢复了应用程序的数据,可能会发生这种情况。如果不是这种情况,请联系开发者。 从密钥库中删除密码? 在密钥库中保存密码 - SimpleX Chat 服务 + SimpleX Chat 服务 通知服务 确认新密码…… 完整的 @@ -232,7 +232,7 @@ 清除聊天记录? 与开发者聊天 清除 - 彩色 + 彩色 已连接 连接 连接 @@ -278,7 +278,7 @@ 文件已保存 已断开连接 错误 - 💻 桌面:通过 扫描二维码 从应用程序扫描显示的二维码。 + 扫描二维码 从应用程序扫描显示的二维码。]]> 删除待定连接? 如何使用 markdown 创建 @@ -428,7 +428,7 @@ 设备验证被禁用。关闭 SimpleX 锁定。 没有启用设备验证。一旦启用设备验证,您可以通过设置打开 SimpleX 锁定。 禁用 SimpleX 锁定 - 目前支持的最大文件尺寸是 %1$s + 目前支持的最大文件尺寸是 %1$s。 文件将在您的联系人在线时收到,请稍等或稍后再查看! 从图库 照片 @@ -461,7 +461,7 @@ 实时 已邀请连接 无效的连接链接 - 斜体 + 斜体 已邀请 邀请加入群组 加入 @@ -502,7 +502,7 @@ 设置联系人姓名…… 已收到回复…… 已受到确认…… - 只有客户端设备存储用户配置文件、联系人、群组和使用 双层端到端加密 发送的消息。 + 双层端到端加密 发送的消息。]]> 视频通话(非端到端加密) 定期 私密通知 @@ -534,9 +534,9 @@ 通知 正在接收消息…… 要接收通知,请输入数据库密码 - 为了保护您的隐私,该应用程序没有推送通知,而是具有 SimpleX 后台服务 ——它每天使用百分之几的电池。 + SimpleX 后台服务 ——它每天使用百分之几的电池。]]> 您的设置 - 为了使用它,请 禁用电池优化SimpleX在下一个对话框。否则通知将被禁用。 + 禁用电池优化为SimpleX在下一个对话框。否则通知将被禁用。]]> 通知预览 需要密码 定期通知被禁用! @@ -568,13 +568,13 @@ 数据库密码错误 保存 更新 - 打开 SimpleX Chat 来接听电话 + 打开 SimpleX Chat 来接听电话 视频通话 - %1$s 想通过以下方式与您联系 + %1$s 想通过以下方式与您联系 拒接来电 点对点 错误:%s - 如果您不能亲自见面,您可以 扫描视频通话中的二维码,或者您的联系人可以分享邀请链接。 + 扫描视频通话中的二维码,或者您的联系人可以分享邀请链接。]]> 您的通话 通过中继 未接来电 @@ -582,13 +582,13 @@ 语音消息 语音消息 SimpleX Chat 通话 - 如果您不能亲自见面,在视频通话中出示二维码,或分享链接。 + 在视频通话中出示二维码,或分享链接。]]> 您的聊天资料 未接来电 待定来电 除非您的联系人已删除此连接或此链接已被使用,否则它可能是一个错误——请报告。 \n如果要连接,请让您的联系人创建另一个连接链接,并检查您的网络连接是否稳定。 - 您已经连接到 %1$s + 您已经连接到 %1$s。 您的聊天资料将被发送 \n给您的联系人 资料和服务器连接 @@ -606,17 +606,17 @@ 未知错误 未知数据库错误:%s 已更新的群组资料 - 已删除 %1$s - 您删除了 %1$s + 已删除 %1$s + 您删除了 %1$s 您的个人资料将发送给您收到此链接的联系人。 - 正在尝试连接到用于从该联系人接收消息的服务器(错误:%1$s)。 + 正在尝试连接到用于从该联系人接收消息的服务器(错误:%1$s)。 您已连接到用于接收该联系人消息的服务器。 您分享了一次性链接 很可能此联系人已经删除了与您的联系。 资料图片占位符 您当前聊天资料的新连接服务器 您当前的资料 - 您的资料存储在您的设备上并且仅与您的联系人共享。SimpleX 服务器无法看见您的资料。 + 您的资料存储在您的设备上并且仅与您的联系人共享。SimpleX 服务器无法看见您的资料。 您的资料、联系人和发送的消息存储在您的设备上。 该资料仅与您的联系人共享。 开启 @@ -628,10 +628,10 @@ 您拒绝了群组邀请 您当前的聊天数据库将被删除并替换为导入的数据库。 \n此操作无法撤消——您的个人资料、联系人、消息和文件将不可撤回地丢失。 - 已邀请 %1$s + 已邀请 %1$s 保存群组资料 服务器地址中的证书指纹可能不正确 - 请使用 %1$s 检查您的网络连接,然后重试。 + 请使用 %1$s 检查您的网络连接,然后重试。 多个聊天资料 数据库不能正常工作。点击了解更多 消息传递错误 @@ -639,15 +639,15 @@ %d 小时 %d 月 %d 秒 - SimpleX 是如何工作的 + SimpleX 是如何工作的 确保 WebRTC ICE 服务器地址格式正确、每行分开且不重复。 - 许多人问:如果SimpleX没有用户标识符,它是怎样传递信息的? + 如果SimpleX没有用户标识符,它是怎样传递信息的?]]> 确保 SMP 服务器地址格式正确、每行分开且不重复。 Markdown 帮助 标记为已验证 建立私密连接 以 %s 身份加入 - 如果您收到 SimpleX Chat 邀请链接,您可以在浏览器中打开它: + 如果您收到 SimpleX Chat 邀请链接,您可以在浏览器中打开它: 标记为已读 标记为未读 在消息中使用 Markdown @@ -668,7 +668,7 @@ 已被管理员移除 Onion 主机将在可用时使用。 将不会使用 Onion 主机。 - 📱 手机:点击在手机应用程序中打开,然后在应用程序中点击连接 + 在手机应用程序中打开,然后在应用程序中点击连接。]]> 消息将被标记为删除。收件人将能够揭示此消息。 更多改进即将推出! 未选择联系人 @@ -711,7 +711,7 @@ 保存并通知联系人 在我们的 GitHub 仓库中阅读更多内容。 拒绝 - 为了保护隐私,而不是所有其他平台使用的用户 ID,SimpleX 具有消息队列的标识符,每个联系人都是分开的。 + 为了保护隐私,而不是所有其他平台使用的用户 ID,SimpleX 具有消息队列的标识符,每个联系人都是分开的。 TCP 连接超时 收到,禁止 设定1天 @@ -734,7 +734,7 @@ 扫码 从您联系人的应用程序中扫描安全码。 安全码 - 秘密 + 秘密 安全评估 SimpleX 消息 %s 未验证 @@ -747,7 +747,7 @@ 角色将更改为“%s”。 该成员将收到新的邀请。 此操作无法撤消——早于所选的发送和接收的消息将被删除。 这可能需要几分钟时间。 此二维码不是链接! - 此功能是实验性的! 它仅在其他客户端安装了 4.2 版时才有效。 地址更改完成后,您应该会在对话中看到该消息——请检查您是否仍能收到来自该联系人(或群组成员)的消息。 + 接收地址将变更到不同的服务器。地址更改将在发件人上线后完成。 此链接不是有效的连接链接! 开始新的聊天 要与您的联系人验证端到端加密,请比较(或扫描)您设备上的代码。 @@ -762,7 +762,7 @@ 未经授权发送 太多图片! 待办的 - 切换接收地址吗? + 更改接收地址? 请让您的联系人启用发送语音消息。 录制语音消息 发消息 @@ -778,7 +778,7 @@ 显示二维码 发送问题和想法 保护您的隐私和安全的消息传递和应用程序平台。 - 删去 + 删去 人们只能通过您共享的链接与您建立联系。 下一代私密通讯软件 粘贴收到的链接 @@ -795,7 +795,7 @@ 接收通过 发送通过 服务器 - 切换接收地址 + 更改接收地址 保留最后的消息草稿及其附件。 私密文件名 感谢用户——通过 Weblate 做出贡献! @@ -844,12 +844,12 @@ 减少电池使用量 为了保护时区,图像/语音文件使用 UTC。 使用聊天 - 在我们的 GitHub 存储库 中阅读更多内容。 + GitHub 存储库 中阅读更多内容。]]> 打开聊天控制台 停止聊天程序 权限被拒绝! 点击按钮 - 感谢您安装 SimpleX Chat + 感谢您安装 SimpleX Chat! 相机 预设服务器地址 扫描服务器二维码 @@ -864,10 +864,10 @@ 系统 对方会在您键入时看到更新。 查看安全码 - 语音消息 (%1$s) + 语音消息 (%1$s) 等待图像中 欢迎! - 欢迎 %1$s + 欢迎 %1$s! 当您的联系人设备在线时,您将可以连接,请稍等或稍后查看! 评价此应用程序 使用 SOCKS 代理? @@ -878,21 +878,21 @@ 此聊天中禁止语音消息。 语音信息在该群组中被禁用。 验证安全码 - 使用 SimpleX Chat 服务器。 - 通过 %1$s - 邀请至群组 %1$s - SimpleX 地址 - SimpleX 团队 - %1$s 成员 + 使用 SimpleX Chat 服务器。 + 通过 %1$s + 邀请至群组 %1$s + SimpleX 地址 + SimpleX 团队 + %1$s 成员 - 您可以控制通过哪些服务器接收消息,您的联系人 - 您用来向他们发送消息的服务器。 + 接收消息,您的联系人 - 您用来向他们发送消息的服务器。]]> 您将在组主设备上线时连接到该群组,请稍等或稍后再检查! 当您启动应用或在应用程序驻留后台超过30 秒后,您将需要进行身份验证。 - 创建于 %1$s - 您可以 连接到 SimpleX Chat 开发者提出任何问题并接收更新 + 创建于 %1$s + 连接到 SimpleX Chat 开发者提出任何问题并接收更新 。]]> 您已接受连接 您的 SMP 服务器 - %1$d 已跳过消息 + %1$d 已跳过消息 %ds 更新内容 您被邀请加入群组 @@ -906,10 +906,10 @@ 想要与您连接! 您的联系人需要在线才能完成连接。 \n您可以取消此连接并删除联系人(稍后尝试使用新链接)。 - SimpleX 标志 + SimpleX 标志 您的 SimpleX 地址 - 为终端安装 SimpleX Chat - 使用 SimpleX Chat 服务器? + 为终端安装 SimpleX Chat + 使用 SimpleX Chat 服务器? 我们不会在服务器上存储您的任何联系人或消息(一旦发送)。 WebRTC ICE 服务器 中继服务器保护您的 IP 地址,但它可以观察通话的持续时间。 @@ -921,9 +921,9 @@ 您将自己的角色更改为 %s 您已更改地址 您可以共享链接或二维码——任何人都可以加入该群组。如果您稍后将其删除,您不会失去该组的成员。 - 间接(%1$s - 您也可以通过点击链接进行连接。 如果它在浏览器中打开,请单击在移动应用程序中打开按钮。 - SimpleX + 间接(%1$s) + 在移动应用程序中打开按钮。]]> + SimpleX 您将加入此链接指向的群组并连接到其群组成员。 通过群组链接 通过一次性链接 @@ -949,7 +949,7 @@ %dm %dmth 等待文件中 - 您的联系人发送的文件大于当前支持的最大大小 (%1$s). + 您的联系人发送的文件大于当前支持的最大大小 (%1$s). 当您的连接请求被接受后,您将可以连接,请稍等或稍后检查! 使用服务器 您的服务器地址 @@ -1046,7 +1046,7 @@ 上传文件 XFTP 服务器 您的 XFTP 服务器 - 如果 SOCKS 代理不支持它们,请将 Use .onion hosts 设置为否。 + Use .onion hosts 设置为否。]]> 使用 SOCKS 代理 端口 删除文件 @@ -1092,8 +1092,8 @@ 立即 错误消息散列 错误消息 ID - %1$d 消息解密失败。 - %1$d 已跳过消息。 + %1$d 消息解密失败。 + %1$d 已跳过消息。 此错误对于此连接是永久性的,请重新连接。 当您或您的连接使用旧数据库备份时,可能会发生这种情况。 解密错误 @@ -1208,7 +1208,7 @@ 了解更多 当人们请求连接时,您可以接受或拒绝它。 如果您以后删除您的地址,您不会丢失您的联系人。 - 用户指南中阅读更多。 + 用户指南中阅读更多。]]> 主题颜色 与您的联系人保持连接。 与联系人分享 @@ -1267,4 +1267,21 @@ 通知将停止工作直到您重启应用程序 关闭? 关闭 + 中止地址更改错误 + 中止地址更改? + 将中止地址更改。将使用旧接收地址。 + 中止 + 中止地址更改 + 允许发送文件和媒体。 + 文件和媒体 + 只有组主可以启用文件和媒体。 + 此群组中禁止文件和媒体。 + 群组成员可以发送文件和媒体。 + 禁止发送文件和媒体。 + 禁止文件和媒体! + 无过滤聊天 + 取消最喜欢 + 最喜欢 + 搜索 + 已关闭 \ No newline at end of file diff --git a/apps/multiplatform/android/src/main/res/values-zh-rTW/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml similarity index 92% rename from apps/multiplatform/android/src/main/res/values-zh-rTW/strings.xml rename to apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml index 8b399bfd21..8b28a432d1 100644 --- a/apps/multiplatform/android/src/main/res/values-zh-rTW/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/zh-rTW/strings.xml @@ -1,5 +1,5 @@ - + 1 個星期 a + b 關於 SimpleX @@ -8,7 +8,7 @@ 1天 1 個月 接受 - 關於 SimpleX Chat + 關於 SimpleX Chat 接受連接請求? 已接受通話 要在端口啟用 SOCKS 代理伺服器嗎?在啟用這個選項之前,必須先啟用代理伺服器。 @@ -21,8 +21,8 @@ 允許 顯示名稱: 全名: - 使用更多電量!通知服務長期在背景中運行 – 有效的訊息就會即時顯示在通知內。 - 對電量友善。通知服務於每十分鐘檢查一次訊息。你可能會錯過通話和迫切的訊息。 + 使用更多電量!通知服務長期在背景中運行 – 有效的訊息就會即時顯示在通知內。]]> + 對電量友善。通知服務於每十分鐘檢查一次訊息。你可能會錯過通話和迫切的訊息。]]> 回應通話請求 清除 允許向群組內的成員傳送私訊。 @@ -48,8 +48,8 @@ 允許使用語音訊息? 取消 取消實況訊息 - 新增新的聯絡人:建立你的一次性二維碼給你的聯絡人。 - 掃描二維碼:連接到向你出示二維碼的聯絡人。 + 新增新的聯絡人:建立你的一次性二維碼給你的聯絡人。]]> + 掃描二維碼:連接到向你出示二維碼的聯絡人。]]> 選擇檔案 相機 從圖片庫選擇圖片 @@ -63,7 +63,7 @@ 分享一次性連結 傳送問題和想法給開發者 如何使用 - 使用終端機安裝 SimpleX Chat + 使用終端機安裝 SimpleX Chat 應用程式版本 你的所有聯絡人會保持連接。 應用程式建構:%s @@ -77,9 +77,9 @@ 通話出錯 正在撥打… 通話中 - 私密 + 私密 已連接 - 對電量最好。 只有在應用程式運行中的時侯才可以接收訊息通知。(沒有後台服務) + 對電量最好。 只有在應用程式運行中的時侯才可以接收訊息通知。(沒有後台服務)]]> 端對端加密的視訊通話 視訊通話(沒有端對端加密) 通話已經結束了! @@ -94,13 +94,13 @@ 語音通話 語音 & 視訊通話 視訊通話 - 粗體 + 粗體 自動接收圖片 備份應用程式資料 應用程式圖示 已匯入對話數據庫 Android 金鑰庫是用於安全地儲存密碼 - 確保通知推送服務的運作。 - 請注意:如果你忘記了密碼你將不能再次復原或修改密碼。 + 請注意:如果你忘記了密碼你將不能再次復原或修改密碼。]]> 當你重新啟動應用程式或修改密碼後, Android 金鑰庫將用來安全地儲存密碼 - 將允許接收訊息通知。 聊天室已停止運作 只有這個群組的負責人才能修改群組內的設定。 @@ -143,13 +143,13 @@ 群組內的成員可以私訊群組內的成員。 %d 分鐘 %d 月 - 通話結束 %1$s + 通話結束 %1$s 取消檔案預覽 無法接收檔案 重複的顯示名稱! 一個單獨的 TCP 連接(和 SOCKS 憑證)將用於每個聯絡人和群組內的成員。 \n請注意:如果你有很多連接,你的電話電量和數據流量的消耗率會大大增加,一些連接有機會會連接失敗。 - 一個單獨的 TCP 連接(和 SOCKS 憑證)將用於 每個聊天室的設定 + 每個聊天室的設定。]]> 返回 省電模式運行中,關閉了背景通知服務和定期更新接收訊息。你可以在通知設定內重新啟用。 匿名聊天模式 @@ -161,7 +161,7 @@ 已連接 簡介 完整連結 - 你可以透過設定關閉 – 當應用程式運行時,通知服務仍然會運行。 + 你可以透過設定關閉 – 當應用程式運行時,通知服務仍然會運行。]]> 通知服務會一直在後台中運行 - 一但接收到新的訊息就會顯示在通知內。 此應用程式只會在運行中的時候才會接收訊息通知。 要求接收圖片 @@ -175,7 +175,7 @@ 建立一次性邀請連結 (分享給你的聯絡人) 點擊按鈕 - 感謝你安裝 SimpleX Chat + 感謝你安裝 SimpleX Chat! 靜音 解除靜音 你的設定 @@ -215,7 +215,7 @@ 實況 無效對話 無效數據 - 連接 %1$d + 連接 %1$d 已建立連接 已邀請連接 連接中… @@ -224,17 +224,17 @@ SimpleX 聯絡人地址 SimpleX 一次性邀請連結 SimpleX 連結 - 透過 %1$s + 透過 %1$s 透過瀏覽器 傳送訊息時出錯 聯絡人已存在 - 你已經連接到 %1$s + 你已經連接到 %1$s。 使用個人檔案(預設值)或使用連接(測試版)。 減少電量使用 更多改進即將推出! 意大利語言界面 感謝用戶 - 使用 Weblate 的翻譯貢獻! - SimpleX + SimpleX k 透過連結連接聯絡人? 透過邀請連結連接? @@ -245,7 +245,7 @@ 錯誤 連接中 你已連接到此聯絡人使用的伺服器以接收訊息。 - 嘗試連接至用於接收此聯絡人訊息的伺服器 (錯誤:%1$s)。 + 嘗試連接至用於接收此聯絡人訊息的伺服器 (錯誤:%1$s)。 正在嘗試連接到用於接收此聯絡人訊息伺服器。 已刪除 已標記為刪除 @@ -258,7 +258,7 @@ 請更新應用程式或聯絡開發人員。 連接超時 連接失敗 - 請使用 %1$s 檢查你的網路連接並且再試一次。 + 請使用 %1$s 檢查你的網路連接並且再試一次。 連接 定期通知已禁用! 需要使用密碼 @@ -299,7 +299,7 @@ 已傳送 未經授權傳送 傳送失敗 - 歡迎 %1$s + 歡迎 %1$s! 歡迎! 在設定中可用這文字 連接中… @@ -308,7 +308,7 @@ 連接中… 點擊以開啟新的對話 找不到檔案 - 語音訊息 (%1$s) + 語音訊息 (%1$s) 語音訊息… 錄製語音訊息 你需要在設定上開放權限允許你的聯絡人傳送語音訊息。 @@ -327,10 +327,10 @@ 安全佇列 刪除佇列 斷開連接 - 為了使用它,請 禁用電量優化 為了 SimpleX 在下一個對話中。否則,將禁用通知功能。 + 禁用電量優化 為了 SimpleX 在下一個對話中。否則,將禁用通知功能。]]> 在接收通知之前,請你輸入數據庫的密碼 應用程式會定期取得新的訊息 — 它每天會消耗百分之幾的電量。應用程式將不使用推送通知 — 你裝置中的數據不會傳送至伺服器。 - SimpleX Chat 服務 + SimpleX Chat 服務 正在接收訊息… 隱藏 SimpleX Chat 訊息 @@ -356,9 +356,9 @@ 未讀 你沒有對話記錄 解碼錯誤 - 你的聯絡人傳送的檔案大於目前支援的最大上限 (%1$s)。 + 你的聯絡人傳送的檔案大於目前支援的最大上限 (%1$s)。 只能同一時間傳送十張圖片 - 目前支援的最大檔案大小為 %1$s + 目前支援的最大檔案大小為 %1$s。 下載檔案需要傳送者上線的時候才能下載檔案,請等待對方上線! 語音訊息 傳送實況的訊息 @@ -366,7 +366,7 @@ 傳送實況訊息 - 這會即時顯示你在輸入中的文字 (掃描或使用剪貼薄貼上) 權限被拒絕! - 為了保護你的私隱,SimpleX 有一個後台通知服務 – 它每天使用百分之幾的電量。 + SimpleX 有一個後台通知服務 – 它每天使用百分之幾的電量。]]> 定期通知 每十分鐘會檢查一次訊息,最快可設為每分鐘檢查一次 訊息文字 @@ -408,7 +408,7 @@ 掃描二維碼 (僅由群組成員儲存) 想和你對話! - SimpleX 徽標 + SimpleX 徽標 透過連結連接 預設伺服器 你的伺服器地址 @@ -421,10 +421,10 @@ Onion 主機不會啟用。 連接 刪除聯絡地址 - 顏色 + 顏色 如何使用你的伺服器 使用連結連接 - 💻 桌面版:在應用程式內掃描一個已存在的二維碼,透過 掃描二維碼 + 掃描二維碼。]]> 設定 這個二維碼不是一個連結! 建立一次性邀請連結 @@ -433,7 +433,7 @@ simplexmq: v%s (%2s) 建立聯絡地址 編輯圖片 - 斜體 + 斜體 已拒絕通話 連接通話中… 等待對方確定… @@ -447,8 +447,8 @@ 刪除圖片 開始中 … 等待對方回應… - 如果你收到 SimepleX Chat 邀請連結,你可以使用瀏覧器開啟: - 📱 電話版: 點擊 使用電話程式開啟, 然後在程式內點擊 連接 + 如果你收到 SimepleX Chat 邀請連結,你可以使用瀏覧器開啟: + 使用電話程式開啟, 然後在程式內點擊 連接。]]> 如果你選擇拒絕,傳送者將不會收到通知。 拒絕 刪除 @@ -460,9 +460,9 @@ 二維碼 個人檔案頭像 預覧連結圖片 - SimpleX 地址 + SimpleX 地址 幫助 - SimpleX 團隊 + SimpleX 團隊 電郵 查看更多 顯示二維碼 @@ -473,15 +473,15 @@ 當群組的建立人上線,你便會成功連接至群組,請耐心等待! 當你的連接請求已被接受,你便會連接成功,請耐心等待! 當你的聯絡人上線,你便會連接成功,請耐心等待! - 如果你不能面對面接觸此聯絡人,可於視訊通話中出示你的二維碼,或者分享連結。 + 可於視訊通話中出示你的二維碼,或者分享連結。]]> 你的個人檔案會傳送給 \n你的聯絡人 將你接收到的連結貼上至下面的框內,以開啟你與你的聯絡人對話。 - 如果你不能面對面接觸此聯絡人,你可以於 視訊通話中掃描二維碼 ,或者你可以分享一個邀請連結給此聯絡人。 + 視訊通話中掃描二維碼 ,或者你可以分享一個邀請連結給此聯絡人。]]> 你的個人檔案會傳送給你的聯絡人 貼上 這些字串不是連接連結! - 你也可以點擊連結連接。如果在瀏覧器中開啟,點擊 在電話應用程式內的開啟 按鈕。 + 在電話應用程式內的開啟 按鈕。]]> 一次性邀請連結 掃描二維碼 錯誤的安全碼! @@ -494,9 +494,9 @@ 用於新的連接 無效的伺服器地址 此伺服器用於你目前的個人檔案 - 使用 SimpleX Chat 伺服器? + 使用 SimpleX Chat 伺服器? 你的 SMP 伺服器 - 目前使用 SimpleX Chat 伺服器。 + 目前使用 SimpleX Chat 伺服器。 如何 配置 ICE 伺服器 已儲存的 WebRTC ICE 伺服器將移除。 @@ -506,7 +506,7 @@ Onion 主機會在可用時啟用。 連接時將需要使用 Onion 主機。 刪除聯絡地址? - 你的個人檔案只會儲存於你的裝置和只會分享給你的聯絡人。 SimpleX 伺服器並不會看到你的個人檔案。 + 你的個人檔案只會儲存於你的裝置和只會分享給你的聯絡人。 SimpleX 伺服器並不會看到你的個人檔案。 儲存並通知你的聯絡人 儲存並通知你的多個聯絡人 你的個人檔案,聯絡人和傳送的訊息只會儲存於你的個人裝置內。 @@ -514,7 +514,7 @@ 建立 如何使用 Markdown 語法 你可以使用 Markdown 語法以更清楚標明訊息: - 刪除線 + 刪除線 你錯過了電話 接收到回應… 連接中… @@ -530,7 +530,7 @@ 我們不會在伺服器內儲存你的任何聯絡人和訊息(一旦傳送)。 建立個人檔案 已確認回應… - 你可以透過 連接到 SimpleX Chat 開發人員提出任何問題並同意更新 + 連接到 SimpleX Chat 開發人員提出任何問題並同意更新。]]> 開啟新的對話 設定聯絡人名稱 你已邀請了你的聯絡人 @@ -565,13 +565,13 @@ 透過群組連結使用匿名聊天模式 一個使用了匿名聊天模式的人透過連結加入了群組 透過使用一次性連結匿名聊天模式連接 - 有很多人問:如果 SimpleX 沒有任何的用戶標識符,它如何傳送訊息? + 如果 SimpleX 沒有任何的用戶標識符,它如何傳送訊息?]]> 即時 定期的 關閉 你錯過了通話 開啟 - 開啟 SimpleX Chat 以接受通話 + 開啟 SimpleX Chat 以接受通話 已拒絕通話 顯示 連接通話中 @@ -594,7 +594,7 @@ 點擊以加入 點擊以使用匿名聊天模式加入 %s 的身份已修改為 %s - 已經邀請 %1$s + 已經邀請 %1$s 已修改你的身份為 %s 連接中(已接受) 退出 @@ -604,7 +604,7 @@ 連接中 創建人 新的成員身份 - %1$s 位成員 + %1$s 位成員 修改群組內的設定 建立群組連結 建立連結 @@ -643,7 +643,7 @@ %s 秒(s) 加密數據庫時出錯 在金鑰庫儲存密碼 - 建立於 %1$s + 建立於 %1$s 還原數據庫的備份 群組為不活躍狀態 邀請連結過時! @@ -791,10 +791,10 @@ 受加密的數據庫密碼會再次更新。 刪除封存對話? 加密數據庫? - 邀請至群組 %1$s + 邀請至群組 %1$s 邀請成員 群組找不到! - 已移除 %1$s + 已移除 %1$s 已刪除群組 群組已經刪除 已邀請 @@ -802,7 +802,7 @@ 聯絡人允許 %ds 私人通知 - 可在 GitHub內查看更多。 + GitHub內查看更多。]]> 於 GitHub 儲存庫內查看更多。 視訊通話來電 掛斷電話來電 @@ -814,7 +814,7 @@ 封存對話 群組資料已經更新 成員 - 你:%1$s + 你:%1$s 刪除群組 即時訊息 封存對話 @@ -823,7 +823,7 @@ 群組 連接 直接 - 間接 (%1$s) + 間接 (%1$s) 伺服器 接收訊息透過 傳送訊息透過 @@ -873,17 +873,17 @@ 感謝用戶 - 使用 Weblate 的翻譯貢獻! 正在修改聯絡地址為 %s … 受加密的數據庫密碼會再次更新和儲存於金鑰庫。 - SimpleX 是怎樣運作 + SimpleX 是怎樣運作 當發生: \n1. 訊息將在傳送至客戶端後兩天或在伺服器內三十天時過時。 \n2. 訊息解密失敗,因為你或你的聯絡人用了舊的數據庫備份 \n3. 連接被破壞。 - 只有客戶端裝置才會儲存你的個人檔案、聯絡人,群組,所有訊息都會經過 兩層的端對端加密 + 兩層的端對端加密。]]> 請放置你的密碼於安全的地方,如果你遺失了密碼,將不可能修改你的密碼。 停止聊天室以匯出對話,匯入或刪除對話數據庫。當聊天室停止後你將不能接收或傳送訊息。 你正在使用匿名聊天模式進入此群組 - 為了避免分享你的真實個人檔案,邀請聯絡人是不允許的。 你傳送了一個群組連結 - 你移除了 %1$s + 你移除了 %1$s 你退出了群組 你修改了聯絡地址為 %s 連接中(邀請介紹階段) @@ -893,9 +893,9 @@ 透過一次性連結連接 傳輸隔離 更新傳輸隔離模式? - 為了保護隱私,而不像是其他平台般需要提取和存儲用戶的 IDs 資料, SimpleX 平台有自家佇列的標識符,這對於你的每個聯絡人也是獨一無二的。 + 為了保護隱私,而不像是其他平台般需要提取和存儲用戶的 IDs 資料, SimpleX 平台有自家佇列的標識符,這對於你的每個聯絡人也是獨一無二的。 當應用程式是運行中 - 你可以控制通過哪一個伺服器 來接收 你的聯絡人訊息 – 這些伺服器用來接收他們傳送給你的訊息。 + 來接收 你的聯絡人訊息 – 這些伺服器用來接收他們傳送給你的訊息。]]> 透過設定啟用於上鎖畫面顯示來電通知。 這操作不能還原 - 你目前的個人檔案,聯絡人,訊息和檔案將不可逆地遺失。 你必須在裝置上使用最新版本的對話數據庫,否則你可能會停止接收某些聯絡人的訊息。 @@ -916,7 +916,7 @@ 聯絡人頭像 個人檔案頭像占位符 不受垃圾郵件和濫用行為影響 - %1$s 希望透過以下方式聯絡你 + %1$s 希望透過以下方式聯絡你 開啟視訊 翻轉相機 待確認通話 @@ -924,7 +924,7 @@ 你的通話 經由分程傳遞連接 在上鎖畫面顯示來電通知: - %1$d 你錯過了多個訊息 + %1$d 你錯過了多個訊息 錯誤的訊息雜湊值 你錯過了多個訊息 @@ -1057,7 +1057,7 @@ SimpleX 鎖定模式 未啟用 SimpleX 鎖定! 主機 - 如果SOCKS 代理不支援它們,請設定 Use .onion hosts為否。 + Use .onion hosts為否。]]> 鎖定模式 密碼 已修改密碼! @@ -1120,11 +1120,11 @@ 系統 此ID的下一則訊息是錯誤(小於或等於上一則的)。 \n當一些錯誤出現或你的連結被破壞時會發生。 - %1$d 訊息解密失敗。 + %1$d 訊息解密失敗。 使用SOCKS 代理伺服器 你的 XFTP 伺服器 這個連結錯誤是永久性的,請重新連接。 - %1$d 錯過了多個訊息。 + %1$d 錯過了多個訊息。 影片和檔案和最大上限為1gb 影片 呈交 @@ -1170,7 +1170,7 @@ 黑暗主題 設定聯絡地址時出錯 開啟多個個人檔案 - 可在 內查看更多關於用戶指南的資料 + 內查看更多關於用戶指南的資料。]]> 自毁 啟用自毀密碼 修改自毀密碼 @@ -1262,4 +1262,6 @@ - 長達5分鐘的語音訊息。 \n- 自定義銷毀時間。 \n- 編輯紀錄。 + 搜尋 + 已關閉 \ No newline at end of file diff --git a/cabal.project b/cabal.project index 82e9949a58..e2edbe83eb 100644 --- a/cabal.project +++ b/cabal.project @@ -7,7 +7,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 54dc8d42e7594632daeadf0a0f115936b17165af + tag: fe22d9b299f106fc4a3d167e90499ddb4d3bfa26 source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 679b55456a..772ef9d864 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."54dc8d42e7594632daeadf0a0f115936b17165af" = "02lhlnwcyr3zmr11drmfwwmn6a54s7id9qzsdlqvi16dr5va245d"; + "https://github.com/simplex-chat/simplexmq.git"."fe22d9b299f106fc4a3d167e90499ddb4d3bfa26" = "1hk6cb7bh5nn3cj6wb38ap2kyg16ajff6mk5xj6vpjh5dgpp8hkb"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/kazu-yamamoto/http2.git"."b5a1b7200cf5bc7044af34ba325284271f6dff25" = "0dqb50j57an64nf4qcf5vcz4xkd1vzvghvf8bk529c1k30r9nfzb"; "https://github.com/simplex-chat/direct-sqlcipher.git"."34309410eb2069b029b8fc1872deb1e0db123294" = "0kwkmhyfsn2lixdlgl15smgr1h5gjk7fky6abzh8rng2h5ymnffd"; diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 6d7ab60e35..a42bb561dc 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -1084,6 +1084,7 @@ processChatCommand = \case APISetNetworkConfig cfg -> withUser' $ \_ -> withAgent (`setNetworkConfig` cfg) >> ok_ APIGetNetworkConfig -> withUser' $ \_ -> CRNetworkConfig <$> withAgent getNetworkConfig + ReconnectAllServers -> withUser' $ \_ -> withAgent reconnectAllServers >> ok_ APISetChatSettings (ChatRef cType chatId) chatSettings -> withUser $ \user -> case cType of CTDirect -> do ct <- withStore $ \db -> do @@ -4908,6 +4909,7 @@ chatCommandP = "/_network " *> (APISetNetworkConfig <$> jsonP), ("/network " <|> "/net ") *> (APISetNetworkConfig <$> netCfgP), ("/network" <|> "/net") $> APIGetNetworkConfig, + "/reconnect" $> ReconnectAllServers, "/_settings " *> (APISetChatSettings <$> chatRefP <* A.space <*> jsonP), "/_info #" *> (APIGroupMemberInfo <$> A.decimal <* A.space <*> A.decimal), "/_info @" *> (APIContactInfo <$> A.decimal), diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index 8e1bb3d143..08127bc66d 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -279,6 +279,7 @@ data ChatCommand | GetChatItemTTL | APISetNetworkConfig NetworkConfig | APIGetNetworkConfig + | ReconnectAllServers | APISetChatSettings ChatRef ChatSettings | APIContactInfo ContactId | APIGroupMemberInfo GroupId GroupMemberId diff --git a/stack.yaml b/stack.yaml index 12a92c8fdc..07fe72bfaa 100644 --- a/stack.yaml +++ b/stack.yaml @@ -49,7 +49,7 @@ extra-deps: # - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561 # - ../simplexmq - github: simplex-chat/simplexmq - commit: 54dc8d42e7594632daeadf0a0f115936b17165af + commit: fe22d9b299f106fc4a3d167e90499ddb4d3bfa26 - github: kazu-yamamoto/http2 commit: b5a1b7200cf5bc7044af34ba325284271f6dff25 # - ../direct-sqlcipher diff --git a/website/langs/ar.json b/website/langs/ar.json index a8c344ef10..24e00cc356 100644 --- a/website/langs/ar.json +++ b/website/langs/ar.json @@ -1,7 +1,7 @@ { "home": "الشاشة الرئيسية", "reference": "المرجع", - "blog": "مدونة", + "blog": "المدونة", "why-simplex": "لماذا SimpleX", "simplex-network": "شبكة SimpleX", "simplex-explained": "شرح SimpleX", @@ -13,7 +13,7 @@ "chat-bot-example": "مثال بوت الدردشة", "smp-protocol": "بروتوكول SMP", "chat-protocol": "بروتوكول الدردشة", - "donate": "تبرع", + "donate": "تبرّع", "terminal-cli": "طرفية CLI", "terms-and-privacy-policy": "الشروط وسياسة الخصوصية", "hero-header": "إعادة تعريف الخصوصية", @@ -35,7 +35,7 @@ "simplex-chat-protocol": "بروتوكول دردشة SimpleX", "developers": "المطورين", "hero-subheader": "أول نظام مراسلة
بدون معرفات المستخدم", - "hero-p-1": "تحتوي التطبيقات الأخرى على معرّفات مستخدم: Signal ،Matrix ،Session ،Briar ،Jami ،Cwtch وما إلى ذلك.
SimpleX ليس لديه، ولا حتى أرقام عشوائية .
وهذا يحسن خصوصيتك بشكل جذري.", + "hero-p-1": "تحتوي التطبيقات الأخرى على معرّفات مستخدم: Signal ،Matrix ،Session ،Briar ،Jami ،Cwtch وما إلى ذلك.
SimpleX ليس لديه، ولا حتى أرقام عشوائية.
وهذا يحسن خصوصيتك بشكل جذري.", "features": "الميزات", "hero-2-header": "قم بإجراء اتصال خاص", "hero-overlay-1-title": "كيف يعمل SimpleX؟", @@ -80,7 +80,7 @@ "hero-overlay-card-1-p-4": "هذا التصميم يمنع تسريب أي البيانات الوصفية للمستخدمين على مستوى التطبيق. لزيادة تحسين الخصوصية وحماية عنوان IP الخاص بك، يمكنك الاتصال بخوادم المراسلة عبر Tor.", "hero-overlay-card-1-p-5": "الأجهزة العميلة فقط هي التي تخزن ملفات تعريف المستخدمين، جهات الاتصال والمجموعات؛ يتم إرسال الرسائل بتشفير ثنائي الطبقة من طرف إلى طرف.", "hero-overlay-card-2-p-2": "يمكنهم بعد ذلك ربط هذه المعلومات بالشبكات الاجتماعية العامة الحالية، وتحديد بعض الهويات الحقيقية.", - "simplex-network-overlay-card-1-li-3": "P2P لا يحل مشكلة هجوم الوسيط (MITM) ، ومعظم التطبيقات الحالية لا تستخدم خارج النطاق رسائل للتبادل الأولي للمفاتيح. يستخدم SimpleX رسائل خارج النطاق أو، في بعض الحالات، اتصالات آمنة وموثوق بها موجودة مسبقًا لتبادل المفاتيح الأولي.", + "simplex-network-overlay-card-1-li-3": "P2P لا يحل مشكلة هجوم الوسيط (MITM)، ومعظم التطبيقات الحالية لا تستخدم خارج النطاق رسائل للتبادل الأولي للمفاتيح. يستخدم SimpleX رسائل خارج النطاق أو، في بعض الحالات، اتصالات آمنة وموثوق بها موجودة مسبقًا لتبادل المفاتيح الأولي.", "privacy-matters-overlay-card-1-p-3": "تستخدم بعض الشركات المالية والتأمين رسوماً بيانية اجتماعية لتحديد أسعار الفائدة وأقساط التأمين. عادةً ما تجعل الأشخاص ذوي الدخل المنخفض يدفعون أكثر — أو كما يسمى \"علاوة الفقر\".", "privacy-matters-overlay-card-1-p-2": "يعرف تجار التجزئة عبر الإنترنت أن الأشخاص ذوي الدخل المنخفض هم أكثر عرضة لإجراء عمليات شراء عاجلة، لذلك قد يفرضون أسعارًا أعلى أو يزيلون الخصومات.", "simplex-private-6-title": "تبديل
خارج النطاق", @@ -100,19 +100,19 @@ "hero-overlay-card-1-p-3": "أنت تحدد الخادم (الخوادم) المراد استخدامه لتلقي الرسائل وجهات الاتصال الخاصة بك — الخوادم التي تستخدمها لإرسال الرسائل إليهم. من المرجح أن تستخدم كل محادثة خادمين مختلفين.", "hero-overlay-card-1-p-1": "سأل العديد من المستخدمين: إذا لم يكن لدى SimpleX معرفات مستخدم، فكيف يمكنها معرفة مكان تسليم الرسائل؟ ", "hero-overlay-card-1-p-2": "لتقديم الرسائل، بدلاً من معرفات المستخدم التي تستخدمها جميع المنصات الأخرى، يستخدم SimpleX معرفات مزدوجة مؤقتة مجهولة الهوية لقوائم انتظار الرسائل، مختلفة لكل اتصال من اتصالاتك — لا توجد معرفات مستخدم دائمة.", - "simplex-network-overlay-card-1-p-1": " P2P بروتوكولات المراسلة والتطبيقات بها مشاكل مختلفة تجعلها أقل موثوقية من SimpleX وأكثر تعقيدًا في التحليل و عرضة لعدة أنواع من الهجمات.", + "simplex-network-overlay-card-1-p-1": "بروتوكولات المراسلة والتطبيقات P2P بها مشاكل مختلفة تجعلها أقل موثوقية من SimpleX وأكثر تعقيدًا في التحليل و عرضة لعدة أنواع من الهجمات.", "hero-overlay-card-2-p-1": "عندما يكون لدى المستخدمين هويات ثابتة، حتى لو كان هذا مجرد رقم عشوائي، مثل معرف الجلسة، فهناك خطر يتمثل في أن الموفر أو المهاجم يمكنه مراقبة كيفية اتصال المستخدمين وعدد الرسائل التي يرسلونها.", "hero-overlay-card-1-p-6": "اقرأ المزيد في SimpleX whitepaper .", "hero-overlay-card-2-p-3": "حتى مع معظم التطبيقات الخاصة التي تستخدم خدمات Tor v3، إذا تحدثت إلى جهتي اتصال مختلفتين عبر نفس الملف الشخصي، فيمكنهما إثبات أنهما متصلان بنفس الشخص.", "hero-overlay-card-2-p-4": "يحمي SimpleX من هذه الهجمات من خلال عدم وجود أي معرفات مستخدم في تصميمه. وإذا كنت تستخدم وضع التصفح المتخفي، فسيكون لديك اسم عرض مختلف لكل جهة اتصال، مع تجنب أي بيانات مشتركة بينهما.", - "simplex-network-overlay-card-1-li-6": "قد تكون شبكات P2P عرضة هجوم DRDoS ، عندما يتمكن العملاء من إعادة بث حركة مرور البيانات وتضخيمها، مما يؤدي إلى رفض الخدمة على مستوى الشبكة. يقوم عملاء SimpleX فقط بترحيل حركة مرور البيانات من اتصال معروف ولا يمكن للمهاجم استخدامها لتضخيم حركة مرور البيانات في الشبكة بالكامل.", + "simplex-network-overlay-card-1-li-6": "قد تكون شبكات P2P عرضة هجوم DRDoS، عندما يتمكن العملاء من إعادة بث حركة مرور البيانات وتضخيمها، مما يؤدي إلى رفض الخدمة على مستوى الشبكة. يقوم عملاء SimpleX فقط بترحيل حركة مرور البيانات من اتصال معروف ولا يمكن للمهاجم استخدامها لتضخيم حركة مرور البيانات في الشبكة بالكامل.", "simplex-network-overlay-card-1-li-1": "تعتمد شبكات P2P على بعض المتغيرات من DHT لتوجيه الرسائل. يجب أن توازن تصميمات DHT بين ضمان التسليم وزمن الوصول. تتمتع SimpleX بضمان تسليم أفضل وزمن انتقال أقل من P2P، لأنه يمكن تمرير الرسالة بشكل متكرر عبر عدة خوادم بالتوازي، باستخدام الخوادم التي اختارها المستلم. في شبكات P2P، يتم تمرير الرسالة عبر عُقد O (log N) بالتسلسل، باستخدام العقد التي تختارها الخوارزمية.", "simplex-network-overlay-card-1-li-2": "لا يحتوي تصميم SimpleX، عكس معظم شبكات P2P، على معرّفات مستخدم عالمية من أي نوع، حتى مؤقتة، ويستخدم فقط المعرّفات المزدوجة المؤقتة، مما يوفر إخفاء هوية أفضل وحماية للبيانات الوصفية.", "simplex-network-overlay-card-1-li-4": "يمكن لبعض مزودي خدمة الإنترنت حظر تطبيقات P2P (مثل BitTorrent ). SimpleX حيادي النقل - يمكنه العمل عبر بروتوكولات الويب القياسية، على سبيل المثال WebSockets.", - "simplex-network-overlay-card-1-li-5": "قد تكون جميع شبكات P2P المعروفة عرضة لهجوم Sybil ، لأن كل عقدة قابلة للاكتشاف، وتعمل الشبكة ككل. تتطلب الإجراءات المعروفة لتخفيفها إما مكونًا مركزيًا أو إثبات عمل مكلف . لا تحتوي شبكة SimpleX على إمكانية اكتشاف الخادم، فهي مجزأة وتعمل كشبكات فرعية متعددة ومعزولة، مما يجعل الهجمات على مستوى الشبكة مستحيلة.", + "simplex-network-overlay-card-1-li-5": "قد تكون جميع شبكات P2P المعروفة عرضة لهجوم Sybil، لأن كل عقدة قابلة للاكتشاف، وتعمل الشبكة ككل. تتطلب الإجراءات المعروفة لتخفيفها إما مكونًا مركزيًا أو إثبات عمل مكلف . لا تحتوي شبكة SimpleX على إمكانية اكتشاف الخادم، فهي مجزأة وتعمل كشبكات فرعية متعددة ومعزولة، مما يجعل الهجمات على مستوى الشبكة مستحيلة.", "privacy-matters-overlay-card-3-p-1": "يجب على الجميع الاهتمام بخصوصية وأمان اتصالاتهم — يمكن للمحادثات غير الضارة أن تعرضك للخطر، حتى لو لم يكن لديك ما تخفيه.", "privacy-matters-overlay-card-3-p-4": "لا يكفي استخدام برنامج مراسلة مشفر من طرف إلى طرف، يجب علينا جميعًا استخدام برامج المراسلة التي تحمي خصوصية شبكاتنا الشخصية — مع من نحن مرتبطون.", - "simplex-unique-overlay-card-1-p-3": "يحمي هذا التصميم خصوصية الأشخاص الذين تتواصل معهم، ويخفيها عن خوادم منصة SimpleX ومن أي مراقبين. لإخفاء عنوان IP الخاص بك من الخوادم، يمكنك الاتصال بخوادم SimpleX عبر Tor .", + "simplex-unique-overlay-card-1-p-3": "يحمي هذا التصميم خصوصية الأشخاص الذين تتواصل معهم، ويخفيها عن خوادم منصة SimpleX ومن أي مراقبين. لإخفاء عنوان IP الخاص بك من الخوادم، يمكنك الاتصال بخوادم SimpleX عبر Tor.", "simplex-unique-overlay-card-2-p-1": "نظرًا لعدم وجود معرف لديك على نظام SimpleX، لا يمكن لأي شخص الاتصال بك ما لم تشارك عنوان مستخدم لمرة واحدة أو مؤقتًا، كرمز QR أو رابط.", "simplex-unique-overlay-card-2-p-2": "حتى مع عنوان المستخدم الاختياري، بينما يمكن استخدامه لإرسال طلبات جهات اتصال غير مرغوب فيها، يمكنك تغييره أو حذفه بالكامل دون فقد أي من اتصالاتك.", "simplex-unique-overlay-card-3-p-2": "يتم الاحتفاظ بالرسائل المشفرة من طرف إلى طرف مؤقتًا على خوادم ترحيل SimpleX حتى يتم استلامها، ثم يتم حذفها نهائيًا.", @@ -128,8 +128,8 @@ "simplex-unique-overlay-card-3-p-1": "يخزن SimpleX Chat جميع بيانات المستخدم على أجهزة العميل فقط باستخدام تنسيق قاعدة بيانات محمولة مشفرة يمكن تصديرها ونقلها إلى أي جهاز مدعوم.", "simplex-unique-overlay-card-3-p-3": "على عكس خوادم الشبكات الموحدة (البريد الإلكتروني أو XMPP أو Matrix)، لا تقوم خوادم SimpleX بتخزين حسابات المستخدمين، فهي تقوم فقط بترحيل الرسائل، مما يحمي خصوصية كلا الطرفين.", "simplex-unique-overlay-card-4-p-1": "يمكنك استخدام SimpleX مع الخوادم الخاصة بك والاستمرار في التواصل مع الأشخاص الذين يستخدمون الخوادم المهيأة مسبقًا التي نقدمها.", - "simplex-unique-overlay-card-4-p-3": "إذا كنت تفكر في التطوير لمنصة SimpleX، على سبيل المثال، بوت الدردشة لمستخدمي تطبيق SimpleX، أو دمج مكتبة SimpleX Chat في تطبيقات الأجهزة المحمولة، من فضلك تواصل معي لأي نصيحة والدعم.", - "donate-here-to-help-us": "تبرع هنا لمساعدتنا", + "simplex-unique-overlay-card-4-p-3": "إذا كنت تفكر في التطوير لمنصة SimpleX، على سبيل المثال، بوت الدردشة لمستخدمي تطبيق SimpleX، أو دمج مكتبة SimpleX Chat في تطبيقات الأجهزة المحمولة، من فضلك تواصل معي لأي نصيحة والدعم.", + "donate-here-to-help-us": "تبرّع هنا لمساعدتنا", "sign-up-to-receive-our-updates": "اشترك للحصول على آخر مستجداتنا", "enter-your-email-address": "أدخل عنوان بريدك الإلكتروني", "get-simplex": "احصل على SimpleX", @@ -154,13 +154,13 @@ "no-federated": "لا - فدرالي", "comparison-section-list-point-2": "العناوين تعتمد على الـDNS", "comparison-section-list-point-3": "المفتاح العام أو معرف آخر فريد وعام", - "comparison-section-list-point-7": "شبكات P2P إما لديها سلطة مركزية أو أن الشبكة كلها يمكن تسويتها", + "comparison-section-list-point-7": "شبكات P2P إما لديها سلطة مركزية أو أن الشبكة كلها يمكن عرضة للخطر", "see-here": "اقرأ هنا", "no-secure": "لا - آمن", "comparison-section-list-point-5": "لا يحمي المعلومات الوصفية للمستخدمين", - "comparison-section-list-point-6": "على الرغم من أن الـP2P موزعة، إلا أنها ليست فدرالية - يشتغلوا على نفس الشبكة", + "comparison-section-list-point-6": "على الرغم من أن الـP2P موزعة، إلا أنها ليست فدرالية - يعملون كشبكة واحدة", "comparison-section-list-point-1": "عادة ما يكون مكوناً من رقم الهاتف، أو اسم المستخدم في بعض الأحيان", - "comparison-section-list-point-4": "إذا ما تم تسوية خوادم المشغل", + "comparison-section-list-point-4": "إذا خوادم المشغّل مُخترقة", "simplex-unique-card-3-p-1": "يخزن SimpleX جميع بيانات المستخدم على الأجهزة العميلة بتنسيق قاعدة بيانات محمولة مشفرة — يمكن نقله إلى جهاز آخر.", "simplex-unique-card-4-p-1": "شبكة SimpleX لا مركزية بالكامل ومستقلة عن أي عملة مشفرة أو أي منصة أخرى، بخلاف الإنترنت.", "simplex-unique-card-4-p-2": "يمكنك استخدام SimpleX مع خوادمك الخاصة أو مع الخوادم التي نوفرها — ولا يزال الاتصال ممكن بأي مستخدم.", @@ -168,7 +168,7 @@ "we-invite-you-to-join-the-conversation": "نحن ندعوك للانضمام إلى محادثة", "join-the-REDDIT-community": "انضم إلى مجتمع REDDIT", "join-us-on-GitHub": "انضم إلينا على GitHub", - "contact-hero-p-2": "لم يتم تنزيل SimpleX Chat حتى الآن؟", + "contact-hero-p-2": "لم تقم بتنزيل SimpleX Chat حتى الآن؟", "contact-hero-p-3": "استخدم الروابط في الاسفل لتنزيل التطبيق.", "scan-qr-code-from-mobile-app": "امسح رمز QR من تطبيق الجوال", "to-make-a-connection": "لإجراء اتصال:", @@ -216,7 +216,7 @@ "guide-dropdown-4": "ملفات تعريف الدردشة", "guide-dropdown-5": "إدارة البيانات", "guide-dropdown-6": "مكالمات الصوت والفيديو", - "guide-dropdown-7": "الخصوصية و أمن", + "guide-dropdown-7": "الخصوصية والأمن", "guide-dropdown-8": "إعدادات التطبيق", "guide-dropdown-9": "إجراء اتصالات", "docs-dropdown-4": "استضافة خادم SMP", @@ -229,8 +229,8 @@ "on-this-page": "على هذه الصفحة", "back-to-top": "عد إلى الأعلى", "docs-dropdown-1": "منصة SimpleX", - "guide": "دليل", + "guide": "الدليل", "docs-dropdown-2": "الوصول إلى ملفات اندرويد", "docs-dropdown-3": "الوصول إلى قاعدة بيانات الدردشة", - "glossary": "معجم" + "glossary": "المعجم" } diff --git a/website/langs/ja.json b/website/langs/ja.json index b1b39782a2..8f18655f58 100644 --- a/website/langs/ja.json +++ b/website/langs/ja.json @@ -4,5 +4,7 @@ "blog": "ブログ", "features": "特徴", "why-simplex": "SimpleX を選ぶ理由", - "simplex-privacy": "SimpleXのプライバシー" + "simplex-privacy": "SimpleXのプライバシー", + "back-to-top": "トップへ戻る", + "glossary": "用語集" } diff --git a/website/langs/zh_Hans.json b/website/langs/zh_Hans.json index 6d9c13b14e..4a1bbcf2d3 100644 --- a/website/langs/zh_Hans.json +++ b/website/langs/zh_Hans.json @@ -228,7 +228,7 @@ "docs-dropdown-5": "托管 XFTP 服务器", "newer-version-of-eng-msg": "本页面有较新的英语版本。", "guide-dropdown-4": "聊天档案", - "guide-dropdown-6": "音视频通话", + "guide-dropdown-6": "语音和视频通话", "guide-dropdown-9": "建立连接", "back-to-top": "回到页首", "on-this-page": "在此页面上",