From 3c07a2d044852762d77b2203904b471b8c667446 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Fri, 15 Jul 2022 18:15:28 +1000 Subject: [PATCH] Added linting for the localized strings, updated the quote & mention behaviour for the current user Added a script and build step to error if we have localised a string in code bug don't have an entry in the localisable files Added the logic and UI to replace the current users public key (or blinded key) with 'You' in mentions and quotes Cleaned up some duplicate & missing localised strings Fixed a bug where new closed groups weren't getting setup locally correctly Updated the id truncating behaviour to always truncate from the middle --- Scripts/LintLocalizableStrings.swift | 251 ++++++++++++++++++ Session.xcodeproj/project.pbxproj | 36 +++ .../Call Management/SessionCallManager.swift | 3 +- .../Conversations/ConversationViewModel.swift | 16 +- .../Conversations/Input View/InputView.swift | 2 + .../Content Views/QuoteView.swift | 24 +- .../Message Cells/VisibleMessageCell.swift | 4 + .../Views & Modals/BodyTextView.swift | 28 ++ Session/Home/HomeViewModel.swift | 12 + .../MessageRequestsViewModel.swift | 13 + .../GIFs/GifPickerViewController.swift | 2 +- .../Translations/de.lproj/Localizable.strings | 29 +- .../Translations/en.lproj/Localizable.strings | 30 ++- .../Translations/es.lproj/Localizable.strings | 29 +- .../Translations/fa.lproj/Localizable.strings | 29 +- .../Translations/fi.lproj/Localizable.strings | 29 +- .../Translations/fr.lproj/Localizable.strings | 29 +- .../Translations/hi.lproj/Localizable.strings | 29 +- .../Translations/hr.lproj/Localizable.strings | 29 +- .../id-ID.lproj/Localizable.strings | 29 +- .../Translations/it.lproj/Localizable.strings | 29 +- .../Translations/ja.lproj/Localizable.strings | 29 +- .../Translations/nl.lproj/Localizable.strings | 29 +- .../Translations/pl.lproj/Localizable.strings | 29 +- .../pt_BR.lproj/Localizable.strings | 29 +- .../Translations/ru.lproj/Localizable.strings | 29 +- .../Translations/si.lproj/Localizable.strings | 29 +- .../Translations/sk.lproj/Localizable.strings | 29 +- .../Translations/sv.lproj/Localizable.strings | 29 +- .../Translations/th.lproj/Localizable.strings | 29 +- .../vi-VN.lproj/Localizable.strings | 29 +- .../zh-Hant.lproj/Localizable.strings | 29 +- .../zh_CN.lproj/Localizable.strings | 29 +- Session/Notifications/AppNotifications.swift | 10 +- Session/Onboarding/LinkDeviceVC.swift | 6 +- Session/Settings/QRCodeVC.swift | 4 +- Session/Shared/FullConversationCell.swift | 16 +- .../HighlightMentionBackgroundView.swift | 161 +++++++++++ Session/Shared/ScanQRCodeWrapperVC.swift | 2 +- Session/Utilities/MentionUtilities.swift | 65 ++++- .../Database/Models/Profile.swift | 9 +- .../Database/Models/SessionThread.swift | 34 +++ .../MessageSender+ClosedGroups.swift | 6 +- .../Shared Models/MessageViewModel.swift | 27 +- .../SessionThreadViewModel.swift | 63 +++++ SessionSnodeKit/Models/SnodeAPIEndpoint.swift | 2 + SessionUIKit/Components/SearchBar.swift | 2 +- SessionUtilitiesKit/Crypto/Mnemonic.swift | 10 +- .../AttachmentTextToolbar.swift | 2 +- .../Screen Lock/OWSScreenLock.swift | 29 +- .../Utilities/CommonStrings.swift | 42 +-- SignalUtilitiesKit/Utilities/OWSAlerts.swift | 19 -- 52 files changed, 1369 insertions(+), 170 deletions(-) create mode 100755 Scripts/LintLocalizableStrings.swift create mode 100644 Session/Shared/HighlightMentionBackgroundView.swift diff --git a/Scripts/LintLocalizableStrings.swift b/Scripts/LintLocalizableStrings.swift new file mode 100755 index 000000000..3f0860735 --- /dev/null +++ b/Scripts/LintLocalizableStrings.swift @@ -0,0 +1,251 @@ +#!/usr/bin/xcrun --sdk macosx swift + +// +// ListLocalizableStrings.swift +// Archa +// +// Created by Morgan Pretty on 18/5/20. +// Copyright © 2020 Archa. All rights reserved. +// +// This script is based on https://github.com/ginowu7/CleanSwiftLocalizableExample the main difference +// is canges to the localized usage regex + +import Foundation + +let fileManager = FileManager.default +let currentPath = ( + ProcessInfo.processInfo.environment["PROJECT_DIR"] ?? fileManager.currentDirectoryPath +) + +/// List of files in currentPath - recursive +var pathFiles: [String] = { + guard let enumerator = fileManager.enumerator(atPath: currentPath), let files = enumerator.allObjects as? [String] else { + fatalError("Could not locate files in path directory: \(currentPath)") + } + + return files +}() + + +/// List of localizable files - not including Localizable files in the Pods +var localizableFiles: [String] = { + return pathFiles + .filter { + $0.hasSuffix("Localizable.strings") && + !$0.contains(".app/") && // Exclude Built Localizable.strings files + !$0.contains("Pods") // Exclude Pods + } +}() + + +/// List of executable files +var executableFiles: [String] = { + return pathFiles.filter { + !$0.localizedCaseInsensitiveContains("test") && // Exclude test files + !$0.contains(".app/") && // Exclude Built Localizable.strings files + !$0.contains("Pods") && // Exclude Pods + ( + NSString(string: $0).pathExtension == "swift" || + NSString(string: $0).pathExtension == "m" + ) + } +}() + +/// Reads contents in path +/// +/// - Parameter path: path of file +/// - Returns: content in file +func contents(atPath path: String) -> String { + print("Path: \(path)") + guard let data = fileManager.contents(atPath: path), let content = String(data: data, encoding: .utf8) else { + fatalError("Could not read from path: \(path)") + } + + return content +} + +/// Returns a list of strings that match regex pattern from content +/// +/// - Parameters: +/// - pattern: regex pattern +/// - content: content to match +/// - Returns: list of results +func regexFor(_ pattern: String, content: String) -> [String] { + guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { + fatalError("Regex not formatted correctly: \(pattern)") + } + + let matches = regex.matches(in: content, options: [], range: NSRange(location: 0, length: content.utf16.count)) + + return matches.map { + guard let range = Range($0.range(at: 0), in: content) else { + fatalError("Incorrect range match") + } + + return String(content[range]) + } +} + +func create() -> [LocalizationStringsFile] { + return localizableFiles.map(LocalizationStringsFile.init(path:)) +} + +/// +/// +/// - Returns: A list of LocalizationCodeFile - contains path of file and all keys in it +func localizedStringsInCode() -> [LocalizationCodeFile] { + return executableFiles.compactMap { + let content = contents(atPath: $0) + // Note: Need to exclude escaped quotation marks from strings + let matchesOld = regexFor("(?<=NSLocalizedString\\()\\s*\"(?!.*?%d)(.*?)\"", content: content) + let matchesNew = regexFor("\"(?!.*?%d)([^(\\\")]*?)\"(?=\\s*)(?=\\.localized)", content: content) + let allMatches = (matchesOld + matchesNew) + + return allMatches.isEmpty ? nil : LocalizationCodeFile(path: $0, keys: Set(allMatches)) + } +} + +/// Throws error if ALL localizable files does not have matching keys +/// +/// - Parameter files: list of localizable files to validate +func validateMatchKeys(_ files: [LocalizationStringsFile]) { + print("------------ Validating keys match in all localizable files ------------") + + guard let base = files.first, files.count > 1 else { return } + + let files = Array(files.dropFirst()) + + files.forEach { + guard let extraKey = Set(base.keys).symmetricDifference($0.keys).first else { return } + let incorrectFile = $0.keys.contains(extraKey) ? $0 : base + printPretty("error: Found extra key: \(extraKey) in file: \(incorrectFile.path)") + } +} + +/// Throws error if localizable files are missing keys +/// +/// - Parameters: +/// - codeFiles: Array of LocalizationCodeFile +/// - localizationFiles: Array of LocalizableStringFiles +func validateMissingKeys(_ codeFiles: [LocalizationCodeFile], localizationFiles: [LocalizationStringsFile]) { + print("------------ Checking for missing keys -----------") + + guard let baseFile = localizationFiles.first else { + fatalError("Could not locate base localization file") + } + + let baseKeys = Set(baseFile.keys) + + codeFiles.forEach { + let extraKeys = $0.keys.subtracting(baseKeys) + if !extraKeys.isEmpty { + printPretty("error: Found keys in code missing in strings file: \(extraKeys) from \($0.path)") + } + } +} + +/// Throws warning if keys exist in localizable file but are not being used +/// +/// - Parameters: +/// - codeFiles: Array of LocalizationCodeFile +/// - localizationFiles: Array of LocalizableStringFiles +func validateDeadKeys(_ codeFiles: [LocalizationCodeFile], localizationFiles: [LocalizationStringsFile]) { + print("------------ Checking for any dead keys in localizable file -----------") + + guard let baseFile = localizationFiles.first else { + fatalError("Could not locate base localization file") + } + + let baseKeys: Set = Set(baseFile.keys) + let allCodeFileKeys: [String] = codeFiles.flatMap { $0.keys } + let deadKeys: [String] = Array(baseKeys.subtracting(allCodeFileKeys)) + .sorted() + .map { $0.trimmingCharacters(in: CharacterSet(charactersIn: "\"")) } + + if !deadKeys.isEmpty { + printPretty("warning: \(deadKeys) - Suggest cleaning dead keys") + } +} + +protocol Pathable { + var path: String { get } +} + +struct LocalizationStringsFile: Pathable { + let path: String + let kv: [String: String] + + var keys: [String] { + return Array(kv.keys) + } + + init(path: String) { + self.path = path + self.kv = ContentParser.parse(path) + } + + /// Writes back to localizable file with sorted keys and removed whitespaces and new lines + func cleanWrite() { + print("------------ Sort and remove whitespaces: \(path) ------------") + let content = kv.keys.sorted().map { "\($0) = \(kv[$0]!);" }.joined(separator: "\n") + try! content.write(toFile: path, atomically: true, encoding: .utf8) + } + +} + +struct LocalizationCodeFile: Pathable { + let path: String + let keys: Set +} + +struct ContentParser { + + /// Parses contents of a file to localizable keys and values - Throws error if localizable file have duplicated keys + /// + /// - Parameter path: Localizable file paths + /// - Returns: localizable key and value for content at path + static func parse(_ path: String) -> [String: String] { + print("------------ Checking for duplicate keys: \(path) ------------") + + let content = contents(atPath: path) + let trimmed = content + .replacingOccurrences(of: "\n+", with: "", options: .regularExpression, range: nil) + .trimmingCharacters(in: .whitespacesAndNewlines) + let keys = regexFor("\"([^\"]*?)\"(?= =)", content: trimmed) + let values = regexFor("(?<== )\"(.*?)\"(?=;)", content: trimmed) + + if keys.count != values.count { + fatalError("Error parsing contents: Make sure all keys and values are in correct format (this could be due to extra spaces between keys and values)") + } + + return zip(keys, values).reduce(into: [String: String]()) { results, keyValue in + if results[keyValue.0] != nil { + printPretty("error: Found duplicate key: \(keyValue.0) in file: \(path)") + abort() + } + results[keyValue.0] = keyValue.1 + } + } +} + +func printPretty(_ string: String) { + print(string.replacingOccurrences(of: "\\", with: "")) +} + +let stringFiles = create() + +if !stringFiles.isEmpty { + print("------------ Found \(stringFiles.count) file(s) ------------") + + stringFiles.forEach { print($0.path) } + validateMatchKeys(stringFiles) + + // Note: Uncomment the below file to clean out all comments from the localizable file (we don't want this because comments make it readable...) + // stringFiles.forEach { $0.cleanWrite() } + + let codeFiles = localizedStringsInCode() + validateMissingKeys(codeFiles, localizationFiles: stringFiles) + validateDeadKeys(codeFiles, localizationFiles: stringFiles) +} + +print("------------ SUCCESS ------------") diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index c6c3c63e1..4ed98f633 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -781,6 +781,7 @@ FDD250702837199200198BDA /* GarbageCollectionJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */; }; FDD250722837234B00198BDA /* MediaGalleryNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */; }; FDE72118286C156E0093DF33 /* ChatSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE72117286C156E0093DF33 /* ChatSettingsViewController.swift */; }; + FDE72154287FE4470093DF33 /* HighlightMentionBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE72153287FE4470093DF33 /* HighlightMentionBackgroundView.swift */; }; FDE77F6B280FEB28002CFC5D /* ControlMessageProcessRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */; }; FDED2E3C282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */; }; FDF0B73C27FFD3D6004C14C5 /* LinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73B27FFD3D6004C14C5 /* LinkPreview.swift */; }; @@ -1811,6 +1812,9 @@ FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarbageCollectionJob.swift; sourceTree = ""; }; FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryNavigationController.swift; sourceTree = ""; }; FDE72117286C156E0093DF33 /* ChatSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatSettingsViewController.swift; sourceTree = ""; }; + FDE7214F287E50D50093DF33 /* ProtoWrappers.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = ProtoWrappers.py; sourceTree = ""; }; + FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LintLocalizableStrings.swift; sourceTree = ""; }; + FDE72153287FE4470093DF33 /* HighlightMentionBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightMentionBackgroundView.swift; sourceTree = ""; }; FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobRunnerError.swift; sourceTree = ""; }; FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlMessageProcessRecord.swift; sourceTree = ""; }; FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+ReusableView.swift"; sourceTree = ""; }; @@ -2436,6 +2440,7 @@ 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */, 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */, 34386A53207D271C009F5D9C /* NeverClearView.swift */, + FDE72153287FE4470093DF33 /* HighlightMentionBackgroundView.swift */, 34F308A01ECB469700BB7697 /* OWSBezierPathView.h */, 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */, 34330AA11E79686200DF2FB9 /* OWSProgressView.h */, @@ -3306,6 +3311,7 @@ FD83B9BC27CF2215005E1583 /* SharedTest */, FDC4388F27B9FFC700C60D73 /* SessionMessagingKitTests */, FD83B9B027CF200A005E1583 /* SessionUtilitiesKitTests */, + FDE7214E287E50D50093DF33 /* Scripts */, D221A08C169C9E5E00537ABF /* Frameworks */, D221A08A169C9E5E00537ABF /* Products */, 2BADBA206E0B8D297E313FBA /* Pods */, @@ -3871,6 +3877,15 @@ path = Utilities; sourceTree = ""; }; + FDE7214E287E50D50093DF33 /* Scripts */ = { + isa = PBXGroup; + children = ( + FDE7214F287E50D50093DF33 /* ProtoWrappers.py */, + FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */, + ); + path = Scripts; + sourceTree = ""; + }; FDF0B7452804F0A8004C14C5 /* Types */ = { isa = PBXGroup; children = ( @@ -4141,6 +4156,7 @@ buildConfigurationList = D221A0BC169C9E5F00537ABF /* Build configuration list for PBXNativeTarget "Session" */; buildPhases = ( 0401967CF3320CC84B175A3B /* [CP] Check Pods Manifest.lock */, + FDE7214D287E50820093DF33 /* Lint Localizable.strings */, D221A085169C9E5E00537ABF /* Sources */, D221A086169C9E5E00537ABF /* Frameworks */, D221A087169C9E5E00537ABF /* Resources */, @@ -4768,6 +4784,25 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + FDE7214D287E50820093DF33 /* Lint Localizable.strings */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Lint Localizable.strings"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Scripts/LintLocalizableStrings.swift\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -5261,6 +5296,7 @@ 7B1581E6271FD2A100848B49 /* VideoPreviewVC.swift in Sources */, B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */, 3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */, + FDE72154287FE4470093DF33 /* HighlightMentionBackgroundView.swift in Sources */, 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */, 4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */, 34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */, diff --git a/Session/Calls/Call Management/SessionCallManager.swift b/Session/Calls/Call Management/SessionCallManager.swift index b21d98f13..30dbcdfa0 100644 --- a/Session/Calls/Call Management/SessionCallManager.swift +++ b/Session/Calls/Call Management/SessionCallManager.swift @@ -40,8 +40,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol { } static func buildProviderConfiguration(useSystemCallLog: Bool) -> CXProviderConfiguration { - let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "Name of application") - let providerConfiguration = CXProviderConfiguration(localizedName: localizedName) + let providerConfiguration = CXProviderConfiguration(localizedName: "Session") providerConfiguration.supportsVideo = true providerConfiguration.maximumCallGroups = 1 providerConfiguration.maximumCallsPerCallGroup = 1 diff --git a/Session/Conversations/ConversationViewModel.swift b/Session/Conversations/ConversationViewModel.swift index 4ab71302e..4cc9d64a7 100644 --- a/Session/Conversations/ConversationViewModel.swift +++ b/Session/Conversations/ConversationViewModel.swift @@ -86,7 +86,10 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { // also want to skip the initial query and trigger it async so that the push animation // doesn't stutter (it should load basically immediately but without this there is a // distinct stutter) - self.pagedDataObserver = self.setupPagedObserver(for: threadId) + self.pagedDataObserver = self.setupPagedObserver( + for: threadId, + userPublicKey: getUserHexEncodedPublicKey() + ) // Run the initial query on a background thread so we don't block the push transition DispatchQueue.global(qos: .default).async { [weak self] in @@ -164,7 +167,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { } } - private func setupPagedObserver(for threadId: String) -> PagedDatabaseObserver { + private func setupPagedObserver(for threadId: String, userPublicKey: String) -> PagedDatabaseObserver { return PagedDatabaseObserver( pagedTable: Interaction.self, pageSize: ConversationViewModel.pageSize, @@ -201,6 +204,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { groupSQL: MessageViewModel.groupSQL, orderSQL: MessageViewModel.orderSQL, dataQuery: MessageViewModel.baseQuery( + userPublicKey: userPublicKey, orderSQL: MessageViewModel.orderSQL, groupSQL: MessageViewModel.groupSQL ), @@ -316,7 +320,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { // it's the last element in the 'sortedData' array index == (sortedData.count - 1) && pageInfo.pageOffset == 0 - ) + ), + currentUserBlindedPublicKey: threadData.currentUserBlindedPublicKey ) } .appending(typingIndicator) @@ -491,7 +496,10 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { self.threadId = updatedThreadId self.observableThreadData = self.setupObservableThreadData(for: updatedThreadId) - self.pagedDataObserver = self.setupPagedObserver(for: updatedThreadId) + self.pagedDataObserver = self.setupPagedObserver( + for: updatedThreadId, + userPublicKey: getUserHexEncodedPublicKey() + ) // Try load everything up to the initial visible message, fallback to just the initial page of messages // if we don't have one diff --git a/Session/Conversations/Input View/InputView.swift b/Session/Conversations/Input View/InputView.swift index a61783967..474c4d6db 100644 --- a/Session/Conversations/Input View/InputView.swift +++ b/Session/Conversations/Input View/InputView.swift @@ -228,6 +228,8 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M authorId: quoteDraftInfo.model.authorId, quotedText: quoteDraftInfo.model.body, threadVariant: threadVariant, + currentUserPublicKey: nil, + currentUserBlindedPublicKey: nil, direction: (quoteDraftInfo.isOutgoing ? .outgoing : .incoming), attachment: quoteDraftInfo.model.attachment, hInset: hInset, diff --git a/Session/Conversations/Message Cells/Content Views/QuoteView.swift b/Session/Conversations/Message Cells/Content Views/QuoteView.swift index 16b91f6ca..2a47a91d9 100644 --- a/Session/Conversations/Message Cells/Content Views/QuoteView.swift +++ b/Session/Conversations/Message Cells/Content Views/QuoteView.swift @@ -28,6 +28,8 @@ final class QuoteView: UIView { authorId: String, quotedText: String?, threadVariant: SessionThread.Variant, + currentUserPublicKey: String?, + currentUserBlindedPublicKey: String?, direction: Direction, attachment: Attachment?, hInset: CGFloat, @@ -43,6 +45,8 @@ final class QuoteView: UIView { authorId: authorId, quotedText: quotedText, threadVariant: threadVariant, + currentUserPublicKey: currentUserPublicKey, + currentUserBlindedPublicKey: currentUserBlindedPublicKey, direction: direction, attachment: attachment, hInset: hInset, @@ -63,6 +67,8 @@ final class QuoteView: UIView { authorId: String, quotedText: String?, threadVariant: SessionThread.Variant, + currentUserPublicKey: String?, + currentUserBlindedPublicKey: String?, direction: Direction, attachment: Attachment?, hInset: CGFloat, @@ -190,6 +196,8 @@ final class QuoteView: UIView { MentionUtilities.highlightMentions( in: $0, threadVariant: threadVariant, + currentUserPublicKey: currentUserPublicKey, + currentUserBlindedPublicKey: currentUserBlindedPublicKey, isOutgoingMessage: isOutgoing, attributes: [:] ) @@ -207,11 +215,21 @@ final class QuoteView: UIView { // Label stack view var authorLabelHeight: CGFloat? if threadVariant == .openGroup || threadVariant == .closedGroup { + let isCurrentUser: Bool = [ + currentUserPublicKey, + currentUserBlindedPublicKey, + ] + .compactMap { $0 } + .asSet() + .contains(authorId) let authorLabel = UILabel() authorLabel.lineBreakMode = .byTruncatingTail - authorLabel.text = Profile.displayName( - id: authorId, - threadVariant: threadVariant + authorLabel.text = (isCurrentUser ? + "MEDIA_GALLERY_SENDER_NAME_YOU".localized() : + Profile.displayName( + id: authorId, + threadVariant: threadVariant + ) ) authorLabel.textColor = textColor authorLabel.font = .boldSystemFont(ofSize: Values.smallFontSize) diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index 248ee419a..ccb099d8e 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -459,6 +459,8 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel authorId: quote.authorId, quotedText: quote.body, threadVariant: cellViewModel.threadVariant, + currentUserPublicKey: cellViewModel.currentUserPublicKey, + currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey, direction: (cellViewModel.variant == .standardOutgoing ? .outgoing : .incoming @@ -956,6 +958,8 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel attributedString: MentionUtilities.highlightMentions( in: (cellViewModel.body ?? ""), threadVariant: cellViewModel.threadVariant, + currentUserPublicKey: cellViewModel.currentUserPublicKey, + currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey, isOutgoingMessage: isOutgoing, attributes: [ .foregroundColor : textColor, diff --git a/Session/Conversations/Views & Modals/BodyTextView.swift b/Session/Conversations/Views & Modals/BodyTextView.swift index d329bd972..358333594 100644 --- a/Session/Conversations/Views & Modals/BodyTextView.swift +++ b/Session/Conversations/Views & Modals/BodyTextView.swift @@ -9,10 +9,29 @@ import UIKit // • The long press interaction that shows the context menu should still work final class BodyTextView: UITextView { private let snDelegate: BodyTextViewDelegate? + private let highlightedMentionBackgroundView: HighlightMentionBackgroundView = HighlightMentionBackgroundView() + + override var attributedText: NSAttributedString! { + didSet { + guard attributedText != nil else { return } + + highlightedMentionBackgroundView.maxPadding = highlightedMentionBackgroundView + .calculateMaxPadding(for: attributedText) + highlightedMentionBackgroundView.frame = self.bounds.insetBy( + dx: -highlightedMentionBackgroundView.maxPadding, + dy: -highlightedMentionBackgroundView.maxPadding + ) + } + } init(snDelegate: BodyTextViewDelegate?) { self.snDelegate = snDelegate + super.init(frame: CGRect.zero, textContainer: nil) + + self.clipsToBounds = false // Needed for the 'HighlightMentionBackgroundView' + addSubview(highlightedMentionBackgroundView) + setUpGestureRecognizers() } @@ -39,6 +58,15 @@ final class BodyTextView: UITextView { @objc private func handleDoubleTap() { // Do nothing } + + override func layoutSubviews() { + super.layoutSubviews() + + highlightedMentionBackgroundView.frame = self.bounds.insetBy( + dx: -highlightedMentionBackgroundView.maxPadding, + dy: -highlightedMentionBackgroundView.maxPadding + ) + } } protocol BodyTextViewDelegate { diff --git a/Session/Home/HomeViewModel.swift b/Session/Home/HomeViewModel.swift index 72505ee99..a6c99443b 100644 --- a/Session/Home/HomeViewModel.swift +++ b/Session/Home/HomeViewModel.swift @@ -252,6 +252,11 @@ public class HomeViewModel { 0 : self.state.unreadMessageRequestThreadCount ) + let groupedOldData: [String: [SessionThreadViewModel]] = (self.threadData + .first(where: { $0.model == .threads })? + .elements) + .defaulting(to: []) + .grouped(by: \.threadId) return [ // If there are no unread message requests then hide the message request banner @@ -275,6 +280,13 @@ public class HomeViewModel { return lhs.lastInteractionDate > rhs.lastInteractionDate } + .map { viewModel -> SessionThreadViewModel in + viewModel.populatingCurrentUserBlindedKey( + currentUserBlindedPublicKeyForThisThread: groupedOldData[viewModel.threadId]? + .first? + .currentUserBlindedPublicKey + ) + } ) ], (!data.isEmpty && (pageInfo.pageOffset + pageInfo.currentCount) < pageInfo.totalCount ? diff --git a/Session/Home/Message Requests/MessageRequestsViewModel.swift b/Session/Home/Message Requests/MessageRequestsViewModel.swift index 96a7c69ad..c19ff8538 100644 --- a/Session/Home/Message Requests/MessageRequestsViewModel.swift +++ b/Session/Home/Message Requests/MessageRequestsViewModel.swift @@ -140,12 +140,25 @@ public class MessageRequestsViewModel { } private func process(data: [SessionThreadViewModel], for pageInfo: PagedData.PageInfo) -> [SectionModel] { + let groupedOldData: [String: [SessionThreadViewModel]] = (self.threadData + .first(where: { $0.model == .threads })? + .elements) + .defaulting(to: []) + .grouped(by: \.threadId) + return [ [ SectionModel( section: .threads, elements: data .sorted { lhs, rhs -> Bool in lhs.lastInteractionDate > rhs.lastInteractionDate } + .map { viewModel -> SessionThreadViewModel in + viewModel.populatingCurrentUserBlindedKey( + currentUserBlindedPublicKeyForThisThread: groupedOldData[viewModel.threadId]? + .first? + .currentUserBlindedPublicKey + ) + } ) ], (!data.isEmpty && (pageInfo.pageOffset + pageInfo.currentCount) < pageInfo.totalCount ? diff --git a/Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift b/Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift index 980e985c6..ce215af26 100644 --- a/Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift +++ b/Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift @@ -105,7 +105,7 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect // Loki: Customize title let titleLabel = UILabel() - titleLabel.text = NSLocalizedString("GIF", comment: "") + titleLabel.text = "accessibility_gif_button".localized().uppercased() titleLabel.textColor = Colors.text titleLabel.font = .boldSystemFont(ofSize: Values.veryLargeFontSize) navigationItem.titleView = titleLabel diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 764cc21f7..0138af276 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Kamera"; "accessibility_main_button_collapse" = "Optionen für Anhänge einklappen"; "invalid_recovery_phrase" = "Ungültige Wiederherstellungsphrase"; -"invalid_recovery_phrase" = "Ungültige Wiederherstellungsphrase"; "DISMISS_BUTTON_TEXT" = "Verwerfen"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Einstellungen"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Fehler"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentifizierung gescheitert."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Zu viele gescheiterte Authentifizierungsversuche. Bitte versuche es später erneut."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Du musst einen Passcode in deinen iOS-Einstellungen festlegen, um die Bildschirmsperre zu verwenden."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Du musst einen Passcode in deinen iOS-Einstellungen festlegen, um die Bildschirmsperre zu verwenden."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Du musst einen Passcode in deinen iOS-Einstellungen festlegen, um die Bildschirmsperre zu verwenden."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index bbdfe3f4e..18d73b302 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Invalid Recovery Phrase"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Dismiss"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Settings"; @@ -653,11 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; - +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index 6a4ca17e0..76abb2b87 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Cámara"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Frase de Recuperación Incorrecta"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Descartar"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Ajustes"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Fallo"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Fallo en la identificación."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Demasiados intentos fallidos. Prueda de nuevo más tarde."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Necesitas configurar un código en «Ajustes» de iOS para poder usar el bloqueo de acceso."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Necesitas configurar un código en «Ajustes» de iOS para poder usar el bloqueo de acceso."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Necesitas configurar un código en «Ajustes» de iOS para poder usar el bloqueo de acceso."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index f742bc0bc..60d6d71ee 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Invalid Recovery Phrase"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Dismiss"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Settings"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "خطاء"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "احراز هویت ناموفق بود."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "چندین احراز هویت ناموفق رخ داد. لطفا بعدا تلاش کنید."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "برای استفاده از قفل صفحه نمایش می بایستی یک رمزعبور از تنظیمات iOS خود فعال کنید."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "شما برای استفاده از قفل صفحه نمایس می بایستی یک رمزعبور از تنظیمات iOS خود فعال کنید."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "برای استفاده از قفل صفحه نمایش می بایستی یک رمزعبور از تنظیمات iOS فعال کنید."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index e8e512296..47b43d082 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Kamera"; "accessibility_main_button_collapse" = "Tiivistä liiteasetukset"; "invalid_recovery_phrase" = "Virheellinen Palautuslauseke"; -"invalid_recovery_phrase" = "Virheellinen palautuslauseke"; "DISMISS_BUTTON_TEXT" = "Hylkää"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Asetukset"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Tunnistautuminen epäonnistui"; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Liian monta epäonnistunutta tunnistautumista. Yritä myöhemmin uudelleen."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Aseta pääsykoodi puhelimesi asetuksista, jotta voit käyttää näytön lukitusta."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Aseta pääsykoodi puhelimesi asetuksista, jotta voit käyttää näytön lukitusta."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Aseta pääsykoodi puhelimesi asetuksista, jotta voit käyttää näytön lukitusta."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index 729b1a90d..ee7ccbf84 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Caméra"; "accessibility_main_button_collapse" = "Réduire les options de pièces jointes"; "invalid_recovery_phrase" = "Phrase de récupération incorrecte"; -"invalid_recovery_phrase" = "Phrase de récupération incorrecte"; "DISMISS_BUTTON_TEXT" = "Fermer"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Paramètres"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "Vous pouvez activer la permission \"Appels vocaux et vidéo\" dans les paramètres de confidentialité."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Erreur"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Échec d’authentification"; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Trop d’essais infructueux d’authentification. Veuillez réessayer plus tard."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Vous devez activer un code dans vos réglages iOS pour utiliser le verrou d’écran."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Vous devez activer un code dans vos réglages iOS pour utiliser le verrou d’écran."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Vous devez activer un code dans vos réglages iOS pour utiliser le verrou d’écran."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index d9589c6a4..86a98157a 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Invalid Recovery Phrase"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Dismiss"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Settings"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "प्रमाणीकरण असफल"; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "बहुत सारी असफल प्रमाणीकरण की कोशिशें हुई हैं। कृपया थोङी देर बाद कोशिश करें।"; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "सक्रीन लॉक इस्तेमाल करने के लिये अपने iOS सेटिंग्स से पासकोड की अनुमति दें।"; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "सक्रीन लॉक इस्तेमाल करने के लिये अपने iOS सेटिंग्स से पासकोड की अनुमति दें।"; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "सक्रीन लॉक इस्तेमाल करने के लिये अपने iOS सेटिंग्स से पासकोड की अनुमति दें।"; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index 2aaa1e710..4b4b3f6ca 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Kamera"; "accessibility_main_button_collapse" = "Sažmi opcije privitka"; "invalid_recovery_phrase" = "Nevažeća fraza za oporavak"; -"invalid_recovery_phrase" = "Nevažeća fraza za oporavak"; "DISMISS_BUTTON_TEXT" = "Odbaci"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Postavke"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Provjera autentičnosti nije uspjela."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Previše neuspjelih pokušaja provjere autentičnosti. Pokušajte ponovo kasnije."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Kako biste koristili Zaključavanje zaslona, morate omogućiti lozinku u postavkama iOS-a."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Kako biste koristili Zaključavanje zaslona, morate omogućiti lozinku u postavkama iOS-a."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Kako biste koristili Zaključavanje zaslona, morate omogućiti lozinku u postavkama iOS-a."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index 227258661..b1376c4db 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Invalid Recovery Phrase"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Dismiss"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Settings"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Galat"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 5c0f62aec..007cac231 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Fotocamera"; "accessibility_main_button_collapse" = "Comprimi opzioni allegato"; "invalid_recovery_phrase" = "Frase Di Recupero non valida"; -"invalid_recovery_phrase" = "Frase Di Ripristino Non Valida"; "DISMISS_BUTTON_TEXT" = "Chiudi"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Impostazioni"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "È possibile abilitare l'autorizzazione 'Voce e video chiamate' nelle Impostazioni Privacy."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Errore"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Autenticazione non riuscita."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Troppi tentativi di autenticazione non riusciti. Riprova più tardi."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Devi abilitare una password nelle impostazioni di iOS per poter usare il blocco schermo."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Devi abilitare una password nelle impostazioni di iOS per poter usare il blocco schermo."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Devi abilitare una password nelle impostazioni di iOS per poter usare il blocco schermo."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index 34f322714..f554a0bcb 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "カメラ"; "accessibility_main_button_collapse" = "添付ファイルのオプションを閉じる"; "invalid_recovery_phrase" = "無効な復元フレーズ"; -"invalid_recovery_phrase" = "無効な復元フレーズ"; "DISMISS_BUTTON_TEXT" = "中止"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "設定"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "プライバシー設定から音声とビデオ通話の許可を有効にできます。"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "エラー"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "認証に失敗しました。"; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "認証失敗が多すぎます。あとで再度試してください。"; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "画面ロックを使用するには、iOSの設定でパスコードを有効にしてください。"; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "画面ロックを使用するには、iOSの設定でパスコードを有効にしてください。"; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "画面ロックを使用するには、iOSの設定でパスコードを有効にしてください。"; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index af4d90a7f..d2280bc06 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Bijlage-opties inklappen"; "invalid_recovery_phrase" = "Ongeldig Herstelzin"; -"invalid_recovery_phrase" = "Ongeldig Herstelzin"; "DISMISS_BUTTON_TEXT" = "Negeren"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Instellingen"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authenticatie mislukt."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Te veel pogingen tot authenticatie. Probeer het later opnieuw."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Om appvergrendeling te kunnen gebruiken, moet je een toegangscode instellen in de iOS-instellingen."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Om appvergrendeling te kunnen gebruiken, moet je een toegangscode instellen in de iOS-instellingen."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Om appvergrendeling te kunnen gebruiken, moet je een toegangscode instellen in de iOS-instellingen."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 6cef8f942..7d53e7b81 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Aparat"; "accessibility_main_button_collapse" = "Zwiń opcje załączników"; "invalid_recovery_phrase" = "Nieprawidłowa fraza odzyskiwania"; -"invalid_recovery_phrase" = "Nieprawidłowa fraza odzyskiwania"; "DISMISS_BUTTON_TEXT" = "Odrzuć"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Ustawienia"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "Możesz włączyć uprawnienie 'Połączenia głosowe i wideo' w Ustawieniach Prywatności."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Błąd"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Uwierzytelnianie nie powiodło się."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Zbyt wiele błędnych logowań. Spróbuj później."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Musisz włączyć kod dostępu w Ustawieniach systemu iOS, aby korzystać z blokady ekranu."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Musisz włączyć kod dostępu w Ustawieniach systemu iOS, aby korzystać z blokady ekranu."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Musisz włączyć kod dostępu w Ustawieniach systemu iOS, aby korzystać z blokady ekranu."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 1ebe65929..8e5856689 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Câmera"; "accessibility_main_button_collapse" = "Recolher opções de anexo"; "invalid_recovery_phrase" = "Frase de Recuperação inválida"; -"invalid_recovery_phrase" = "Frase de Recuperação inválida"; "DISMISS_BUTTON_TEXT" = "Ignorar"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Configurações"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Erro"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Falha na autenticação."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Você excedeu o número máximo permitido de tentativas de autenticação. Por favor, tente novamente mais tarde."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Você deve criar uma senha no app Ajustes do iOS para usar bloqueio de tela."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Você deve criar uma senha no app Ajustes do iOS para usar o bloqueio de tela."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Você deve criar uma senha no app Ajustes do iOS para usar o bloqueio de tela."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index cf4e35c0c..8e0c3f534 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Камера"; "accessibility_main_button_collapse" = "Свернуть параметры вложений"; "invalid_recovery_phrase" = "Неверная секретная фраза"; -"invalid_recovery_phrase" = "Неверная секретная фраза"; "DISMISS_BUTTON_TEXT" = "Закрыть"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Настройки"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Ошибка"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Ошибка аутентификации."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Слишком много неудачных попыток аутентификации. Пожалуйста, повторите попытку позже."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Вы должны включить код доступа в приложении «Настройки», чтобы использовать блокировку экрана."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Вы должны включить код доступа в приложении «Настройки», чтобы использовать блокировку экрана."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Вы должны включить код доступа в приложении «Настройки», чтобы использовать блокировку экрана."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index 826878f56..bd1d4fd91 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Invalid Recovery Phrase"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Dismiss"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "සැකසුම්"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index c6330a516..6632f0943 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Kamera"; "accessibility_main_button_collapse" = "Uzatvor možnosti prípon"; "invalid_recovery_phrase" = "Neplatná Obnovovacia Fráza"; -"invalid_recovery_phrase" = "Neplatná Obnovovacia Fráza"; "DISMISS_BUTTON_TEXT" = "Zrušiť"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Nastavenia"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Autentifikácia zlyhala"; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Priveľa nepodarených pokusov o autentifikáciu. Prosím, skúste to znovu neskôr."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Pre používanie zámku obrazovky, zapnite kódový zámok v nastaveniach iOS."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Pre používanie zámku obrazovky, zapnite kódový zámok v nastaveniach iOS."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Pre používanie zámku obrazovky, zapnite kódový zámok v nastaveniach iOS."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index 92138867f..afee13e19 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Kamera"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Invalid Recovery Phrase"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Dismiss"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Inställningar"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Autentisering misslyckades."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "För många misslyckade autentiseringsförsök. Försök igen senare."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "Du måste aktivera en lösenkod i dina iOS-inställningar för att använda Skärmlås."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "Du måste aktivera en lösenkod i dina iOS-inställningar för att använda Skärmlås."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "Du måste aktivera en lösenkod i dina iOS-inställningar för att använda Skärmlås."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index 6545dea2d..6b9f85dec 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Invalid Recovery Phrase"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Dismiss"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Settings"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "การรับรองความถูกต้องไม่สำเร็จ"; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "รับรองความถูกต้องไม่สำเร็จหลายครั้งเกินไป โปรดลองใหม่ในภายหลัง"; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "คุณต้องเปิดใช้งานรหัสผ่านในการตั้งค่า iOS ของคุณเพื่อใช้งานการล็อกหน้าจอ"; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "คุณต้องเปิดใช้งานรหัสผ่านในการตั้งค่า iOS ของคุณเพื่อใช้งานการล็อกหน้าจอ"; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "คุณต้องเปิดใช้งานรหัสผ่านในการตั้งค่า iOS ของคุณเพื่อใช้งานการล็อกหน้าจอ"; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index 58c025221..6b5e5594b 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "Camera"; "accessibility_main_button_collapse" = "Collapse attachment options"; "invalid_recovery_phrase" = "Invalid Recovery Phrase"; -"invalid_recovery_phrase" = "Invalid Recovery Phrase"; "DISMISS_BUTTON_TEXT" = "Dismiss"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "Settings"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index f47db9db0..c389b1514 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "相機"; "accessibility_main_button_collapse" = "摺疊附件選項"; "invalid_recovery_phrase" = "備援暗語無效"; -"invalid_recovery_phrase" = "恢復短語無效"; "DISMISS_BUTTON_TEXT" = "關閉"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "設定"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "You can enable the 'Voice and video calls' permission in the Privacy Settings."; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "Error"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "Authentication failed."; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "Too many failed authentication attempts. Please try again later."; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "You must enable a passcode in your iOS Settings in order to use Screen Lock."; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index 820ba3c80..68bdf9b6b 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -606,7 +606,6 @@ "accessibility_camera_button" = "相机"; "accessibility_main_button_collapse" = "收起附件选项"; "invalid_recovery_phrase" = "恢复口令无效"; -"invalid_recovery_phrase" = "恢复口令无效"; "DISMISS_BUTTON_TEXT" = "取消"; /* Button text which opens the settings app */ "OPEN_SETTINGS_BUTTON" = "设置"; @@ -653,10 +652,36 @@ "modal_call_permission_request_explanation" = "您可以在隐私设置中启用“语音和视频通话”权限。"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred"; "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later"; -"ALERT_ERROR_TITLE" = "错误"; "LOADING_CONVERSATIONS" = "Loading Conversations..."; "DATABASE_MIGRATION_FAILED" = "An error occurred when optimising the database\n\nYou can export your application logs to be able to share for troubleshooting or you can restore our device\n\nWarning: Restoring your device will result in loss of any data older than two weeks"; "CHATS_TITLE" = "Chats"; "MESSAGE_TRIMMING_TITLE" = "Message Trimming"; "MESSAGE_TRIMMING_OPEN_GROUP_TITLE" = "Delete Old Open Group Messages"; "MESSAGE_TRIMMING_OPEN_GROUP_DESCRIPTION" = "Automatically delete messages which are older than 6 months from open groups with over 2,000 messages when starting the app"; +"RECOVERY_PHASE_ERROR_GENERIC" = "Something went wrong. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LENGTH" = "Looks like you didn't enter enough words. Please check your recovery phrase and try again."; +"RECOVERY_PHASE_ERROR_LAST_WORD" = "You seem to be missing the last word of your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_INVALID_WORD" = "There appears to be an invalid word in your recovery phrase. Please check what you entered and try again."; +"RECOVERY_PHASE_ERROR_FAILED" = "Your recovery phrase couldn't be verified. Please check what you entered and try again."; +/* Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode. */ +"SCREEN_LOCK_ENABLE_UNKNOWN_ERROR" = "Authentication could not be accessed."; +/* Indicates that Touch ID/Face ID/Phone Passcode authentication failed. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED" = "认证失败。"; +/* Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT" = "认证失败次数太多,请稍后再试。"; +/* Indicates that Touch ID/Face ID/Phone Passcode are not available on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE" = "您需要先设置您的密码来开启屏幕锁功能。"; +/* Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED" = "您需要先设置您的密码来开启屏幕锁功能。"; +/* Indicates that Touch ID/Face ID/Phone Passcode passcode is not set. */ +"SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET" = "您需要先设置您的密码来开启屏幕锁功能。"; +/* Label for the button to send a message */ +"SEND_BUTTON_TITLE" = "Send"; +/* Generic text for button that retries whatever the last action was. */ +"RETRY_BUTTON_TEXT" = "Retry"; +/* notification action */ +"SHOW_THREAD_BUTTON_TITLE" = "Show Chat"; +/* notification body */ +"SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; +"INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; +"INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; diff --git a/Session/Notifications/AppNotifications.swift b/Session/Notifications/AppNotifications.swift index 49491f158..96463a3f8 100644 --- a/Session/Notifications/AppNotifications.swift +++ b/Session/Notifications/AppNotifications.swift @@ -224,11 +224,19 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { let userInfo = [ AppNotificationUserInfoKey.threadId: thread.id ] + + let userPublicKey: String = getUserHexEncodedPublicKey(db) + let userBlindedKey: String? = SessionThread.getUserHexEncodedBlindedKey( + threadId: thread.id, + threadVariant: thread.variant + ) DispatchQueue.main.async { notificationBody = MentionUtilities.highlightMentions( in: (notificationBody ?? ""), - threadVariant: thread.variant + threadVariant: thread.variant, + currentUserPublicKey: userPublicKey, + currentUserBlindedPublicKey: userBlindedKey ) let sound: Preferences.Sound? = self.requestSound(thread: thread) diff --git a/Session/Onboarding/LinkDeviceVC.swift b/Session/Onboarding/LinkDeviceVC.swift index 2d14ab3f9..5791ee005 100644 --- a/Session/Onboarding/LinkDeviceVC.swift +++ b/Session/Onboarding/LinkDeviceVC.swift @@ -128,7 +128,11 @@ final class LinkDeviceVC : BaseVC, UIPageViewControllerDataSource, UIPageViewCon func continueWithSeed(_ seed: Data) { if (seed.count != 16) { - let alert = UIAlertController(title: NSLocalizedString("invalid_recovery_phrase", comment: ""), message: NSLocalizedString("Please check the Recovery Phrase and try again.", comment: ""), preferredStyle: .alert) + let alert = UIAlertController( + title: "invalid_recovery_phrase".localized(), + message: "INVALID_RECOVERY_PHRASE_MESSAGE".localized(), + preferredStyle: .alert + ) alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: { _ in self.scanQRCodeWrapperVC.startCapture() })) diff --git a/Session/Settings/QRCodeVC.swift b/Session/Settings/QRCodeVC.swift index 4376809ea..be39795b0 100644 --- a/Session/Settings/QRCodeVC.swift +++ b/Session/Settings/QRCodeVC.swift @@ -121,7 +121,9 @@ final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControl fileprivate func startNewPrivateChatIfPossible(with hexEncodedPublicKey: String) { if !ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) { - let alert = UIAlertController(title: NSLocalizedString("invalid_session_id", comment: ""), message: NSLocalizedString("Please check the Session ID and try again.", comment: ""), preferredStyle: .alert) + let alert = UIAlertController( + title: "invalid_session_id".localized(), + message: "INVALID_SESSION_ID_MESSAGE".localized(), preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: nil)) presentAlert(alert) } diff --git a/Session/Shared/FullConversationCell.swift b/Session/Shared/FullConversationCell.swift index 92ffebb8a..ebf55e4c2 100644 --- a/Session/Shared/FullConversationCell.swift +++ b/Session/Shared/FullConversationCell.swift @@ -267,6 +267,8 @@ public final class FullConversationCell: UITableViewCell { cellViewModel.authorName(for: .contact) : nil ), + currentUserPublicKey: cellViewModel.currentUserPublicKey, + currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey, searchText: searchText.lowercased(), fontSize: Values.smallFontSize ) @@ -288,6 +290,8 @@ public final class FullConversationCell: UITableViewCell { timestampLabel.isHidden = true displayNameLabel.attributedText = getHighlightedSnippet( content: cellViewModel.displayName, + currentUserPublicKey: cellViewModel.currentUserPublicKey, + currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey, searchText: searchText.lowercased(), fontSize: Values.mediumFontSize ) @@ -299,6 +303,8 @@ public final class FullConversationCell: UITableViewCell { bottomLabelStackView.isHidden = (cellViewModel.threadMemberNames ?? "").isEmpty snippetLabel.attributedText = getHighlightedSnippet( content: (cellViewModel.threadMemberNames ?? ""), + currentUserPublicKey: cellViewModel.currentUserPublicKey, + currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey, searchText: searchText.lowercased(), fontSize: Values.smallFontSize ) @@ -440,7 +446,9 @@ public final class FullConversationCell: UITableViewCell { attachmentCount: cellViewModel.interactionAttachmentCount, isOpenGroupInvitation: (cellViewModel.interactionIsOpenGroupInvitation == true) ), - threadVariant: cellViewModel.threadVariant + threadVariant: cellViewModel.threadVariant, + currentUserPublicKey: cellViewModel.currentUserPublicKey, + currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey ), attributes: [ .font: font, @@ -454,6 +462,8 @@ public final class FullConversationCell: UITableViewCell { private func getHighlightedSnippet( content: String, authorName: String? = nil, + currentUserPublicKey: String, + currentUserBlindedPublicKey: String?, searchText: String, fontSize: CGFloat ) -> NSAttributedString { @@ -473,7 +483,9 @@ public final class FullConversationCell: UITableViewCell { // we don't want to include the truncated id as part of the name so we exclude it let mentionReplacedContent: String = MentionUtilities.highlightMentions( in: content, - threadVariant: .contact + threadVariant: .contact, + currentUserPublicKey: currentUserPublicKey, + currentUserBlindedPublicKey: currentUserBlindedPublicKey ) let result: NSMutableAttributedString = NSMutableAttributedString( string: mentionReplacedContent, diff --git a/Session/Shared/HighlightMentionBackgroundView.swift b/Session/Shared/HighlightMentionBackgroundView.swift new file mode 100644 index 000000000..1b9a593ba --- /dev/null +++ b/Session/Shared/HighlightMentionBackgroundView.swift @@ -0,0 +1,161 @@ +// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. + +import UIKit + +public extension NSAttributedString.Key { + static let currentUserMentionBackgroundColor: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundColor") + static let currentUserMentionBackgroundCornerRadius: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundCornerRadius") + static let currentUserMentionBackgroundPadding: NSAttributedString.Key = NSAttributedString.Key(rawValue: "currentUserMentionBackgroundPadding") +} + +class HighlightMentionBackgroundView: UIView { + var maxPadding: CGFloat = 0 + + init() { + super.init(frame: .zero) + + self.isOpaque = false + self.layer.zPosition = -1 + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Functions + + public func calculateMaxPadding(for attributedText: NSAttributedString) -> CGFloat { + var allMentionRadii: [CGFloat?] = [] + let path: CGMutablePath = CGMutablePath() + path.addRect(CGRect( + x: 0, + y: 0, + width: CGFloat.greatestFiniteMagnitude, + height: CGFloat.greatestFiniteMagnitude + )) + + let framesetter = CTFramesetterCreateWithAttributedString(attributedText as CFAttributedString) + let frame: CTFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributedText.length), path, nil) + let lines: [CTLine] = frame.lines + + lines.forEach { line in + let runs: [CTRun] = line.ctruns + + runs.forEach { run in + let attributes: NSDictionary = CTRunGetAttributes(run) + allMentionRadii.append( + attributes + .value(forKey: NSAttributedString.Key.currentUserMentionBackgroundPadding.rawValue) as? CGFloat + ) + } + } + + return allMentionRadii + .compactMap { $0 } + .max() + .defaulting(to: 0) + } + + // MARK: - Drawing + + override func draw(_ rect: CGRect) { + guard + let superview: UITextView = (self.superview as? UITextView), + let context = UIGraphicsGetCurrentContext() + else { return } + + // Need to invery the Y axis because iOS likes to render from the bottom left instead of the top left + context.textMatrix = .identity + context.translateBy(x: 0, y: bounds.size.height) + context.scaleBy(x: 1.0, y: -1.0) + + // Note: Calculations MUST happen based on the 'superview' size as this class has extra padding which + // can result in calculations being off + let path = CGMutablePath() + let size = superview.sizeThatFits(CGSize(width: superview.bounds.width, height: .greatestFiniteMagnitude)) + path.addRect(CGRect(x: 0, y: 0, width: size.width, height: size.height), transform: .identity) + + let framesetter = CTFramesetterCreateWithAttributedString(superview.attributedText as CFAttributedString) + let frame: CTFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, superview.attributedText.length), path, nil) + let lines: [CTLine] = frame.lines + + var origins = [CGPoint](repeating: .zero, count: lines.count) + CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), &origins) + + for lineIndex in 0.. lineWidth ? lineWidth : runBounds.width) + + let path = UIBezierPath(roundedRect: runBounds, cornerRadius: cornerRadius) + mentionBackgroundColor.setFill() + path.fill() + } + } + } +} + +extension CTFrame { + var lines: [CTLine] { + return ((CTFrameGetLines(self) as [AnyObject] as? [CTLine]) ?? []) + } +} + +extension CTLine { + var ctruns: [CTRun] { + return ((CTLineGetGlyphRuns(self) as [AnyObject] as? [CTRun]) ?? []) + } +} diff --git a/Session/Shared/ScanQRCodeWrapperVC.swift b/Session/Shared/ScanQRCodeWrapperVC.swift index e3a8c07e2..2d8241569 100644 --- a/Session/Shared/ScanQRCodeWrapperVC.swift +++ b/Session/Shared/ScanQRCodeWrapperVC.swift @@ -56,7 +56,7 @@ final class ScanQRCodeWrapperVC : BaseVC { explanationLabel.autoPinWidthToSuperview(withMargin: 32) explanationLabel.autoPinHeightToSuperview(withMargin: 32) // Title - title = NSLocalizedString("Scan QR Code", comment: "") + title = "Scan QR Code" } override func viewDidAppear(_ animated: Bool) { diff --git a/Session/Utilities/MentionUtilities.swift b/Session/Utilities/MentionUtilities.swift index 104deaaea..f5876d5d6 100644 --- a/Session/Utilities/MentionUtilities.swift +++ b/Session/Utilities/MentionUtilities.swift @@ -6,10 +6,17 @@ import SessionUIKit import SessionMessagingKit public enum MentionUtilities { - public static func highlightMentions(in string: String, threadVariant: SessionThread.Variant) -> String { + public static func highlightMentions( + in string: String, + threadVariant: SessionThread.Variant, + currentUserPublicKey: String, + currentUserBlindedPublicKey: String? + ) -> String { return highlightMentions( in: string, threadVariant: threadVariant, + currentUserPublicKey: currentUserPublicKey, + currentUserBlindedPublicKey: currentUserBlindedPublicKey, isOutgoingMessage: false, attributes: [:] ).string // isOutgoingMessage and attributes are irrelevant @@ -18,6 +25,8 @@ public enum MentionUtilities { public static func highlightMentions( in string: String, threadVariant: SessionThread.Variant, + currentUserPublicKey: String?, + currentUserBlindedPublicKey: String?, isOutgoingMessage: Bool, attributes: [NSAttributedString.Key: Any] ) -> NSAttributedString { @@ -29,7 +38,13 @@ public enum MentionUtilities { var string = string var lastMatchEnd: Int = 0 - var mentions: [(range: NSRange, publicKey: String)] = [] + var mentions: [(range: NSRange, isCurrentUser: Bool)] = [] + let currentUserPublicKeys: Set = [ + currentUserPublicKey, + currentUserBlindedPublicKey + ] + .compactMap { $0 } + .asSet() while let match: NSTextCheckingResult = regex.firstMatch( in: string, @@ -39,28 +54,52 @@ public enum MentionUtilities { guard let range: Range = Range(match.range, in: string) else { break } let publicKey: String = String(string[range].dropFirst()) // Drop the @ + let isCurrentUser: Bool = currentUserPublicKeys.contains(publicKey) - guard let displayName: String = Profile.displayNameNoFallback(id: publicKey, threadVariant: threadVariant) else { - lastMatchEnd = (match.range.location + match.range.length) - continue - } + guard let targetString: String = { + guard !isCurrentUser else { return "MEDIA_GALLERY_SENDER_NAME_YOU".localized() } + guard let displayName: String = Profile.displayNameNoFallback(id: publicKey, threadVariant: threadVariant) else { + lastMatchEnd = (match.range.location + match.range.length) + return nil + } + + return displayName + }() + else { continue } - string = string.replacingCharacters(in: range, with: "@\(displayName)") - lastMatchEnd = (match.range.location + displayName.utf16.count) + string = string.replacingCharacters(in: range, with: "@\(targetString)") + lastMatchEnd = (match.range.location + targetString.utf16.count) mentions.append(( // + 1 to include the @ - range: NSRange(location: match.range.location, length: displayName.utf16.count + 1), - publicKey: publicKey + range: NSRange(location: match.range.location, length: targetString.utf16.count + 1), + isCurrentUser: isCurrentUser )) } + let sizeDiff: CGFloat = (Values.smallFontSize / Values.mediumFontSize) let result: NSMutableAttributedString = NSMutableAttributedString(string: string, attributes: attributes) mentions.forEach { mention in - // FIXME: This might break when swapping between themes - let color = isOutgoingMessage ? (isLightMode ? .white : .black) : Colors.accent - result.addAttribute(.foregroundColor, value: color, range: mention.range) result.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.smallFontSize), range: mention.range) + + if mention.isCurrentUser { + // Note: The designs don't match with the dynamic sizing so these values need to be calculated + // to maintain a "rounded rect" effect rather than a "pill" effect + result.addAttribute(.currentUserMentionBackgroundCornerRadius, value: (8 * sizeDiff), range: mention.range) + result.addAttribute(.currentUserMentionBackgroundPadding, value: (3 * sizeDiff), range: mention.range) + result.addAttribute(.currentUserMentionBackgroundColor, value: Colors.accent, range: mention.range) + result.addAttribute(.foregroundColor, value: UIColor.black, range: mention.range) + } + else { + let color: UIColor = { + switch (isLightMode, isOutgoingMessage) { + case (_, true): return .black + case (true, false): return .black + case (false, false): return Colors.accent + } + }() + result.addAttribute(.foregroundColor, value: color, range: mention.range) + } } return result diff --git a/SessionMessagingKit/Database/Models/Profile.swift b/SessionMessagingKit/Database/Models/Profile.swift index 32385683b..e57a95422 100644 --- a/SessionMessagingKit/Database/Models/Profile.swift +++ b/SessionMessagingKit/Database/Models/Profile.swift @@ -314,14 +314,11 @@ public extension Profile { /// A standardised mechanism for truncating a user id for a given thread static func truncated(id: String, threadVariant: SessionThread.Variant = .contact) -> String { - switch threadVariant { - case .openGroup: return truncated(id: id, truncating: .start) - default: return truncated(id: id, truncating: .middle) - } + return truncated(id: id, truncating: .middle) } /// A standardised mechanism for truncating a user id - static func truncated(id: String, truncating: Truncation = .start) -> String { + static func truncated(id: String, truncating: Truncation = .middle) -> String { guard id.count > 8 else { return id } switch truncating { @@ -355,7 +352,7 @@ public extension Profile { case .openGroup: // In open groups, where it's more likely that multiple users have the same name, // we display a bit of the Session ID after a user's display name for added context - return "\(name) (\(Profile.truncated(id: id, truncating: .start)))" + return "\(name) (\(Profile.truncated(id: id, truncating: .middle)))" } } } diff --git a/SessionMessagingKit/Database/Models/SessionThread.swift b/SessionMessagingKit/Database/Models/SessionThread.swift index 9f0967104..1b4e55169 100644 --- a/SessionMessagingKit/Database/Models/SessionThread.swift +++ b/SessionMessagingKit/Database/Models/SessionThread.swift @@ -2,6 +2,7 @@ import Foundation import GRDB +import Sodium import SessionUtilitiesKit public struct SessionThread: Codable, Identifiable, Equatable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible { @@ -314,6 +315,39 @@ public extension SessionThread { return profile.displayName() } } + + static func getUserHexEncodedBlindedKey( + threadId: String, + threadVariant: Variant + ) -> String? { + guard + threadVariant == .openGroup, + let blindingInfo: (edkeyPair: Box.KeyPair?, publicKey: String?) = Storage.shared.read({ db in + return ( + Identity.fetchUserEd25519KeyPair(db), + try OpenGroup + .filter(id: threadId) + .select(.publicKey) + .asRequest(of: String.self) + .fetchOne(db) + ) + }), + let userEdKeyPair: Box.KeyPair = blindingInfo.edkeyPair, + let publicKey: String = blindingInfo.publicKey + else { return nil } + + let sodium: Sodium = Sodium() + + let blindedKeyPair: Box.KeyPair? = sodium.blindedKeyPair( + serverPublicKey: publicKey, + edKeyPair: userEdKeyPair, + genericHash: sodium.getGenericHash() + ) + + return blindedKeyPair.map { keyPair -> String in + SessionId(.blinded, publicKey: keyPair.publicKey).hexString + } + } } // MARK: - Objective-C Support diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index a52576076..ff813332e 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -44,11 +44,11 @@ extension MessageSender { // Send a closed group update message to all members individually var promises: [Promise] = [] - try members.forEach { adminId in + try members.forEach { memberId in try GroupMember( groupId: groupPublicKey, - profileId: adminId, - role: .admin + profileId: memberId, + role: .standard ).insert(db) } diff --git a/SessionMessagingKit/Shared Models/MessageViewModel.swift b/SessionMessagingKit/Shared Models/MessageViewModel.swift index 9e7467c99..bad4cb96e 100644 --- a/SessionMessagingKit/Shared Models/MessageViewModel.swift +++ b/SessionMessagingKit/Shared Models/MessageViewModel.swift @@ -29,6 +29,7 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable, public static let quoteAttachmentKey: SQL = SQL(stringLiteral: CodingKeys.quoteAttachment.stringValue) public static let linkPreviewKey: SQL = SQL(stringLiteral: CodingKeys.linkPreview.stringValue) public static let linkPreviewAttachmentKey: SQL = SQL(stringLiteral: CodingKeys.linkPreviewAttachment.stringValue) + public static let currentUserPublicKeyKey: SQL = SQL(stringLiteral: CodingKeys.currentUserPublicKey.stringValue) public static let cellTypeKey: SQL = SQL(stringLiteral: CodingKeys.cellType.stringValue) public static let authorNameKey: SQL = SQL(stringLiteral: CodingKeys.authorName.stringValue) public static let shouldShowProfileKey: SQL = SQL(stringLiteral: CodingKeys.shouldShowProfile.stringValue) @@ -92,6 +93,8 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable, public let linkPreview: LinkPreview? public let linkPreviewAttachment: Attachment? + public let currentUserPublicKey: String + // Post-Query Processing Data /// This value includes the associated attachments @@ -132,6 +135,9 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable, /// This value indicates whether this is the last message in the thread public let isLast: Bool + + /// This is the users blinded key (will only be set for messages within open groups) + public let currentUserBlindedPublicKey: String? // MARK: - Mutation @@ -164,6 +170,7 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable, quoteAttachment: self.quoteAttachment, linkPreview: self.linkPreview, linkPreviewAttachment: self.linkPreviewAttachment, + currentUserPublicKey: self.currentUserPublicKey, attachments: attachments, cellType: self.cellType, authorName: self.authorName, @@ -175,14 +182,16 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable, previousVariant: self.previousVariant, positionInCluster: self.positionInCluster, isOnlyMessageInCluster: self.isOnlyMessageInCluster, - isLast: self.isLast + isLast: self.isLast, + currentUserBlindedPublicKey: self.currentUserBlindedPublicKey ) } public func withClusteringChanges( prevModel: MessageViewModel?, nextModel: MessageViewModel?, - isLast: Bool + isLast: Bool, + currentUserBlindedPublicKey: String? ) -> MessageViewModel { let cellType: CellType = { guard self.isTypingIndicator != true else { return .typingIndicator } @@ -338,6 +347,7 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable, quoteAttachment: self.quoteAttachment, linkPreview: self.linkPreview, linkPreviewAttachment: self.linkPreviewAttachment, + currentUserPublicKey: self.currentUserPublicKey, attachments: self.attachments, cellType: cellType, authorName: authorDisplayName, @@ -385,7 +395,8 @@ public struct MessageViewModel: FetchableRecordWithRowId, Decodable, Equatable, previousVariant: prevModel?.variant, positionInCluster: positionInCluster, isOnlyMessageInCluster: isOnlyMessageInCluster, - isLast: isLast + isLast: isLast, + currentUserBlindedPublicKey: currentUserBlindedPublicKey ) } } @@ -478,6 +489,7 @@ public extension MessageViewModel { self.quoteAttachment = nil self.linkPreview = nil self.linkPreviewAttachment = nil + self.currentUserPublicKey = "" // Post-Query Processing Data @@ -493,6 +505,7 @@ public extension MessageViewModel { self.positionInCluster = .middle self.isOnlyMessageInCluster = true self.isLast = true + self.currentUserBlindedPublicKey = nil } } @@ -557,7 +570,11 @@ public extension MessageViewModel { return SQL("\(interaction[.timestampMs].desc)") }() - static func baseQuery(orderSQL: SQL, groupSQL: SQL?) -> (([Int64]) -> AdaptedFetchRequest>) { + static func baseQuery( + userPublicKey: String, + orderSQL: SQL, + groupSQL: SQL? + ) -> (([Int64]) -> AdaptedFetchRequest>) { return { rowIds -> AdaptedFetchRequest> in let interaction: TypedTableAlias = TypedTableAlias() let thread: TypedTableAlias = TypedTableAlias() @@ -621,6 +638,8 @@ public extension MessageViewModel { \(ViewModel.linkPreviewKey).*, \(ViewModel.linkPreviewAttachmentKey).*, + \(SQL("\(userPublicKey)")) AS \(ViewModel.currentUserPublicKeyKey), + -- All of the below properties are set in post-query processing but to prevent the -- query from crashing when decoding we need to provide default values \(CellType.textOnlyMessage) AS \(ViewModel.cellTypeKey), diff --git a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift index fc099a5cb..bb78b6940 100644 --- a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift +++ b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift @@ -2,6 +2,7 @@ import Foundation import GRDB +import Sodium import DifferenceKit import SessionUtilitiesKit @@ -124,6 +125,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat private let threadContactNameInternal: String? private let authorNameInternal: String? public let currentUserPublicKey: String + public let currentUserBlindedPublicKey: String? // UI specific logic @@ -275,6 +277,67 @@ public extension SessionThreadViewModel { self.threadContactNameInternal = nil self.authorNameInternal = nil self.currentUserPublicKey = getUserHexEncodedPublicKey() + self.currentUserBlindedPublicKey = nil + } +} + +// MARK: - Mutation + +public extension SessionThreadViewModel { + func populatingCurrentUserBlindedKey( + currentUserBlindedPublicKeyForThisThread: String? = nil + ) -> SessionThreadViewModel { + return SessionThreadViewModel( + rowId: self.rowId, + threadId: self.threadId, + threadVariant: self.threadVariant, + threadCreationDateTimestamp: self.threadCreationDateTimestamp, + threadMemberNames: self.threadMemberNames, + threadIsNoteToSelf: self.threadIsNoteToSelf, + threadIsMessageRequest: self.threadIsMessageRequest, + threadRequiresApproval: self.threadRequiresApproval, + threadShouldBeVisible: self.threadShouldBeVisible, + threadIsPinned: self.threadIsPinned, + threadIsBlocked: self.threadIsBlocked, + threadMutedUntilTimestamp: self.threadMutedUntilTimestamp, + threadOnlyNotifyForMentions: self.threadOnlyNotifyForMentions, + threadMessageDraft: self.threadMessageDraft, + threadContactIsTyping: self.threadContactIsTyping, + threadUnreadCount: self.threadUnreadCount, + threadUnreadMentionCount: self.threadUnreadMentionCount, + contactProfile: self.contactProfile, + closedGroupProfileFront: self.closedGroupProfileFront, + closedGroupProfileBack: self.closedGroupProfileBack, + closedGroupProfileBackFallback: self.closedGroupProfileBackFallback, + closedGroupName: self.closedGroupName, + closedGroupUserCount: self.closedGroupUserCount, + currentUserIsClosedGroupMember: self.currentUserIsClosedGroupMember, + currentUserIsClosedGroupAdmin: self.currentUserIsClosedGroupAdmin, + openGroupName: self.openGroupName, + openGroupServer: self.openGroupServer, + openGroupRoomToken: self.openGroupRoomToken, + openGroupProfilePictureData: self.openGroupProfilePictureData, + openGroupUserCount: self.openGroupUserCount, + interactionId: self.interactionId, + interactionVariant: self.interactionVariant, + interactionTimestampMs: self.interactionTimestampMs, + interactionBody: self.interactionBody, + interactionState: self.interactionState, + interactionIsOpenGroupInvitation: self.interactionIsOpenGroupInvitation, + interactionAttachmentDescriptionInfo: self.interactionAttachmentDescriptionInfo, + interactionAttachmentCount: self.interactionAttachmentCount, + authorId: self.authorId, + threadContactNameInternal: self.threadContactNameInternal, + authorNameInternal: self.authorNameInternal, + currentUserPublicKey: self.currentUserPublicKey, + currentUserBlindedPublicKey: ( + currentUserBlindedPublicKeyForThisThread ?? + SessionThread.getUserHexEncodedBlindedKey( + threadId: self.threadId, + threadVariant: self.threadVariant + ) + ) + ) } } diff --git a/SessionSnodeKit/Models/SnodeAPIEndpoint.swift b/SessionSnodeKit/Models/SnodeAPIEndpoint.swift index 1028740fe..63ffd5334 100644 --- a/SessionSnodeKit/Models/SnodeAPIEndpoint.swift +++ b/SessionSnodeKit/Models/SnodeAPIEndpoint.swift @@ -11,4 +11,6 @@ public enum SnodeAPIEndpoint: String { case getInfo = "info" case clearAllData = "delete_all" case expire = "expire" + case batch = "batch" + case sequence = "sequence" } diff --git a/SessionUIKit/Components/SearchBar.swift b/SessionUIKit/Components/SearchBar.swift index ecefdca22..830f0973f 100644 --- a/SessionUIKit/Components/SearchBar.swift +++ b/SessionUIKit/Components/SearchBar.swift @@ -26,7 +26,7 @@ public extension UISearchBar { let searchTextField: UITextField = self.searchTextField searchTextField.backgroundColor = Colors.searchBarBackground // The search bar background color searchTextField.textColor = Colors.text - searchTextField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""), attributes: [ .foregroundColor : Colors.searchBarPlaceholder ]) + searchTextField.attributedPlaceholder = NSAttributedString(string: "Search", attributes: [ .foregroundColor : Colors.searchBarPlaceholder ]) setPositionAdjustment(UIOffset(horizontal: 4, vertical: 0), for: UISearchBar.Icon.search) searchTextPositionAdjustment = UIOffset(horizontal: 2, vertical: 0) setPositionAdjustment(UIOffset(horizontal: -4, vertical: 0), for: UISearchBar.Icon.clear) diff --git a/SessionUtilitiesKit/Crypto/Mnemonic.swift b/SessionUtilitiesKit/Crypto/Mnemonic.swift index 1786f5e72..b420a89f7 100644 --- a/SessionUtilitiesKit/Crypto/Mnemonic.swift +++ b/SessionUtilitiesKit/Crypto/Mnemonic.swift @@ -48,11 +48,11 @@ public enum Mnemonic { public var errorDescription: String? { switch self { - case .generic: return NSLocalizedString("Something went wrong. Please check your recovery phrase and try again.", comment: "") - case .inputTooShort: return NSLocalizedString("Looks like you didn't enter enough words. Please check your recovery phrase and try again.", comment: "") - case .missingLastWord: return NSLocalizedString("You seem to be missing the last word of your recovery phrase. Please check what you entered and try again.", comment: "") - case .invalidWord: return NSLocalizedString("There appears to be an invalid word in your recovery phrase. Please check what you entered and try again.", comment: "") - case .verificationFailed: return NSLocalizedString("Your recovery phrase couldn't be verified. Please check what you entered and try again.", comment: "") + case .generic: return "RECOVERY_PHASE_ERROR_GENERIC".localized() + case .inputTooShort: return "RECOVERY_PHASE_ERROR_LENGTH".localized() + case .missingLastWord: return "RECOVERY_PHASE_ERROR_LAST_WORD".localized() + case .invalidWord: return "RECOVERY_PHASE_ERROR_INVALID_WORD".localized() + case .verificationFailed: return "RECOVERY_PHASE_ERROR_FAILED".localized() } } } diff --git a/SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentTextToolbar.swift b/SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentTextToolbar.swift index f5dcf5963..01bb11578 100644 --- a/SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentTextToolbar.swift +++ b/SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentTextToolbar.swift @@ -164,7 +164,7 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate { private lazy var placeholderTextView: UITextView = { let placeholderTextView = buildTextView() - placeholderTextView.text = NSLocalizedString("Message", comment: "") + placeholderTextView.text = "Message" placeholderTextView.isEditable = false return placeholderTextView diff --git a/SignalUtilitiesKit/Screen Lock/OWSScreenLock.swift b/SignalUtilitiesKit/Screen Lock/OWSScreenLock.swift index dfa7a7279..306bac424 100644 --- a/SignalUtilitiesKit/Screen Lock/OWSScreenLock.swift +++ b/SignalUtilitiesKit/Screen Lock/OWSScreenLock.swift @@ -118,8 +118,7 @@ import SessionMessagingKit completion completionParam: @escaping ((OWSScreenLockOutcome) -> Void)) { AssertIsOnMainThread() - let defaultErrorDescription = NSLocalizedString("SCREEN_LOCK_ENABLE_UNKNOWN_ERROR", - comment: "Indicates that an unknown error occurred while using Touch ID/Face ID/Phone Passcode.") + let defaultErrorDescription = "SCREEN_LOCK_ENABLE_UNKNOWN_ERROR".localized() // Ensure completion is always called on the main thread. let completion = { (outcome: OWSScreenLockOutcome) in @@ -140,7 +139,7 @@ import SessionMessagingKit switch outcome { case .success: owsFailDebug("local authentication unexpected success") - completion(.failure(error:defaultErrorDescription)) + completion(.failure(error: defaultErrorDescription)) case .cancel, .failure, .unexpectedFailure: completion(outcome) } @@ -177,16 +176,13 @@ import SessionMessagingKit switch laError.code { case .biometryNotAvailable: Logger.error("local authentication error: biometryNotAvailable.") - return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE", - comment: "Indicates that Touch ID/Face ID/Phone Passcode are not available on this device.")) + return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE".localized()) case .biometryNotEnrolled: Logger.error("local authentication error: biometryNotEnrolled.") - return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED", - comment: "Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device.")) + return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED".localized()) case .biometryLockout: Logger.error("local authentication error: biometryLockout.") - return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT", - comment: "Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures.")) + return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT".localized()) default: // Fall through to second switch break @@ -195,27 +191,22 @@ import SessionMessagingKit switch laError.code { case .authenticationFailed: Logger.error("local authentication error: authenticationFailed.") - return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED", - comment: "Indicates that Touch ID/Face ID/Phone Passcode authentication failed.")) + return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_FAILED".localized()) case .userCancel, .userFallback, .systemCancel, .appCancel: Logger.info("local authentication cancelled.") return .cancel case .passcodeNotSet: Logger.error("local authentication error: passcodeNotSet.") - return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET", - comment: "Indicates that Touch ID/Face ID/Phone Passcode passcode is not set.")) + return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_PASSCODE_NOT_SET".localized()) case .touchIDNotAvailable: Logger.error("local authentication error: touchIDNotAvailable.") - return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE", - comment: "Indicates that Touch ID/Face ID/Phone Passcode are not available on this device.")) + return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_AVAILABLE".localized()) case .touchIDNotEnrolled: Logger.error("local authentication error: touchIDNotEnrolled.") - return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED", - comment: "Indicates that Touch ID/Face ID/Phone Passcode is not configured on this device.")) + return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_NOT_ENROLLED".localized()) case .touchIDLockout: Logger.error("local authentication error: touchIDLockout.") - return .failure(error: NSLocalizedString("SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT", - comment: "Indicates that Touch ID/Face ID/Phone Passcode is 'locked out' on this device due to authentication failures.")) + return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT".localized()) case .invalidContext: owsFailDebug("context not valid.") return .unexpectedFailure(error:defaultErrorDescription) diff --git a/SignalUtilitiesKit/Utilities/CommonStrings.swift b/SignalUtilitiesKit/Utilities/CommonStrings.swift index 0bcac0c4f..b3c7f6c88 100644 --- a/SignalUtilitiesKit/Utilities/CommonStrings.swift +++ b/SignalUtilitiesKit/Utilities/CommonStrings.swift @@ -16,7 +16,7 @@ import Foundation @objc static public let doneButton = NSLocalizedString("BUTTON_DONE", comment: "Label for generic done button.") @objc - static public let retryButton = NSLocalizedString("RETRY_BUTTON_TEXT", comment: "Generic text for button that retries whatever the last action was.") + static public let retryButton = "RETRY_BUTTON_TEXT".localized() @objc static public let openSettingsButton = NSLocalizedString("OPEN_SETTINGS_BUTTON", comment: "Button text which opens the settings app") @objc @@ -31,20 +31,11 @@ import Foundation static public let markAsReadNotificationAction = NSLocalizedString("PUSH_MANAGER_MARKREAD", comment: "Notification action button title") @objc - static public let sendButton = NSLocalizedString("SEND_BUTTON_TITLE", comment: "Label for the button to send a message") + static public let sendButton = "SEND_BUTTON_TITLE".localized() } @objc public class NotificationStrings: NSObject { - @objc - static public let incomingCallBody = NSLocalizedString("CALL_INCOMING_NOTIFICATION_BODY", comment: "notification body") - - @objc - static public let missedCallBody = NSLocalizedString("CALL_MISSED_NOTIFICATION_BODY", comment: "notification body") - - @objc - static public let missedCallBecauseOfIdentityChangeBody = NSLocalizedString("CALL_MISSED_BECAUSE_OF_IDENTITY_CHANGE_NOTIFICATION_BODY", comment: "notification body") - @objc static public let incomingMessageBody = NSLocalizedString("APN_Message", comment: "notification body") @@ -55,41 +46,16 @@ public class NotificationStrings: NSObject { static public let incomingGroupMessageTitleFormat = NSLocalizedString("NEW_GROUP_MESSAGE_NOTIFICATION_TITLE", comment: "notification title. Embeds {{author name}} and {{group name}}") @objc - static public let failedToSendBody = NSLocalizedString("SEND_FAILED_NOTIFICATION_BODY", comment: "notification body") + static public let failedToSendBody = "SEND_FAILED_NOTIFICATION_BODY".localized() } @objc public class CallStrings: NSObject { - @objc - static public let callStatusFormat = NSLocalizedString("CALL_STATUS_FORMAT", comment: "embeds {{Call Status}} in call screen label. For ongoing calls, {{Call Status}} is a seconds timer like 01:23, otherwise {{Call Status}} is a short text like 'Ringing', 'Busy', or 'Failed Call'") - - @objc - static public let confirmAndCallButtonTitle = NSLocalizedString("SAFETY_NUMBER_CHANGED_CONFIRM_CALL_ACTION", comment: "alert button text to confirm placing an outgoing call after the recipients Safety Number has changed.") - - @objc - static public let callBackAlertTitle = NSLocalizedString("CALL_USER_ALERT_TITLE", comment: "Title for alert offering to call a user.") - @objc - static public let callBackAlertMessageFormat = NSLocalizedString("CALL_USER_ALERT_MESSAGE_FORMAT", comment: "Message format for alert offering to call a user. Embeds {{the user's display name or phone number}}.") - @objc - static public let callBackAlertCallButton = NSLocalizedString("CALL_USER_ALERT_CALL_BUTTON", comment: "Label for call button for alert offering to call a user.") - // MARK: Notification actions @objc - static public let callBackButtonTitle = NSLocalizedString("CALLBACK_BUTTON_TITLE", comment: "notification action") - @objc - static public let showThreadButtonTitle = NSLocalizedString("SHOW_THREAD_BUTTON_TITLE", comment: "notification action") - @objc - static public let answerCallButtonTitle = NSLocalizedString("ANSWER_CALL_BUTTON_TITLE", comment: "notification action") - @objc - static public let declineCallButtonTitle = NSLocalizedString("REJECT_CALL_BUTTON_TITLE", comment: "notification action") + static public let showThreadButtonTitle = "SHOW_THREAD_BUTTON_TITLE".localized() } @objc public class MediaStrings: NSObject { @objc static public let allMedia = NSLocalizedString("MEDIA_DETAIL_VIEW_ALL_MEDIA_BUTTON", comment: "nav bar button item") } - -@objc public class SafetyNumberStrings: NSObject { - @objc - static public let confirmSendButton = NSLocalizedString("SAFETY_NUMBER_CHANGED_CONFIRM_SEND_ACTION", - comment: "button title to confirm sending to a recipient whose safety number recently changed") -} diff --git a/SignalUtilitiesKit/Utilities/OWSAlerts.swift b/SignalUtilitiesKit/Utilities/OWSAlerts.swift index caa9d7e6d..f8cc99beb 100644 --- a/SignalUtilitiesKit/Utilities/OWSAlerts.swift +++ b/SignalUtilitiesKit/Utilities/OWSAlerts.swift @@ -6,25 +6,6 @@ import Foundation import SessionUtilitiesKit @objc public class OWSAlerts: NSObject { - - /// Cleanup and present alert for no permissions - @objc - public class func showNoMicrophonePermissionAlert() { - let alertTitle = NSLocalizedString("CALL_AUDIO_PERMISSION_TITLE", comment: "Alert title when calling and permissions for microphone are missing") - let alertMessage = NSLocalizedString("CALL_AUDIO_PERMISSION_MESSAGE", comment: "Alert message when calling and permissions for microphone are missing") - let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert) - - let dismissAction = UIAlertAction(title: CommonStrings.dismissButton, style: .cancel) - dismissAction.accessibilityIdentifier = "OWSAlerts.\("dismiss")" - alert.addAction(dismissAction) - - if let settingsAction = CurrentAppContext().openSystemSettingsAction { - settingsAction.accessibilityIdentifier = "OWSAlerts.\("settings")" - alert.addAction(settingsAction) - } - CurrentAppContext().frontmostViewController()?.presentAlert(alert) - } - @objc public class func showAlert(_ alert: UIAlertController) { guard let frontmostViewController = CurrentAppContext().frontmostViewController() else {