Browse Source

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
pull/612/head
Morgan Pretty 2 months ago
parent
commit
3c07a2d044
  1. 251
      Scripts/LintLocalizableStrings.swift
  2. 36
      Session.xcodeproj/project.pbxproj
  3. 3
      Session/Calls/Call Management/SessionCallManager.swift
  4. 16
      Session/Conversations/ConversationViewModel.swift
  5. 2
      Session/Conversations/Input View/InputView.swift
  6. 24
      Session/Conversations/Message Cells/Content Views/QuoteView.swift
  7. 4
      Session/Conversations/Message Cells/VisibleMessageCell.swift
  8. 28
      Session/Conversations/Views & Modals/BodyTextView.swift
  9. 12
      Session/Home/HomeViewModel.swift
  10. 13
      Session/Home/Message Requests/MessageRequestsViewModel.swift
  11. 2
      Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift
  12. 29
      Session/Meta/Translations/de.lproj/Localizable.strings
  13. 30
      Session/Meta/Translations/en.lproj/Localizable.strings
  14. 29
      Session/Meta/Translations/es.lproj/Localizable.strings
  15. 29
      Session/Meta/Translations/fa.lproj/Localizable.strings
  16. 29
      Session/Meta/Translations/fi.lproj/Localizable.strings
  17. 29
      Session/Meta/Translations/fr.lproj/Localizable.strings
  18. 29
      Session/Meta/Translations/hi.lproj/Localizable.strings
  19. 29
      Session/Meta/Translations/hr.lproj/Localizable.strings
  20. 29
      Session/Meta/Translations/id-ID.lproj/Localizable.strings
  21. 29
      Session/Meta/Translations/it.lproj/Localizable.strings
  22. 29
      Session/Meta/Translations/ja.lproj/Localizable.strings
  23. 29
      Session/Meta/Translations/nl.lproj/Localizable.strings
  24. 29
      Session/Meta/Translations/pl.lproj/Localizable.strings
  25. 29
      Session/Meta/Translations/pt_BR.lproj/Localizable.strings
  26. 29
      Session/Meta/Translations/ru.lproj/Localizable.strings
  27. 29
      Session/Meta/Translations/si.lproj/Localizable.strings
  28. 29
      Session/Meta/Translations/sk.lproj/Localizable.strings
  29. 29
      Session/Meta/Translations/sv.lproj/Localizable.strings
  30. 29
      Session/Meta/Translations/th.lproj/Localizable.strings
  31. 29
      Session/Meta/Translations/vi-VN.lproj/Localizable.strings
  32. 29
      Session/Meta/Translations/zh-Hant.lproj/Localizable.strings
  33. 29
      Session/Meta/Translations/zh_CN.lproj/Localizable.strings
  34. 10
      Session/Notifications/AppNotifications.swift
  35. 6
      Session/Onboarding/LinkDeviceVC.swift
  36. 4
      Session/Settings/QRCodeVC.swift
  37. 16
      Session/Shared/FullConversationCell.swift
  38. 161
      Session/Shared/HighlightMentionBackgroundView.swift
  39. 2
      Session/Shared/ScanQRCodeWrapperVC.swift
  40. 65
      Session/Utilities/MentionUtilities.swift
  41. 9
      SessionMessagingKit/Database/Models/Profile.swift
  42. 34
      SessionMessagingKit/Database/Models/SessionThread.swift
  43. 6
      SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift
  44. 27
      SessionMessagingKit/Shared Models/MessageViewModel.swift
  45. 63
      SessionMessagingKit/Shared Models/SessionThreadViewModel.swift
  46. 2
      SessionSnodeKit/Models/SnodeAPIEndpoint.swift
  47. 2
      SessionUIKit/Components/SearchBar.swift
  48. 10
      SessionUtilitiesKit/Crypto/Mnemonic.swift
  49. 2
      SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentTextToolbar.swift
  50. 29
      SignalUtilitiesKit/Screen Lock/OWSScreenLock.swift
  51. 42
      SignalUtilitiesKit/Utilities/CommonStrings.swift
  52. 19
      SignalUtilitiesKit/Utilities/OWSAlerts.swift

251
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<String> = 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<String>
}
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 ------------")

36
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 = "<group>"; };
FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryNavigationController.swift; sourceTree = "<group>"; };
FDE72117286C156E0093DF33 /* ChatSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatSettingsViewController.swift; sourceTree = "<group>"; };
FDE7214F287E50D50093DF33 /* ProtoWrappers.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = ProtoWrappers.py; sourceTree = "<group>"; };
FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LintLocalizableStrings.swift; sourceTree = "<group>"; };
FDE72153287FE4470093DF33 /* HighlightMentionBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightMentionBackgroundView.swift; sourceTree = "<group>"; };
FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobRunnerError.swift; sourceTree = "<group>"; };
FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlMessageProcessRecord.swift; sourceTree = "<group>"; };
FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+ReusableView.swift"; sourceTree = "<group>"; };
@ -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 = "<group>";
};
FDE7214E287E50D50093DF33 /* Scripts */ = {
isa = PBXGroup;
children = (
FDE7214F287E50D50093DF33 /* ProtoWrappers.py */,
FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */,
);
path = Scripts;
sourceTree = "<group>";
};
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 */,

3
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

16
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<Interaction, MessageViewModel> {
private func setupPagedObserver(for threadId: String, userPublicKey: String) -> PagedDatabaseObserver<Interaction, MessageViewModel> {
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

2
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,

24
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)

4
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,

28
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 {

12
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 ?

13
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 ?

2
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

29
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.";

30
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.";

29
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.";

29
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.";

29
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.";

29
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.";

29
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.";

29
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.";

29
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.";

29
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.";

29
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.";

29
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_AUTHENTICATI