From fd1c368ca03564098d4a7ae11daddb3145f251d4 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO <> Date: Tue, 19 Mar 2024 11:27:18 +1100 Subject: [PATCH] WIP: check for any untouched strings --- Scripts/LintLocalizableStrings.swift | 24 +++++++++++++++---- .../Calls/Call Management/SessionCall.swift | 2 +- .../Call Management/SessionCallManager.swift | 2 +- Session/Calls/CallVC.swift | 2 +- Session/Calls/VideoPreviewVC.swift | 2 +- .../ConversationVC+Interaction.swift | 23 +++++++++--------- Session/Conversations/ConversationVC.swift | 4 ++-- .../Conversations/ConversationViewModel.swift | 2 +- .../EmojiPickerCollectionView.swift | 4 ++-- .../VoiceMessageRecordingView.swift | 2 +- .../DisappearingMessageTimerView.swift | 2 +- .../Content Views/MediaPlaceholderView.swift | 12 ++++++---- .../OpenGroupInvitationView.swift | 4 ++-- .../Content Views/QuoteView.swift | 2 +- .../Content Views/ReactionView.swift | 2 +- .../Content Views/TypingIndicatorView.swift | 4 ++-- .../Content Views/VoiceMessageView.swift | 4 ++-- .../Message Cells/VisibleMessageCell.swift | 6 ++--- .../Views & Modals/ReactionListSheet.swift | 2 +- Session/Emoji/Emoji+Available.swift | 2 ++ .../GlobalSearchViewController.swift | 2 +- Session/Home/HomeVC.swift | 4 ++-- .../Views/MessageRequestsCell.swift | 2 +- .../NewConversationViewModel.swift | 4 ++-- .../GIFs/GifPickerViewController.swift | 2 +- .../GIFs/GiphyDownloader.swift | 2 +- .../ImagePickerController.swift | 2 +- .../MediaTileViewController.swift | 4 ++-- .../PhotoCaptureViewController.swift | 8 +++---- .../PhotoLibrary.swift | 2 +- Session/Meta/AppDelegate.swift | 14 +++++------ Session/Meta/MainAppContext.swift | 4 ++-- Session/Meta/SessionApp.swift | 8 +++---- .../PushRegistrationManager.swift | 8 +++---- Session/Onboarding/RegisterVC.swift | 8 ++----- Session/Onboarding/RestoreVC.swift | 13 ++-------- Session/Onboarding/SeedVC.swift | 12 +++++----- Session/Path/PathVC.swift | 4 ++-- Session/Settings/HelpViewModel.swift | 22 ++++++++--------- .../Settings/Views/VersionFooterView.swift | 2 +- Session/Shared/FullConversationCell.swift | 18 +++++++------- Session/Shared/ScanQRCodeWrapperVC.swift | 2 +- Session/Utilities/Date+Utilities.swift | 2 ++ Session/Utilities/IP2Country.swift | 8 +++---- Session/Utilities/MentionUtilities.swift | 4 ++-- Session/Utilities/QRCode.swift | 8 +++---- .../NSENotificationPresenter.swift | 2 +- .../NotificationError.swift | 6 ++--- .../NotificationServiceExtension.swift | 18 +++++++------- .../ShareNavController.swift | 6 ++--- SessionShareExtension/ThreadPickerVC.swift | 2 +- 51 files changed, 161 insertions(+), 149 deletions(-) diff --git a/Scripts/LintLocalizableStrings.swift b/Scripts/LintLocalizableStrings.swift index 9860c275f..a4d904a60 100755 --- a/Scripts/LintLocalizableStrings.swift +++ b/Scripts/LintLocalizableStrings.swift @@ -27,7 +27,7 @@ extension ProjectState { "_SharedTestUtilities/", // Exclude shared test directory "external/" // External dependencies ] - static let excludedPhrases: Set = [ "", " ", ",", ", ", "null" ] + static let excludedPhrases: Set = [ "", " ", " ", ",", ", ", "null", "\"", "@[0-9a-fA-F]{66}", "^[0-9A-Fa-f]+$" ] static let excludedUnlocalisedStringLineMatching: Set = [ .contains(ProjectState.lintSuppression, caseSensitive: false), .prefix("#import", caseSensitive: false), @@ -46,9 +46,9 @@ extension ProjectState { .contains("[UIImage imageNamed:", caseSensitive: false), .contains("UIFont(name:", caseSensitive: false), .contains(".dateFormat =", caseSensitive: false), - .contains(".accessibilityLabel =", caseSensitive: false), - .contains(".accessibilityValue =", caseSensitive: false), - .contains(".accessibilityIdentifier =", caseSensitive: false), + .contains("accessibilityLabel =", caseSensitive: false), + .contains("accessibilityValue =", caseSensitive: false), + .contains("accessibilityIdentifier =", caseSensitive: false), .contains("accessibilityIdentifier:", caseSensitive: false), .contains("accessibilityLabel:", caseSensitive: false), .contains("Accessibility(identifier:", caseSensitive: false), @@ -73,6 +73,17 @@ extension ProjectState { .previousLine(numEarlier: 2, .contains("Accessibility(", caseSensitive: false)) ), .contains("SQL(", caseSensitive: false), + .contains(" == ", caseSensitive: false), + .contains("forResource:", caseSensitive: false), + .contains("imageName:", caseSensitive: false), + .contains(".userInfo[", caseSensitive: false), + .contains("payload[", caseSensitive: false), + .contains(".infoDictionary?[", caseSensitive: false), + .contains("accessibilityId:", caseSensitive: false), + .contains("key:", caseSensitive: false), + .contains("separator:", caseSensitive: false), + .nextLine(.contains(".put(key:", caseSensitive: false)), + .nextLine(.contains(".localized()", caseSensitive: false)), .regex(".*static var databaseTableName: String"), .regex("Logger\\..*\\("), .regex("OWSLogger\\..*\\("), @@ -545,6 +556,7 @@ indirect enum MatchType: Hashable { case containsAnd(String, caseSensitive: Bool, MatchType) case regex(String) case previousLine(numEarlier: Int, MatchType) + case nextLine(MatchType) func matches(_ value: String, _ index: Int, _ lines: [String]) -> Bool { switch self { @@ -578,6 +590,10 @@ indirect enum MatchType: Hashable { let targetIndex: Int = (index - numEarlier) return type.matches(lines[targetIndex], targetIndex, lines) + + case .nextLine(let type): + guard index + 1 < lines.count else { return false } + return type.matches(lines[index + 1], index + 1, lines) } } } diff --git a/Session/Calls/Call Management/SessionCall.swift b/Session/Calls/Call Management/SessionCall.swift index e8e8dd255..173430c22 100644 --- a/Session/Calls/Call Management/SessionCall.swift +++ b/Session/Calls/Call Management/SessionCall.swift @@ -182,7 +182,7 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate { func reportIncomingCallIfNeeded(completion: @escaping (Error?) -> Void) { guard case .answer = mode else { - SessionCallManager.reportFakeCall(info: "Call not in answer mode") + SessionCallManager.reportFakeCall(info: "Call not in answer mode") // stringlint:disable return } diff --git a/Session/Calls/Call Management/SessionCallManager.swift b/Session/Calls/Call Management/SessionCallManager.swift index c5dfd5c4a..ad28d2718 100644 --- a/Session/Calls/Call Management/SessionCallManager.swift +++ b/Session/Calls/Call Management/SessionCallManager.swift @@ -43,7 +43,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol { } static func buildProviderConfiguration(useSystemCallLog: Bool) -> CXProviderConfiguration { - let providerConfiguration = CXProviderConfiguration(localizedName: "Session") + let providerConfiguration = CXProviderConfiguration(localizedName: "Session") // stringlint:disable providerConfiguration.supportsVideo = true providerConfiguration.maximumCallGroups = 1 providerConfiguration.maximumCallsPerCallGroup = 1 diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index 61f6d54b9..1a0b5dae9 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -629,7 +629,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate { } @objc private func updateDuration() { - callDurationLabel.text = String(format: "%.2d:%.2d", duration/60, duration%60) + callDurationLabel.text = String(format: "%.2d:%.2d", duration/60, duration%60) // stringlint:disable duration += 1 } diff --git a/Session/Calls/VideoPreviewVC.swift b/Session/Calls/VideoPreviewVC.swift index 798451bac..449b36fbc 100644 --- a/Session/Calls/VideoPreviewVC.swift +++ b/Session/Calls/VideoPreviewVC.swift @@ -74,7 +74,7 @@ class VideoPreviewVC: UIViewController, CameraManagerDelegate { private lazy var titleLabel: UILabel = { let result = UILabel() result.font = .boldSystemFont(ofSize: Values.veryLargeFontSize) - result.text = "Preview" + result.text = "preview".localized() result.themeTextColor = .textPrimary result.textAlignment = .center diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index df5649a39..695a2c23e 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -730,7 +730,7 @@ extension ConversationVC: let newText: String = snInputView.text.replacingCharacters( in: currentMentionStartIndex..., - with: "@\(mentionInfo.profile.displayName(for: self.viewModel.threadData.threadVariant)) " + with: "@\(mentionInfo.profile.displayName(for: self.viewModel.threadData.threadVariant)) " // stringlint:disable ) snInputView.text = newText @@ -789,8 +789,8 @@ extension ConversationVC: func replaceMentions(in text: String) -> String { var result = text for mention in mentions { - guard let range = result.range(of: "@\(mention.profile.displayName(for: mention.threadVariant))") else { continue } - result = result.replacingCharacters(in: range, with: "@\(mention.profile.id)") + guard let range = result.range(of: "@\(mention.profile.displayName(for: mention.threadVariant))") else { continue } // stringlint:disable + result = result.replacingCharacters(in: range, with: "@\(mention.profile.id)") // stringlint:disable } return result @@ -1702,14 +1702,14 @@ extension ConversationVC: )) // HACK: Extracting this info from the error string is pretty dodgy - let prefix: String = "HTTP request failed at destination (Service node " + let prefix: String = "HTTP request failed at destination (Service node " // stringlint:disable if let mostRecentFailureText: String = cellViewModel.mostRecentFailureText, mostRecentFailureText.hasPrefix(prefix) { let rest = mostRecentFailureText.substring(from: prefix.count) - if let index = rest.firstIndex(of: ")") { + if let index = rest.firstIndex(of: ")") { // stringlint:disable let snodeAddress = String(rest[rest.startIndex.. String in - guard part.hasPrefix("\"") && part.hasSuffix("\"") else { return part } + guard part.hasPrefix("\"") && part.hasSuffix("\"") else { return part } // stringlint:disable let partRange = (part.index(after: part.startIndex).. 0 ? displayName.substring(to: 1) : "") let section: String = initialCharacter.capitalized.isSingleAlphabet ? - initialCharacter.capitalized : - "#" + initialCharacter.capitalized : + "#" // stringlint:disable if groupedContacts[section] == nil { groupedContacts[section] = SectionData( diff --git a/Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift b/Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift index 0ebf08c77..76ff3689f 100644 --- a/Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift +++ b/Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift @@ -37,7 +37,7 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect var hasSelectedCell: Bool = false var imageInfos = [GiphyImageInfo]() - private let kCellReuseIdentifier = "kCellReuseIdentifier" + private let kCellReuseIdentifier = "kCellReuseIdentifier" // stringlint:disable var progressiveSearchTimer: Timer? diff --git a/Session/Media Viewing & Editing/GIFs/GiphyDownloader.swift b/Session/Media Viewing & Editing/GIFs/GiphyDownloader.swift index 3afd8d56a..7cb77c7b6 100644 --- a/Session/Media Viewing & Editing/GIFs/GiphyDownloader.swift +++ b/Session/Media Viewing & Editing/GIFs/GiphyDownloader.swift @@ -8,5 +8,5 @@ public class GiphyDownloader: ProxiedContentDownloader { // MARK: - Properties - public static let giphyDownloader = GiphyDownloader(downloadFolderName: "GIFs") + public static let giphyDownloader = GiphyDownloader(downloadFolderName: "GIFs") // stringlint:disable } diff --git a/Session/Media Viewing & Editing/ImagePickerController.swift b/Session/Media Viewing & Editing/ImagePickerController.swift index 7c78039e0..96fdce4fa 100644 --- a/Session/Media Viewing & Editing/ImagePickerController.swift +++ b/Session/Media Viewing & Editing/ImagePickerController.swift @@ -72,7 +72,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat // quickly toggle between the Capture and the Picker VC's, we use the same custom "X" // icon here rather than the system "stop" icon so that the spacing matches exactly. // Otherwise there's a noticable shift in the icon placement. - let cancelImage = UIImage(imageLiteralResourceName: "X") + let cancelImage = #imageLiteral(resourceName: "X") let cancelButton = UIBarButtonItem(image: cancelImage, style: .plain, target: self, action: #selector(didPressCancel)) cancelButton.themeTintColor = .textPrimary diff --git a/Session/Media Viewing & Editing/MediaTileViewController.swift b/Session/Media Viewing & Editing/MediaTileViewController.swift index 994f8d9f4..acae7c339 100644 --- a/Session/Media Viewing & Editing/MediaTileViewController.swift +++ b/Session/Media Viewing & Editing/MediaTileViewController.swift @@ -759,7 +759,7 @@ private class MediaTileViewLayout: UICollectionViewFlowLayout { private class MediaGallerySectionHeader: UICollectionReusableView { - static let reuseIdentifier = "MediaGallerySectionHeader" + static let reuseIdentifier = "MediaGallerySectionHeader" // stringlint:disable // HACK: scrollbar incorrectly appears *behind* section headers // in collection view on iOS11 =( @@ -817,7 +817,7 @@ private class MediaGallerySectionHeader: UICollectionReusableView { private class MediaGalleryStaticHeader: UICollectionViewCell { - static let reuseIdentifier = "MediaGalleryStaticHeader" + static let reuseIdentifier = "MediaGalleryStaticHeader" // stringlint:disable let label = UILabel() diff --git a/Session/Media Viewing & Editing/PhotoCaptureViewController.swift b/Session/Media Viewing & Editing/PhotoCaptureViewController.swift index 7e999a893..a5e654617 100644 --- a/Session/Media Viewing & Editing/PhotoCaptureViewController.swift +++ b/Session/Media Viewing & Editing/PhotoCaptureViewController.swift @@ -341,11 +341,11 @@ class PhotoCaptureViewController: OWSViewController { let imageName: String switch photoCapture.flashMode { case .auto: - imageName = "ic_flash_mode_auto" + imageName = "ic_flash_mode_auto" // stringlint:disable case .on: - imageName = "ic_flash_mode_on" + imageName = "ic_flash_mode_on" // stringlint:disable case .off: - imageName = "ic_flash_mode_off" + imageName = "ic_flash_mode_off" // stringlint:disable default: preconditionFailure() } @@ -646,7 +646,7 @@ class RecordingTimerView: UIView { private lazy var timeFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "mm:ss" - formatter.timeZone = TimeZone(identifier: "UTC")! + formatter.timeZone = TimeZone(identifier: "UTC")! // stringlint:disable return formatter }() diff --git a/Session/Media Viewing & Editing/PhotoLibrary.swift b/Session/Media Viewing & Editing/PhotoLibrary.swift index 7c9dd6b4b..f7211ecbe 100644 --- a/Session/Media Viewing & Editing/PhotoLibrary.swift +++ b/Session/Media Viewing & Editing/PhotoLibrary.swift @@ -186,7 +186,7 @@ class PhotoCollectionContents { exportSession.outputFileType = AVFileType.mp4 exportSession.metadataItemFilter = AVMetadataItemFilter.forSharing() - let exportPath = OWSFileSystem.temporaryFilePath(withFileExtension: "mp4") + let exportPath = OWSFileSystem.temporaryFilePath(withFileExtension: "mp4") // stringlint:disable let exportURL = URL(fileURLWithPath: exportPath) exportSession.outputURL = exportURL diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index 0da572d4e..702787aaa 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -862,9 +862,9 @@ private enum LifecycleMethod: Equatable { var timingName: String { switch self { - case .finishLaunching: return "Launch" - case .enterForeground: return "EnterForeground" - case .didBecomeActive: return "BecomeActive" + case .finishLaunching: return "Launch" // stringlint:disable + case .enterForeground: return "EnterForeground" // stringlint:disable + case .didBecomeActive: return "BecomeActive" // stringlint:disable } } @@ -888,11 +888,11 @@ private enum StartupError: Error { var name: String { switch self { case .databaseError(StorageError.startupFailed), .databaseError(DatabaseError.SQLITE_LOCKED): - return "Database startup failed" + return "Database startup failed" // stringlint:disable - case .failedToRestore: return "Failed to restore" - case .databaseError: return "Database error" - case .startupTimeout: return "Startup timeout" + case .failedToRestore: return "Failed to restore" // stringlint:disable + case .databaseError: return "Database error" // stringlint:disable + case .startupTimeout: return "Startup timeout" // stringlint:disable } } diff --git a/Session/Meta/MainAppContext.swift b/Session/Meta/MainAppContext.swift index 9869c4562..55855589b 100644 --- a/Session/Meta/MainAppContext.swift +++ b/Session/Meta/MainAppContext.swift @@ -165,7 +165,7 @@ final class MainAppContext: AppContext { func ensureSleepBlocking(_ shouldBeBlocking: Bool, blockingObjects: [Any]) { if UIApplication.shared.isIdleTimerDisabled != shouldBeBlocking { if shouldBeBlocking { - var logString: String = "Blocking sleep because of: \(String(describing: blockingObjects.first))" + var logString: String = "Blocking sleep because of: \(String(describing: blockingObjects.first))" // stringlint:disable if blockingObjects.count > 1 { logString = "\(logString) (and \(blockingObjects.count - 1) others)" @@ -209,7 +209,7 @@ final class MainAppContext: AppContext { // b) modified time before app launch time. let filePath: String = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName).path - if !fileName.hasPrefix("ows_temp") { + if !fileName.hasPrefix("ows_temp") { // stringlint:disable // It's fine if we can't get the attributes (the file may have been deleted since we found it), // also don't delete files which were created in the last N minutes guard diff --git a/Session/Meta/SessionApp.swift b/Session/Meta/SessionApp.swift index 94f52ae67..3dc0ac663 100644 --- a/Session/Meta/SessionApp.swift +++ b/Session/Meta/SessionApp.swift @@ -13,10 +13,10 @@ public struct SessionApp { static var versionInfo: String { let buildNumber: String = (Bundle.main.infoDictionary?["CFBundleVersion"] as? String) - .map { " (\($0))" } + .map { " (\($0))" } // stringlint:disable .defaulting(to: "") let appVersion: String? = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) - .map { "App: \($0)\(buildNumber)" } + .map { "App: \($0)\(buildNumber)" } // stringlint:disable #if DEBUG let commitInfo: String? = (Bundle.main.infoDictionary?["GitCommitHash"] as? String).map { "Commit: \($0)" } #else @@ -24,9 +24,9 @@ public struct SessionApp { #endif let versionInfo: [String] = [ - "iOS \(UIDevice.current.systemVersion)", + "iOS \(UIDevice.current.systemVersion)", // stringlint:disable appVersion, - "libSession: \(SessionUtil.libSessionVersion)", + "libSession: \(SessionUtil.libSessionVersion)", // stringlint:disable commitInfo ].compactMap { $0 } diff --git a/Session/Notifications/PushRegistrationManager.swift b/Session/Notifications/PushRegistrationManager.swift index 439fe2f75..99f40f1e9 100644 --- a/Session/Notifications/PushRegistrationManager.swift +++ b/Session/Notifications/PushRegistrationManager.swift @@ -176,7 +176,7 @@ public enum PushRegistrationError: Error { // so the user doesn't remain indefinitely hung for no good reason. return Fail( error: PushRegistrationError.pushNotSupported( - description: "Device configuration disallows push notifications" + description: "Device configuration disallows push notifications" // stringlint:disable ) ).eraseToAnyPublisher() @@ -282,7 +282,7 @@ public enum PushRegistrationError: Error { let caller: String = payload["caller"] as? String, let timestampMs: Int64 = payload["timestamp"] as? Int64 else { - SessionCallManager.reportFakeCall(info: "Missing payload data") + SessionCallManager.reportFakeCall(info: "Missing payload data") // stringlint:disable return } @@ -327,7 +327,7 @@ public enum PushRegistrationError: Error { } guard let call: SessionCall = maybeCall else { - SessionCallManager.reportFakeCall(info: "Could not retrieve call from database") + SessionCallManager.reportFakeCall(info: "Could not retrieve call from database") // stringlint:disable return } @@ -345,6 +345,6 @@ public enum PushRegistrationError: Error { // We transmit pushToken data as hex encoded string to the server fileprivate extension Data { var hexEncodedString: String { - return map { String(format: "%02hhx", $0) }.joined() + return map { String(format: "%02hhx", $0) }.joined() // stringlint:disable } } diff --git a/Session/Onboarding/RegisterVC.swift b/Session/Onboarding/RegisterVC.swift index 8febdc7ce..569687fe4 100644 --- a/Session/Onboarding/RegisterVC.swift +++ b/Session/Onboarding/RegisterVC.swift @@ -39,12 +39,7 @@ final class RegisterVC : BaseVC { let result = UILabel() result.font = .systemFont(ofSize: Values.verySmallFontSize) result.themeTextColor = .textPrimary - let text = "By using this service, you agree to our Terms of Service, End User License Agreement (EULA) and Privacy Policy" - let attributedText = NSMutableAttributedString(string: text, attributes: [ .font : UIFont.systemFont(ofSize: Values.verySmallFontSize) ]) - attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Terms of Service")) - attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "End User License Agreement (EULA)")) - attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Privacy Policy")) - result.attributedText = attributedText + result.attributedText = "onboardingTosPrivacy".localizedFormatted(in: result) result.textAlignment = .center result.lineBreakMode = .byWordWrapping result.numberOfLines = 0 @@ -231,6 +226,7 @@ final class RegisterVC : BaseVC { Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(enableCopyButton), userInfo: nil, repeats: false) } + // TODO: Will be removed by onboarding redesign @objc private func handleLegalLabelTapped(_ tapGestureRecognizer: UITapGestureRecognizer) { let urlAsString: String? let tosRange = (legalLabel.text! as NSString).range(of: "Terms of Service") diff --git a/Session/Onboarding/RestoreVC.swift b/Session/Onboarding/RestoreVC.swift index 15d228d06..247a7ed12 100644 --- a/Session/Onboarding/RestoreVC.swift +++ b/Session/Onboarding/RestoreVC.swift @@ -26,18 +26,8 @@ final class RestoreVC: BaseVC { private lazy var legalLabel: UILabel = { let result = UILabel() result.font = .systemFont(ofSize: Values.verySmallFontSize) - let text = "By using this service, you agree to our Terms of Service, End User License Agreement (EULA) and Privacy Policy" - let attributedText = NSMutableAttributedString( - string: text, - attributes: [ - .font: UIFont.systemFont(ofSize: Values.verySmallFontSize) - ] - ) - attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Terms of Service")) - attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "End User License Agreement (EULA)")) - attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Privacy Policy")) result.themeTextColor = .textPrimary - result.attributedText = attributedText + result.attributedText = "onboardingTosPrivacy".localizedFormatted(in: result) result.textAlignment = .center result.lineBreakMode = .byWordWrapping result.numberOfLines = 0 @@ -230,6 +220,7 @@ final class RestoreVC: BaseVC { self.navigationController?.pushViewController(pnModeVC, animated: true) } + // TODO: Will be removed by onboarding redesign @objc private func handleLegalLabelTapped(_ tapGestureRecognizer: UITapGestureRecognizer) { let urlAsString: String? let tosRange = (legalLabel.text! as NSString).range(of: "Terms of Service") diff --git a/Session/Onboarding/SeedVC.swift b/Session/Onboarding/SeedVC.swift index 09bd501ac..5da9fd6bb 100644 --- a/Session/Onboarding/SeedVC.swift +++ b/Session/Onboarding/SeedVC.swift @@ -42,10 +42,10 @@ final class SeedVC: BaseVC { private lazy var redactedMnemonic: String = { if isIPhone5OrSmaller { - return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆" + return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆" // stringlint:disable } - return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆ ▆▆▆▆▆▆▆▆ ▆▆ ▆▆▆ ▆▆▆▆▆▆▆" + return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆ ▆▆▆▆▆▆▆▆ ▆▆ ▆▆▆ ▆▆▆▆▆▆▆" // stringlint:disable }() // MARK: - Initialization @@ -68,12 +68,12 @@ final class SeedVC: BaseVC { result.setProgress(0.9, animated: false) ThemeManager.onThemeChange(observer: result) { [weak result] _, primaryColor in - let title = "You're almost finished! 90%" + let title = "You're almost finished! 90%" // stringlint:disable let attributedTitle = NSMutableAttributedString(string: title) attributedTitle.addAttribute( .foregroundColor, value: primaryColor.color, - range: (title as NSString).range(of: "90%") + range: (title as NSString).range(of: "90%") // stringlint:disable ) result?.title = attributedTitle } @@ -234,12 +234,12 @@ final class SeedVC: BaseVC { UIView.transition(with: seedReminderView.titleLabel, duration: 0.25, options: .transitionCrossDissolve, animations: { ThemeManager.onThemeChange(observer: self.seedReminderView) { [weak self] _, primaryColor in - let title = "Account Secured! 100%" + let title = "Account Secured! 100%" // stringlint:disable let attributedTitle = NSMutableAttributedString(string: title) attributedTitle.addAttribute( .foregroundColor, value: primaryColor.color, - range: (title as NSString).range(of: "100%") + range: (title as NSString).range(of: "100%") // stringlint:disable ) self?.seedReminderView.title = attributedTitle } diff --git a/Session/Path/PathVC.swift b/Session/Path/PathVC.swift index 71673c97d..02932fd79 100644 --- a/Session/Path/PathVC.swift +++ b/Session/Path/PathVC.swift @@ -219,8 +219,8 @@ final class PathVC: BaseVC { private func getPathRow(snode: Snode, location: LineView.Location, dotAnimationStartDelay: Double, dotAnimationRepeatInterval: Double, isGuardSnode: Bool) -> UIStackView { let country: String = (IP2Country.isInitialized ? - IP2Country.shared.countryNamesCache.wrappedValue[snode.ip].defaulting(to: "Resolving...") : - "Resolving..." + IP2Country.shared.countryNamesCache.wrappedValue[snode.ip].defaulting(to: "resolving".localized()) : + "resolving".localized() ) return getPathRow( diff --git a/Session/Settings/HelpViewModel.swift b/Session/Settings/HelpViewModel.swift index ea3a73b12..419897388 100644 --- a/Session/Settings/HelpViewModel.swift +++ b/Session/Settings/HelpViewModel.swift @@ -154,7 +154,7 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa elements: [ SessionCell.Info( id: .support, - title: "Export Database", + title: "Export Database", // stringlint:disable rightAccessory: .icon( UIImage(systemName: "square.and.arrow.up.trianglebadge.exclamationmark")? .withRenderingMode(.alwaysTemplate), @@ -224,7 +224,7 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa self.transitionToScreen( ConfirmationModal( info: ConfirmationModal.Info( - title: "Export Database", + title: "Export Database", // stringlint:disable body: .input( explanation: NSAttributedString( string: """ @@ -235,12 +235,12 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa This password will be used to encrypt the database decryption key and will be exported alongside the database """ ), - placeholder: "Enter a password", + placeholder: "Enter a password", // stringlint:disable initialValue: generatedPassword, clearButton: true, onChange: { [weak self] value in self?.databaseKeyEncryptionPassword = value } ), - confirmTitle: "Export", + confirmTitle: "Export", // stringlint:disable dismissOnConfirm: false, onConfirm: { [weak self] modal in modal.dismiss(animated: true) { @@ -248,8 +248,8 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa self?.transitionToScreen( ConfirmationModal( info: ConfirmationModal.Info( - title: "Error", - body: .text("Password must be at least 6 characters") + title: "Error", // stringlint:disable + body: .text("Password must be at least 6 characters") // stringlint:disable ) ), transitionType: .present @@ -275,14 +275,14 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa self?.transitionToScreen( ConfirmationModal( info: ConfirmationModal.Info( - title: "Password", + title: "Password", // stringlint:disable body: .text(""" The generated password was: \(generatedPassword) Avoid sending this via the same means as the database """), - confirmTitle: "Share", + confirmTitle: "Share", // stringlint:disable dismissOnConfirm: false, onConfirm: { [weak self] modal in modal.dismiss(animated: true) { @@ -319,16 +319,16 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa let message: String = { switch error { case CryptoKitError.incorrectKeySize: - return "The password must be between 6 and 32 characters (padded to 32 bytes)" + return "The password must be between 6 and 32 characters (padded to 32 bytes)" // stringlint:disable - default: return "Failed to export database" + default: return "Failed to export database" // stringlint:disable } }() self?.transitionToScreen( ConfirmationModal( info: ConfirmationModal.Info( - title: "Error", + title: "Error", // stringlint:disable body: .text(message) ) ), diff --git a/Session/Settings/Views/VersionFooterView.swift b/Session/Settings/Views/VersionFooterView.swift index 4a7a5a65f..1ebc2aff9 100644 --- a/Session/Settings/Views/VersionFooterView.swift +++ b/Session/Settings/Views/VersionFooterView.swift @@ -37,7 +37,7 @@ class VersionFooterView: UIView { let version: String = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, let buildNumber: String = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { - result.text = "Version \(version) (\(buildNumber))" + result.text = "Version \(version) (\(buildNumber))" // stringlint:disable } return result diff --git a/Session/Shared/FullConversationCell.swift b/Session/Shared/FullConversationCell.swift index 4bb7983a4..e001ef348 100644 --- a/Session/Shared/FullConversationCell.swift +++ b/Session/Shared/FullConversationCell.swift @@ -7,7 +7,7 @@ import SessionMessagingKit import SessionUtilitiesKit public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticCell { - public static let mutePrefix: String = "\u{e067} " + public static let mutePrefix: String = "\u{e067} " // stringlint:disable public static let unreadCountViewSize: CGFloat = 20 private static let statusIndicatorSize: CGFloat = 14 @@ -105,7 +105,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC let result: UILabel = UILabel() result.font = .boldSystemFont(ofSize: Values.verySmallFontSize) result.themeTextColor = .conversationButton_unreadBubbleText - result.text = "@" + result.text = "@" // stringlint:disable result.textAlignment = .center return result @@ -401,7 +401,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC unreadImageView.isHidden = (!unreadCountView.isHidden || !threadIsUnread) unreadCountLabel.text = (unreadCount <= 0 ? "" : - (unreadCount < 10000 ? "\(unreadCount)" : "9999+") + (unreadCount < 10000 ? "\(unreadCount)" : "9999+") // stringlint:disable ) unreadCountLabel.font = .boldSystemFont( ofSize: (unreadCount < 10000 ? Values.verySmallFontSize : 8) @@ -526,7 +526,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC if let hasUnread: Bool = hasUnread { if hasUnread { unreadCountView.isHidden = false - unreadCountLabel.text = "1" + unreadCountLabel.text = "1" // stringlint:disable unreadCountLabel.font = .boldSystemFont(ofSize: Values.verySmallFontSize) accentLineView.alpha = 1 } else { @@ -579,7 +579,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC let authorName: String = cellViewModel.authorName(for: cellViewModel.threadVariant) result.append(NSAttributedString( - string: "\(authorName): ", + string: "\(authorName): ", // stringlint:disable attributes: [ .foregroundColor: textColor ] )) } @@ -624,7 +624,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC guard !content.isEmpty, content != "noteToSelf".localized() else { return NSMutableAttributedString( string: (authorName != nil && authorName?.isEmpty != true ? - "\(authorName ?? ""): \(content)" : + "\(authorName ?? ""): \(content)" : // stringlint:disable content ), attributes: [ .foregroundColor: textColor ] @@ -666,8 +666,8 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC normalizedSnippet .ranges( of: (Singleton.hasAppContext && Singleton.appContext.isRTL ? - "(\(part.lowercased()))(^|[^a-zA-Z0-9])" : - "(^|[^a-zA-Z0-9])(\(part.lowercased()))" + "(\(part.lowercased()))(^|[^a-zA-Z0-9])" : // stringlint:disable + "(^|[^a-zA-Z0-9])(\(part.lowercased()))" // stringlint:disable ), options: [.regularExpression] ) @@ -702,7 +702,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC guard !authorName.isEmpty else { return nil } let authorPrefix: NSAttributedString = NSAttributedString( - string: "\(authorName): ", + string: "\(authorName): ", // stringlint:disable attributes: [ .foregroundColor: textColor ] ) diff --git a/Session/Shared/ScanQRCodeWrapperVC.swift b/Session/Shared/ScanQRCodeWrapperVC.swift index a80b2305c..cef131fb7 100644 --- a/Session/Shared/ScanQRCodeWrapperVC.swift +++ b/Session/Shared/ScanQRCodeWrapperVC.swift @@ -29,7 +29,7 @@ final class ScanQRCodeWrapperVC: BaseVC { override func viewDidLoad() { super.viewDidLoad() - title = "Scan QR Code" + title = "qrScan".localized() // Set up navigation bar if needed if isPresentedModally { diff --git a/Session/Utilities/Date+Utilities.swift b/Session/Utilities/Date+Utilities.swift index c6e440f3f..b50ba69f6 100644 --- a/Session/Utilities/Date+Utilities.swift +++ b/Session/Utilities/Date+Utilities.swift @@ -1,5 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. +// stringlint:disable + import Foundation import SessionUtilitiesKit diff --git a/Session/Utilities/IP2Country.swift b/Session/Utilities/IP2Country.swift index 830b291f7..427671217 100644 --- a/Session/Utilities/IP2Country.swift +++ b/Session/Utilities/IP2Country.swift @@ -44,10 +44,10 @@ final class IP2Country { let ipAsInt: Int = IPv4.toInt(ip) guard - let ipv4TableIndex = ipv4Table["network"]?.firstIndex(where: { $0 > ipAsInt }).map({ $0 - 1 }), - let countryID: Int = ipv4Table["registered_country_geoname_id"]?[ipv4TableIndex], - let countryNamesTableIndex = countryNamesTable["geoname_id"]?.firstIndex(of: String(countryID)), - let result: String = countryNamesTable["country_name"]?[countryNamesTableIndex] + let ipv4TableIndex = ipv4Table["network"]?.firstIndex(where: { $0 > ipAsInt }).map({ $0 - 1 }), // stringlint:disable + let countryID: Int = ipv4Table["registered_country_geoname_id"]?[ipv4TableIndex], // stringlint:disable + let countryNamesTableIndex = countryNamesTable["geoname_id"]?.firstIndex(of: String(countryID)), // stringlint:disable + let result: String = countryNamesTable["country_name"]?[countryNamesTableIndex] // stringlint:disable else { return "onionRoutingPathUnknownCountry".localized() // Relies on the array being sorted } diff --git a/Session/Utilities/MentionUtilities.swift b/Session/Utilities/MentionUtilities.swift index 75416ad39..c93124f5d 100644 --- a/Session/Utilities/MentionUtilities.swift +++ b/Session/Utilities/MentionUtilities.swift @@ -41,7 +41,7 @@ public enum MentionUtilities { attributes: [NSAttributedString.Key: Any] ) -> NSAttributedString { guard - let regex: NSRegularExpression = try? NSRegularExpression(pattern: "@[0-9a-fA-F]{66}", options: []) + let regex: NSRegularExpression = try? NSRegularExpression(pattern: "@[0-9a-fA-F]{66}", options: []) // stringlint:disable else { return NSAttributedString(string: string) } @@ -78,7 +78,7 @@ public enum MentionUtilities { }() else { continue } - string = string.replacingCharacters(in: range, with: "@\(targetString)") + string = string.replacingCharacters(in: range, with: "@\(targetString)") // stringlint:disable lastMatchEnd = (match.range.location + targetString.utf16.count) mentions.append(( diff --git a/Session/Utilities/QRCode.swift b/Session/Utilities/QRCode.swift index e9bebd201..1b5c8898c 100644 --- a/Session/Utilities/QRCode.swift +++ b/Session/Utilities/QRCode.swift @@ -10,12 +10,12 @@ enum QRCode { static func generate(for string: String, hasBackground: Bool) -> UIImage { let data = string.data(using: .utf8) var qrCodeAsCIImage: CIImage - let filter1 = CIFilter(name: "CIQRCodeGenerator")! + let filter1 = CIFilter(name: "CIQRCodeGenerator")! // stringlint:disable filter1.setValue(data, forKey: "inputMessage") qrCodeAsCIImage = filter1.outputImage! guard !hasBackground else { - let filter2 = CIFilter(name: "CIFalseColor")! + let filter2 = CIFilter(name: "CIFalseColor")! // stringlint:disable filter2.setValue(qrCodeAsCIImage, forKey: "inputImage") filter2.setValue(CIColor(color: .black), forKey: "inputColor0") filter2.setValue(CIColor(color: .white), forKey: "inputColor1") @@ -25,10 +25,10 @@ enum QRCode { return UIImage(ciImage: scaledQRCodeAsCIImage) } - let filter2 = CIFilter(name: "CIColorInvert")! + let filter2 = CIFilter(name: "CIColorInvert")! // stringlint:disable filter2.setValue(qrCodeAsCIImage, forKey: "inputImage") qrCodeAsCIImage = filter2.outputImage! - let filter3 = CIFilter(name: "CIMaskToAlpha")! + let filter3 = CIFilter(name: "CIMaskToAlpha")! // stringlint:disable filter3.setValue(qrCodeAsCIImage, forKey: "inputImage") qrCodeAsCIImage = filter3.outputImage! diff --git a/SessionNotificationServiceExtension/NSENotificationPresenter.swift b/SessionNotificationServiceExtension/NSENotificationPresenter.swift index 2d354525a..fe8ccf7b7 100644 --- a/SessionNotificationServiceExtension/NSENotificationPresenter.swift +++ b/SessionNotificationServiceExtension/NSENotificationPresenter.swift @@ -259,7 +259,7 @@ private extension String { var matchEnd = m1.range.location + m1.range.length if let displayName: String = Profile.displayNameNoFallback(id: publicKey) { - result = (result as NSString).replacingCharacters(in: m1.range, with: "@\(displayName)") + result = (result as NSString).replacingCharacters(in: m1.range, with: "@\(displayName)") // stringlint:disable mentions.append((range: NSRange(location: m1.range.location, length: displayName.utf16.count + 1), publicKey: publicKey)) // + 1 to include the @ matchEnd = m1.range.location + displayName.utf16.count } diff --git a/SessionNotificationServiceExtension/NotificationError.swift b/SessionNotificationServiceExtension/NotificationError.swift index 5d2884509..017e666dc 100644 --- a/SessionNotificationServiceExtension/NotificationError.swift +++ b/SessionNotificationServiceExtension/NotificationError.swift @@ -10,9 +10,9 @@ enum NotificationError: LocalizedError { public var errorDescription: String? { switch self { - case .processing(let result): return "Failed to process notification (\(result))" - case .messageProcessing: return "Failed to process message" - case .messageHandling(let error): return "Failed to handle message (\(error))" + case .processing(let result): return "Failed to process notification (\(result))" // stringlint:disable + case .messageProcessing: return "Failed to process message" // stringlint:disable + case .messageHandling(let error): return "Failed to handle message (\(error))" // stringlint:disable } } } diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 5df487184..26b394dec 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -17,10 +17,10 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension private var request: UNNotificationRequest? private var openGroupPollCancellable: AnyCancellable? - public static let isFromRemoteKey = "remote" - public static let threadIdKey = "Signal.AppNotificationsUserInfoKey.threadId" - public static let threadVariantRaw = "Signal.AppNotificationsUserInfoKey.threadVariantRaw" - public static let threadNotificationCounter = "Session.AppNotificationsUserInfoKey.threadNotificationCounter" + public static let isFromRemoteKey = "remote" // stringlint:disable + public static let threadIdKey = "Signal.AppNotificationsUserInfoKey.threadId" // stringlint:disable + public static let threadVariantRaw = "Signal.AppNotificationsUserInfoKey.threadVariantRaw" // stringlint:disable + public static let threadNotificationCounter = "Session.AppNotificationsUserInfoKey.threadNotificationCounter" // stringlint:disable private static let callPreOfferLargeNotificationSupressionDuration: TimeInterval = 30 // MARK: Did receive a remote push notification request @@ -320,9 +320,9 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension guard let caller: String = callMessage.sender, let timestamp = callMessage.sentTimestamp else { return } let payload: JSON = [ - "uuid": callMessage.uuid, - "caller": caller, - "timestamp": timestamp + "uuid": callMessage.uuid, // stringlint:disable + "caller": caller, // stringlint:disable + "timestamp": timestamp // stringlint:disable ] CXProvider.reportNewIncomingVoIPPushPayload(payload) { error in @@ -352,7 +352,9 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension if let sender: String = callMessage.sender { let senderDisplayName: String = Profile.displayName(db, id: sender, threadVariant: .contact) - notificationContent.body = "\(senderDisplayName) is calling..." + notificationContent.body = "callsIncoming" + .put(key: "name", value: senderDisplayName) + .localized() } else { notificationContent.body = "Incoming call..." diff --git a/SessionShareExtension/ShareNavController.swift b/SessionShareExtension/ShareNavController.swift index a61e7e535..68bd9ecb0 100644 --- a/SessionShareExtension/ShareNavController.swift +++ b/SessionShareExtension/ShareNavController.swift @@ -473,7 +473,7 @@ final class ShareNavController: UINavigationController, ShareViewDelegate { switch value { case let data as Data: - let customFileName = "Contact.vcf" + let customFileName = "Contact.vcf" // stringlint:disable let customFileExtension = MIMETypeUtil.fileExtension(forUTIType: srcUtiType) guard let tempFilePath = OWSFileSystem.writeData(toTemporaryFile: data, fileExtension: customFileExtension) else { @@ -504,7 +504,7 @@ final class ShareNavController: UINavigationController, ShareViewDelegate { ) return } - guard let tempFilePath = OWSFileSystem.writeData(toTemporaryFile: data, fileExtension: "txt") else { + guard let tempFilePath = OWSFileSystem.writeData(toTemporaryFile: data, fileExtension: "txt") else { // stringlint:disable resolver( Result.failure(ShareViewControllerError.assertionError(description: "Error writing item data: \(String(describing: error))")) ) @@ -574,7 +574,7 @@ final class ShareNavController: UINavigationController, ShareViewDelegate { case let image as UIImage: if let data = image.pngData() { - let tempFilePath = OWSFileSystem.temporaryFilePath(withFileExtension: "png") + let tempFilePath = OWSFileSystem.temporaryFilePath(withFileExtension: "png") // stringlint:disable do { let url = NSURL.fileURL(withPath: tempFilePath) try data.write(to: url) diff --git a/SessionShareExtension/ThreadPickerVC.swift b/SessionShareExtension/ThreadPickerVC.swift index 424136910..25e43c1e7 100644 --- a/SessionShareExtension/ThreadPickerVC.swift +++ b/SessionShareExtension/ThreadPickerVC.swift @@ -212,7 +212,7 @@ final class ThreadPickerVC: UIViewController, UITableViewDataSource, UITableView ( (messageText?.isEmpty == true || (attachments[0].text() == messageText) ? attachments[0].text() : - "\(attachments[0].text() ?? "")\n\n\(messageText ?? "")" + "\(attachments[0].text() ?? "")\n\n\(messageText ?? "")" // stringlint:disable ) ) : messageText