From aff01c19424b3d7d2faaa3f437dd576041c7e802 Mon Sep 17 00:00:00 2001 From: Katherine Bertelsen Date: Fri, 17 Oct 2025 14:35:51 -0500 Subject: [PATCH 1/8] Weeks --- .../Localizations/en.lproj/Localizable.strings | 1 - .../en.lproj/Localizable.stringsdict | 16 ++++++++++++++++ .../Enum/FlightRecorderLoggingDuration.swift | 2 +- .../FlightRecorderLoggingDurationTests.swift | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.strings b/BitwardenResources/Localizations/en.lproj/Localizable.strings index a2c7691c5b..1e27a3ad9a 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.strings +++ b/BitwardenResources/Localizations/en.lproj/Localizable.strings @@ -1147,7 +1147,6 @@ "LoggingDuration" = "Logging duration"; "LogsWillBeAutomaticallyDeletedAfter30DaysDescriptionLong" = "Logs will be automatically deleted after 30 days. Bitwarden is only able to access your log data when you share it."; "ForDetailsOnWhatIsAndIsntLoggedVisitTheBitwardenHelpCenter" = "For details on what is and isn’t logged, visit the **[Bitwarden help center](%1$@)**."; -"OneWeek" = "1 week"; "ShowMore" = "Show more"; "ShowLess" = "Show less"; "ItemNameX" = "Item name, %1$@"; diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict index 85d5f314a4..3d80874bf3 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict +++ b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict @@ -18,5 +18,21 @@ %d minutes + XWeeks + + NSStringLocalizedFormatKey + %#@weeks@ + weeks + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d week + other + %d weeks + + diff --git a/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDuration.swift b/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDuration.swift index 48295c02b7..79e0f0282a 100644 --- a/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDuration.swift +++ b/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDuration.swift @@ -22,7 +22,7 @@ enum FlightRecorderLoggingDuration: CaseIterable, Codable, Menuable { case .oneHour: Localizations.oneHour case .eightHours: Localizations.xHours(8) case .twentyFourHours: Localizations.xHours(24) - case .oneWeek: Localizations.oneWeek + case .oneWeek: Localizations.xWeeks(1) } } diff --git a/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDurationTests.swift b/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDurationTests.swift index 0424b58035..80a05721f5 100644 --- a/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDurationTests.swift +++ b/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDurationTests.swift @@ -28,7 +28,7 @@ class FlightRecorderLoggingDurationTests: BitwardenTestCase { XCTAssertEqual(FlightRecorderLoggingDuration.oneHour.localizedName, Localizations.oneHour) XCTAssertEqual(FlightRecorderLoggingDuration.eightHours.localizedName, Localizations.xHours(8)) XCTAssertEqual(FlightRecorderLoggingDuration.twentyFourHours.localizedName, Localizations.xHours(24)) - XCTAssertEqual(FlightRecorderLoggingDuration.oneWeek.localizedName, Localizations.oneWeek) + XCTAssertEqual(FlightRecorderLoggingDuration.oneWeek.localizedName, Localizations.xWeeks(1)) } /// `shortDescription` returns a short string representation of the logging duration. From 1edaf55b71603d5573cf4f326ae8e01035898f1a Mon Sep 17 00:00:00 2001 From: Katherine Bertelsen Date: Fri, 17 Oct 2025 14:47:18 -0500 Subject: [PATCH 2/8] Days --- .../Models/Enum/SessionTimeoutValue.swift | 29 +---------------- .../Enum/SessionTimeoutValueTests.swift | 4 +-- .../Models/Enum/SessionTimeoutValue.swift | 30 ++++++++++++++++- .../en.lproj/Localizable.strings | 8 ----- .../en.lproj/Localizable.stringsdict | 32 +++++++++++++++++++ .../Enum/FlightRecorderLoggingDuration.swift | 2 +- .../FlightRecorderLoggingDurationTests.swift | 2 +- .../Models/Enum/SendDeletionDateType.swift | 12 +++---- .../Enum/SendDeletionDateTypeTests.swift | 12 +++---- .../AccountSecurityState.swift | 28 +--------------- 10 files changed, 79 insertions(+), 80 deletions(-) diff --git a/AuthenticatorShared/Core/Platform/Models/Enum/SessionTimeoutValue.swift b/AuthenticatorShared/Core/Platform/Models/Enum/SessionTimeoutValue.swift index f969ecc301..2cb41066b9 100644 --- a/AuthenticatorShared/Core/Platform/Models/Enum/SessionTimeoutValue.swift +++ b/AuthenticatorShared/Core/Platform/Models/Enum/SessionTimeoutValue.swift @@ -1,12 +1,11 @@ import BitwardenKit -import BitwardenResources // MARK: - SessionTimeoutValue /// An enumeration of session timeout values to choose from. /// BWA does not use the custom value. /// -extension SessionTimeoutValue: @retroactive CaseIterable, Menuable { +extension SessionTimeoutValue: @retroactive CaseIterable { /// All of the cases to show in the menu. public static let allCases: [Self] = [ .immediately, @@ -19,30 +18,4 @@ extension SessionTimeoutValue: @retroactive CaseIterable, Menuable { .onAppRestart, .never, ] - - /// The localized string representation of a `SessionTimeoutValue`. - public var localizedName: String { - switch self { - case .immediately: - Localizations.immediately - case .oneMinute: - Localizations.xMinutes(1) - case .fiveMinutes: - Localizations.xMinutes(5) - case .fifteenMinutes: - Localizations.xMinutes(15) - case .thirtyMinutes: - Localizations.xMinutes(30) - case .oneHour: - Localizations.oneHour - case .fourHours: - Localizations.fourHours - case .onAppRestart: - Localizations.onRestart - case .never: - Localizations.never - case .custom: - Localizations.custom - } - } } diff --git a/AuthenticatorShared/Core/Platform/Models/Enum/SessionTimeoutValueTests.swift b/AuthenticatorShared/Core/Platform/Models/Enum/SessionTimeoutValueTests.swift index 7477c8f539..3eac453a45 100644 --- a/AuthenticatorShared/Core/Platform/Models/Enum/SessionTimeoutValueTests.swift +++ b/AuthenticatorShared/Core/Platform/Models/Enum/SessionTimeoutValueTests.swift @@ -32,8 +32,8 @@ final class SessionTimeoutValueTests: BitwardenTestCase { XCTAssertEqual(SessionTimeoutValue.fiveMinutes.localizedName, Localizations.xMinutes(5)) XCTAssertEqual(SessionTimeoutValue.fifteenMinutes.localizedName, Localizations.xMinutes(15)) XCTAssertEqual(SessionTimeoutValue.thirtyMinutes.localizedName, Localizations.xMinutes(30)) - XCTAssertEqual(SessionTimeoutValue.oneHour.localizedName, Localizations.oneHour) - XCTAssertEqual(SessionTimeoutValue.fourHours.localizedName, Localizations.fourHours) + XCTAssertEqual(SessionTimeoutValue.oneHour.localizedName, Localizations.xHours(1)) + XCTAssertEqual(SessionTimeoutValue.fourHours.localizedName, Localizations.xHours(4)) XCTAssertEqual(SessionTimeoutValue.onAppRestart.localizedName, Localizations.onRestart) XCTAssertEqual(SessionTimeoutValue.never.localizedName, Localizations.never) XCTAssertEqual(SessionTimeoutValue.custom(123).localizedName, Localizations.custom) diff --git a/BitwardenKit/Core/Platform/Models/Enum/SessionTimeoutValue.swift b/BitwardenKit/Core/Platform/Models/Enum/SessionTimeoutValue.swift index 5e8debe1d7..134b78a3c1 100644 --- a/BitwardenKit/Core/Platform/Models/Enum/SessionTimeoutValue.swift +++ b/BitwardenKit/Core/Platform/Models/Enum/SessionTimeoutValue.swift @@ -1,8 +1,10 @@ +import BitwardenResources + // MARK: - SessionTimeoutValue /// An enumeration of session timeout values to choose from. /// -public enum SessionTimeoutValue: Codable, RawRepresentable, Equatable, Hashable, Sendable { +public enum SessionTimeoutValue: Codable, RawRepresentable, Equatable, Hashable, Menuable, Sendable { /// Time out immediately. case immediately @@ -38,6 +40,32 @@ public enum SessionTimeoutValue: Codable, RawRepresentable, Equatable, Hashable, rawValue * 60 } + /// The localized string representation of a `SessionTimeoutValue`. + public var localizedName: String { + switch self { + case .immediately: + Localizations.immediately + case .oneMinute: + Localizations.xMinutes(1) + case .fiveMinutes: + Localizations.xMinutes(5) + case .fifteenMinutes: + Localizations.xMinutes(15) + case .thirtyMinutes: + Localizations.xMinutes(30) + case .oneHour: + Localizations.xHours(1) + case .fourHours: + Localizations.xHours(4) + case .onAppRestart: + Localizations.onRestart + case .never: + Localizations.never + case .custom: + Localizations.custom + } + } + /// The session timeout value in minutes. public var rawValue: Int { switch self { diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.strings b/BitwardenResources/Localizations/en.lproj/Localizable.strings index 1e27a3ad9a..8e58a89335 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.strings +++ b/BitwardenResources/Localizations/en.lproj/Localizable.strings @@ -131,8 +131,6 @@ "LastSync" = "Last sync:"; "Length" = "Length"; "Lock" = "Lock"; -"OneHour" = "1 hour"; -"FourHours" = "4 hours"; "Immediately" = "Immediately"; "VaultTimeout" = "Vault timeout"; "VaultTimeoutAction" = "Vault timeout action"; @@ -584,11 +582,6 @@ "SendDeleted" = "Send deleted"; "SendUpdated" = "Send saved"; "NewSendCreated" = "Send created"; -"OneDay" = "1 day"; -"TwoDays" = "2 days"; -"ThreeDays" = "3 days"; -"SevenDays" = "7 days"; -"ThirtyDays" = "30 days"; "Custom" = "Custom"; "ShareOnSave" = "Share this Send upon save"; "SendDisabledWarning" = "Due to an enterprise policy, you are only able to delete an existing Send."; @@ -841,7 +834,6 @@ "OneHourAndXMinute" = "One hour and %1$@ minutes"; "XHoursAndOneMinute" = "%1$@ hours and one minute"; "XHoursAndYMinutes" = "%1$@ hours and %2$@ minutes"; -"XHours" = "%1$@ hours"; "PasskeyManagementExplanationLong" = "Use Bitwarden to save new passkeys and log in with passkeys stored in your vault."; "AutofillServicesExplanationLong" = "The Android Autofill Framework is used to assist in filling login information into other apps on your device."; "UseInlineAutofillExplanationLong" = "Use inline autofill if your selected keyboard supports it. Otherwise, use the default overlay."; diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict index 3d80874bf3..a2aa82184d 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict +++ b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict @@ -2,6 +2,38 @@ + XDays + + NSStringLocalizedFormatKey + %#@days@ + days + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d day + other + %d days + + + XHours + + NSStringLocalizedFormatKey + %#@hours@ + hours + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d hour + other + %d hours + + XMinutes NSStringLocalizedFormatKey diff --git a/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDuration.swift b/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDuration.swift index 79e0f0282a..df0aadc871 100644 --- a/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDuration.swift +++ b/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDuration.swift @@ -19,7 +19,7 @@ enum FlightRecorderLoggingDuration: CaseIterable, Codable, Menuable { var localizedName: String { switch self { - case .oneHour: Localizations.oneHour + case .oneHour: Localizations.xHours(1) case .eightHours: Localizations.xHours(8) case .twentyFourHours: Localizations.xHours(24) case .oneWeek: Localizations.xWeeks(1) diff --git a/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDurationTests.swift b/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDurationTests.swift index 80a05721f5..9ec4e67b69 100644 --- a/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDurationTests.swift +++ b/BitwardenShared/Core/Platform/Models/Enum/FlightRecorderLoggingDurationTests.swift @@ -25,7 +25,7 @@ class FlightRecorderLoggingDurationTests: BitwardenTestCase { /// `localizedName` returns the correct values. func test_localizedName() { - XCTAssertEqual(FlightRecorderLoggingDuration.oneHour.localizedName, Localizations.oneHour) + XCTAssertEqual(FlightRecorderLoggingDuration.oneHour.localizedName, Localizations.xHours(1)) XCTAssertEqual(FlightRecorderLoggingDuration.eightHours.localizedName, Localizations.xHours(8)) XCTAssertEqual(FlightRecorderLoggingDuration.twentyFourHours.localizedName, Localizations.xHours(24)) XCTAssertEqual(FlightRecorderLoggingDuration.oneWeek.localizedName, Localizations.xWeeks(1)) diff --git a/BitwardenShared/Core/Tools/Models/Enum/SendDeletionDateType.swift b/BitwardenShared/Core/Tools/Models/Enum/SendDeletionDateType.swift index c885456517..cabdd644d5 100644 --- a/BitwardenShared/Core/Tools/Models/Enum/SendDeletionDateType.swift +++ b/BitwardenShared/Core/Tools/Models/Enum/SendDeletionDateType.swift @@ -32,12 +32,12 @@ enum SendDeletionDateType: Menuable { var localizedName: String { switch self { - case .oneHour: Localizations.oneHour - case .oneDay: Localizations.oneDay - case .twoDays: Localizations.twoDays - case .threeDays: Localizations.threeDays - case .sevenDays: Localizations.sevenDays - case .thirtyDays: Localizations.thirtyDays + case .oneHour: Localizations.xHours(1) + case .oneDay: Localizations.xDays(1) + case .twoDays: Localizations.xDays(2) + case .threeDays: Localizations.xDays(3) + case .sevenDays: Localizations.xDays(7) + case .thirtyDays: Localizations.xDays(30) case let .custom(customDate): customDate.dateTimeDisplay } } diff --git a/BitwardenShared/Core/Tools/Models/Enum/SendDeletionDateTypeTests.swift b/BitwardenShared/Core/Tools/Models/Enum/SendDeletionDateTypeTests.swift index 6ae69556cd..6989bcf2b9 100644 --- a/BitwardenShared/Core/Tools/Models/Enum/SendDeletionDateTypeTests.swift +++ b/BitwardenShared/Core/Tools/Models/Enum/SendDeletionDateTypeTests.swift @@ -37,12 +37,12 @@ class SendDeletionDateTypeTests: BitwardenTestCase { /// `localizedName` returns the localized name of the option to display in the menu. func test_localizedName() { - XCTAssertEqual(SendDeletionDateType.oneHour.localizedName, Localizations.oneHour) - XCTAssertEqual(SendDeletionDateType.oneDay.localizedName, Localizations.oneDay) - XCTAssertEqual(SendDeletionDateType.twoDays.localizedName, Localizations.twoDays) - XCTAssertEqual(SendDeletionDateType.threeDays.localizedName, Localizations.threeDays) - XCTAssertEqual(SendDeletionDateType.sevenDays.localizedName, Localizations.sevenDays) - XCTAssertEqual(SendDeletionDateType.thirtyDays.localizedName, Localizations.thirtyDays) + XCTAssertEqual(SendDeletionDateType.oneHour.localizedName, Localizations.xHours(1)) + XCTAssertEqual(SendDeletionDateType.oneDay.localizedName, Localizations.xDays(1)) + XCTAssertEqual(SendDeletionDateType.twoDays.localizedName, Localizations.xDays(2)) + XCTAssertEqual(SendDeletionDateType.threeDays.localizedName, Localizations.xDays(3)) + XCTAssertEqual(SendDeletionDateType.sevenDays.localizedName, Localizations.xDays(7)) + XCTAssertEqual(SendDeletionDateType.thirtyDays.localizedName, Localizations.xDays(30)) XCTAssertEqual( SendDeletionDateType.custom(Date(year: 2024, month: 1, day: 19)).localizedName, diff --git a/BitwardenShared/UI/Platform/Settings/Settings/AccountSecurity/AccountSecurityState.swift b/BitwardenShared/UI/Platform/Settings/Settings/AccountSecurity/AccountSecurityState.swift index b0cd8b72d8..6a40bdd8d8 100644 --- a/BitwardenShared/UI/Platform/Settings/Settings/AccountSecurity/AccountSecurityState.swift +++ b/BitwardenShared/UI/Platform/Settings/Settings/AccountSecurity/AccountSecurityState.swift @@ -21,7 +21,7 @@ public enum UnlockMethod { /// An enumeration of session timeout values to choose from. /// -extension SessionTimeoutValue: @retroactive CaseIterable, @retroactive Menuable { +extension SessionTimeoutValue: @retroactive CaseIterable { /// All of the cases to show in the menu. public static let allCases: [Self] = [ .immediately, @@ -35,32 +35,6 @@ extension SessionTimeoutValue: @retroactive CaseIterable, @retroactive Menuable .never, .custom(-100), ] - - /// The localized string representation of a `SessionTimeoutValue`. - public var localizedName: String { - switch self { - case .immediately: - Localizations.immediately - case .oneMinute: - Localizations.xMinutes(1) - case .fiveMinutes: - Localizations.xMinutes(5) - case .fifteenMinutes: - Localizations.xMinutes(15) - case .thirtyMinutes: - Localizations.xMinutes(30) - case .oneHour: - Localizations.oneHour - case .fourHours: - Localizations.fourHours - case .onAppRestart: - Localizations.onRestart - case .never: - Localizations.never - case .custom: - Localizations.custom - } - } } // MARK: - SessionTimeoutAction From 9d36700c466acc530ad45acc4e74640bd850f42e Mon Sep 17 00:00:00 2001 From: Katherine Bertelsen Date: Fri, 17 Oct 2025 15:48:51 -0500 Subject: [PATCH 3/8] Seconds --- .../Enum/ClearClipboardValueTests.swift | 30 --------- .../TestHelpers/MockPasteboardService.swift | 1 + .../AuthenticatorItemState.swift | 6 +- .../Models/Enum/ClearClipboardValue.swift | 13 ++-- .../Enum/ClearClipboardValueTests.swift | 11 ++-- .../en.lproj/Localizable.strings | 5 -- .../en.lproj/Localizable.stringsdict | 16 +++++ .../Models/Enum/ClearClipboardValue.swift | 61 ------------------- .../Repositories/SettingsRepository.swift | 1 + .../TestHelpers/MockSettingsRepository.swift | 1 + .../TestHelpers/MockPasteboardService.swift | 1 + 11 files changed, 34 insertions(+), 112 deletions(-) delete mode 100644 AuthenticatorShared/Core/Platform/Models/Enum/ClearClipboardValueTests.swift rename {AuthenticatorShared => BitwardenKit}/Core/Platform/Models/Enum/ClearClipboardValue.swift (83%) rename {BitwardenShared => BitwardenKit}/Core/Platform/Models/Enum/ClearClipboardValueTests.swift (90%) delete mode 100644 BitwardenShared/Core/Platform/Models/Enum/ClearClipboardValue.swift diff --git a/AuthenticatorShared/Core/Platform/Models/Enum/ClearClipboardValueTests.swift b/AuthenticatorShared/Core/Platform/Models/Enum/ClearClipboardValueTests.swift deleted file mode 100644 index 680d101562..0000000000 --- a/AuthenticatorShared/Core/Platform/Models/Enum/ClearClipboardValueTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -import BitwardenResources -import XCTest - -@testable import AuthenticatorShared - -class ClearClipboardValueTests: BitwardenTestCase { - // MARK: Tests - - /// `localizedName` returns the correct values. - func test_localizedName() { - XCTAssertEqual(ClearClipboardValue.never.localizedName, Localizations.never) - XCTAssertEqual(ClearClipboardValue.tenSeconds.localizedName, Localizations.tenSeconds) - XCTAssertEqual(ClearClipboardValue.twentySeconds.localizedName, Localizations.twentySeconds) - XCTAssertEqual(ClearClipboardValue.thirtySeconds.localizedName, Localizations.thirtySeconds) - XCTAssertEqual(ClearClipboardValue.oneMinute.localizedName, Localizations.xMinutes(1)) - XCTAssertEqual(ClearClipboardValue.twoMinutes.localizedName, Localizations.xMinutes(2)) - XCTAssertEqual(ClearClipboardValue.fiveMinutes.localizedName, Localizations.xMinutes(5)) - } - - /// `rawValue` returns the correct values. - func test_rawValues() { - XCTAssertEqual(ClearClipboardValue.never.rawValue, -1) - XCTAssertEqual(ClearClipboardValue.tenSeconds.rawValue, 10) - XCTAssertEqual(ClearClipboardValue.twentySeconds.rawValue, 20) - XCTAssertEqual(ClearClipboardValue.thirtySeconds.rawValue, 30) - XCTAssertEqual(ClearClipboardValue.oneMinute.rawValue, 60) - XCTAssertEqual(ClearClipboardValue.twoMinutes.rawValue, 120) - XCTAssertEqual(ClearClipboardValue.fiveMinutes.rawValue, 300) - } -} diff --git a/AuthenticatorShared/Core/Platform/Services/TestHelpers/MockPasteboardService.swift b/AuthenticatorShared/Core/Platform/Services/TestHelpers/MockPasteboardService.swift index f574786a52..3b842a8a9b 100644 --- a/AuthenticatorShared/Core/Platform/Services/TestHelpers/MockPasteboardService.swift +++ b/AuthenticatorShared/Core/Platform/Services/TestHelpers/MockPasteboardService.swift @@ -1,4 +1,5 @@ @testable import AuthenticatorShared +import BitwardenKit class MockPasteboardService: PasteboardService { var clearClipboardValue: ClearClipboardValue = .never diff --git a/AuthenticatorShared/UI/Vault/AuthenticatorItem/AuthenticatorItemState.swift b/AuthenticatorShared/UI/Vault/AuthenticatorItem/AuthenticatorItemState.swift index 2e4648e028..22015e22f5 100644 --- a/AuthenticatorShared/UI/Vault/AuthenticatorItem/AuthenticatorItemState.swift +++ b/AuthenticatorShared/UI/Vault/AuthenticatorItem/AuthenticatorItemState.swift @@ -161,11 +161,11 @@ enum TotpPeriodOptions: Int, Menuable, CaseIterable { var localizedName: String { switch self { case .thirty: - Localizations.thirtySeconds + Localizations.xSeconds(30) case .sixty: - Localizations.sixtySeconds + Localizations.xSeconds(60) case .ninety: - Localizations.ninetySeconds + Localizations.xSeconds(90) } } } diff --git a/AuthenticatorShared/Core/Platform/Models/Enum/ClearClipboardValue.swift b/BitwardenKit/Core/Platform/Models/Enum/ClearClipboardValue.swift similarity index 83% rename from AuthenticatorShared/Core/Platform/Models/Enum/ClearClipboardValue.swift rename to BitwardenKit/Core/Platform/Models/Enum/ClearClipboardValue.swift index 9347a331e3..a6222ba81e 100644 --- a/AuthenticatorShared/Core/Platform/Models/Enum/ClearClipboardValue.swift +++ b/BitwardenKit/Core/Platform/Models/Enum/ClearClipboardValue.swift @@ -1,4 +1,3 @@ -import BitwardenKit import BitwardenResources import Foundation @@ -6,7 +5,7 @@ import Foundation /// The time after which the clipboard should be cleared. /// -enum ClearClipboardValue: Int, Menuable { +public enum ClearClipboardValue: Int, Menuable { /// Do not clear the clipboard. case never = -1 @@ -29,7 +28,7 @@ enum ClearClipboardValue: Int, Menuable { case fiveMinutes = 300 /// All of the cases to show in the menu, in order. - static let allCases: [Self] = [ + public static let allCases: [Self] = [ .never, .tenSeconds, .twentySeconds, @@ -40,16 +39,16 @@ enum ClearClipboardValue: Int, Menuable { ] /// The name of the value to display in the menu. - var localizedName: String { + public var localizedName: String { switch self { case .never: Localizations.never case .tenSeconds: - Localizations.tenSeconds + Localizations.xSeconds(10) case .twentySeconds: - Localizations.twentySeconds + Localizations.xSeconds(20) case .thirtySeconds: - Localizations.thirtySeconds + Localizations.xSeconds(30) case .oneMinute: Localizations.xMinutes(1) case .twoMinutes: diff --git a/BitwardenShared/Core/Platform/Models/Enum/ClearClipboardValueTests.swift b/BitwardenKit/Core/Platform/Models/Enum/ClearClipboardValueTests.swift similarity index 90% rename from BitwardenShared/Core/Platform/Models/Enum/ClearClipboardValueTests.swift rename to BitwardenKit/Core/Platform/Models/Enum/ClearClipboardValueTests.swift index 08ffc1b939..8d7a37a9b6 100644 --- a/BitwardenShared/Core/Platform/Models/Enum/ClearClipboardValueTests.swift +++ b/BitwardenKit/Core/Platform/Models/Enum/ClearClipboardValueTests.swift @@ -1,7 +1,6 @@ -import XCTest - +import BitwardenKit import BitwardenResources -@testable import BitwardenShared +import XCTest class ClearClipboardValueTests: BitwardenTestCase { // MARK: Tests @@ -9,9 +8,9 @@ class ClearClipboardValueTests: BitwardenTestCase { /// `localizedName` returns the correct values. func test_localizedName() { XCTAssertEqual(ClearClipboardValue.never.localizedName, Localizations.never) - XCTAssertEqual(ClearClipboardValue.tenSeconds.localizedName, Localizations.tenSeconds) - XCTAssertEqual(ClearClipboardValue.twentySeconds.localizedName, Localizations.twentySeconds) - XCTAssertEqual(ClearClipboardValue.thirtySeconds.localizedName, Localizations.thirtySeconds) + XCTAssertEqual(ClearClipboardValue.tenSeconds.localizedName, Localizations.xSeconds(10)) + XCTAssertEqual(ClearClipboardValue.twentySeconds.localizedName, Localizations.xSeconds(20)) + XCTAssertEqual(ClearClipboardValue.thirtySeconds.localizedName, Localizations.xSeconds(30)) XCTAssertEqual(ClearClipboardValue.oneMinute.localizedName, Localizations.xMinutes(1)) XCTAssertEqual(ClearClipboardValue.twoMinutes.localizedName, Localizations.xMinutes(2)) XCTAssertEqual(ClearClipboardValue.fiveMinutes.localizedName, Localizations.xMinutes(5)) diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.strings b/BitwardenResources/Localizations/en.lproj/Localizable.strings index 8e58a89335..9ba2cc7ac8 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.strings +++ b/BitwardenResources/Localizations/en.lproj/Localizable.strings @@ -437,9 +437,6 @@ "VaultLockedIdentity" = "Your vault is locked. Verify your identity to continue."; "Dark" = "Dark"; "Light" = "Light"; -"TenSeconds" = "10 seconds"; -"ThirtySeconds" = "30 seconds"; -"TwentySeconds" = "20 seconds"; "ClearClipboard" = "Clear clipboard"; "ClearClipboardDescription" = "Automatically clear copied values from your clipboard."; "DefaultUriMatchDetection" = "Default URI match detection"; @@ -1233,7 +1230,6 @@ "LearnMoreLink" = "[Learn more](%1$@)"; "LocalCodes" = "Local codes"; "NeedHelpVisitOurHelpCenterForGuidance" = "Need help? Visit our Help Center for guidance."; -"NinetySeconds" = "90 seconds"; "NoAskMe" = "No, ask me"; "NoCodes" = "You don’t have any codes to display"; "None" = "None"; @@ -1251,7 +1247,6 @@ "SetSaveLocallyAsYourDefaultSaveOption" = "Set “Save locally” as your default save option?"; "SetSaveToBitwardenAsYourDefaultSaveOption" = "Set “Save to Bitwarden” as your default save option?"; "SignInUsingUniqueCodes" = "Sign in using unique codes"; -"SixtySeconds" = "60 seconds"; "Skip" = "Skip"; "Steam" = "Steam"; "StoreAllOfYourLoginsAndSyncVerificationCodesDirectlyWithTheAuthenticatorApp" = "Store all of your logins and sync verification codes directly with the Authenticator app."; diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict index a2aa82184d..ba5899d365 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict +++ b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict @@ -50,6 +50,22 @@ %d minutes + XSeconds + + NSStringLocalizedFormatKey + %#@seconds@ + seconds + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d second + other + %d seconds + + XWeeks NSStringLocalizedFormatKey diff --git a/BitwardenShared/Core/Platform/Models/Enum/ClearClipboardValue.swift b/BitwardenShared/Core/Platform/Models/Enum/ClearClipboardValue.swift deleted file mode 100644 index 9347a331e3..0000000000 --- a/BitwardenShared/Core/Platform/Models/Enum/ClearClipboardValue.swift +++ /dev/null @@ -1,61 +0,0 @@ -import BitwardenKit -import BitwardenResources -import Foundation - -// MARK: - ClearClipboardValue - -/// The time after which the clipboard should be cleared. -/// -enum ClearClipboardValue: Int, Menuable { - /// Do not clear the clipboard. - case never = -1 - - /// Clear the clipboard after ten seconds. - case tenSeconds = 10 - - /// Clear the clipboard after twenty seconds. - case twentySeconds = 20 - - /// Clear the clipboard after thirty seconds. - case thirtySeconds = 30 - - /// Clear the clipboard after one minute. - case oneMinute = 60 - - /// Clear the clipboard after two minutes. - case twoMinutes = 120 - - /// Clear the clipboard after five minutes. - case fiveMinutes = 300 - - /// All of the cases to show in the menu, in order. - static let allCases: [Self] = [ - .never, - .tenSeconds, - .twentySeconds, - .thirtySeconds, - .oneMinute, - .twoMinutes, - .fiveMinutes, - ] - - /// The name of the value to display in the menu. - var localizedName: String { - switch self { - case .never: - Localizations.never - case .tenSeconds: - Localizations.tenSeconds - case .twentySeconds: - Localizations.twentySeconds - case .thirtySeconds: - Localizations.thirtySeconds - case .oneMinute: - Localizations.xMinutes(1) - case .twoMinutes: - Localizations.xMinutes(2) - case .fiveMinutes: - Localizations.xMinutes(5) - } - } -} diff --git a/BitwardenShared/Core/Platform/Repositories/SettingsRepository.swift b/BitwardenShared/Core/Platform/Repositories/SettingsRepository.swift index bb693a537e..89f4fbf356 100644 --- a/BitwardenShared/Core/Platform/Repositories/SettingsRepository.swift +++ b/BitwardenShared/Core/Platform/Repositories/SettingsRepository.swift @@ -1,3 +1,4 @@ +import BitwardenKit import BitwardenSdk import Combine import Foundation diff --git a/BitwardenShared/Core/Platform/Repositories/TestHelpers/MockSettingsRepository.swift b/BitwardenShared/Core/Platform/Repositories/TestHelpers/MockSettingsRepository.swift index b7ac40555e..e3be1b83a7 100644 --- a/BitwardenShared/Core/Platform/Repositories/TestHelpers/MockSettingsRepository.swift +++ b/BitwardenShared/Core/Platform/Repositories/TestHelpers/MockSettingsRepository.swift @@ -1,3 +1,4 @@ +import BitwardenKit import BitwardenSdk import Combine import Foundation diff --git a/BitwardenShared/Core/Platform/Services/TestHelpers/MockPasteboardService.swift b/BitwardenShared/Core/Platform/Services/TestHelpers/MockPasteboardService.swift index e4da2fb382..96072a051b 100644 --- a/BitwardenShared/Core/Platform/Services/TestHelpers/MockPasteboardService.swift +++ b/BitwardenShared/Core/Platform/Services/TestHelpers/MockPasteboardService.swift @@ -1,3 +1,4 @@ +import BitwardenKit @testable import BitwardenShared class MockPasteboardService: PasteboardService { From b00a2741b6777c5cf8d9b0f74fc29099a9d5d384 Mon Sep 17 00:00:00 2001 From: Katherine Bertelsen Date: Tue, 21 Oct 2025 09:13:19 -0500 Subject: [PATCH 4/8] Add comments --- .../Localizations/en.lproj/Localizable.stringsdict | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict index ba5899d365..73a9386ee6 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict +++ b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict @@ -2,6 +2,7 @@ + XDays NSStringLocalizedFormatKey @@ -18,6 +19,7 @@ %d days + XHours NSStringLocalizedFormatKey @@ -34,6 +36,7 @@ %d hours + XMinutes NSStringLocalizedFormatKey @@ -50,6 +53,7 @@ %d minutes + XSeconds NSStringLocalizedFormatKey @@ -66,6 +70,7 @@ %d seconds + XWeeks NSStringLocalizedFormatKey From 40e34c4a68452504334f37667ad667e9faa91a2b Mon Sep 17 00:00:00 2001 From: Katherine Bertelsen Date: Fri, 31 Oct 2025 12:46:56 -0500 Subject: [PATCH 5/8] Move X items to stringsdict --- .../Localizations/en.lproj/Localizable.strings | 1 - .../en.lproj/Localizable.stringsdict | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.strings b/BitwardenResources/Localizations/en.lproj/Localizable.strings index 9ba2cc7ac8..90b7d5973e 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.strings +++ b/BitwardenResources/Localizations/en.lproj/Localizable.strings @@ -1102,7 +1102,6 @@ "SendNameRequired" = "Send name (required)"; "CheckPasswordForDataBreaches" = "Check password for data breaches"; "PrivateNote" = "Private note"; -"XItems" = "%1$@ items"; "CannotDeleteUserSoleOwnerDescriptionLong" = "Cannot delete this user because it is the sole owner of at least one organization. Please delete these organizations or upgrade another user."; "APasskeyAlreadyExistsForThisApplication" = "A passkey already exists for this application."; "APasskeyAlreadyExistsForThisApplicationButAnErrorOccurredWhileLoadingIt" = "A passkey already exists for this application but an error occurred while loading it."; diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict index 73a9386ee6..b70c2eef4e 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict +++ b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict @@ -19,6 +19,23 @@ %d days + + XItems + + NSStringLocalizedFormatKey + %#@items@ + items + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d item + other + %d items + + XHours From d07a2468846a77dbacc6acde77aa48ac83fc4f89 Mon Sep 17 00:00:00 2001 From: Katherine Bertelsen Date: Fri, 31 Oct 2025 13:56:03 -0500 Subject: [PATCH 6/8] Decrypt vault items --- .../Localizations/en.lproj/Localizable.strings | 2 -- .../en.lproj/Localizable.stringsdict | 17 +++++++++++++++++ .../UI/Vault/Extensions/Alert+Vault.swift | 4 +--- .../UI/Vault/Extensions/AlertVaultTests.swift | 4 ++-- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.strings b/BitwardenResources/Localizations/en.lproj/Localizable.strings index 90b7d5973e..aa9deeb377 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.strings +++ b/BitwardenResources/Localizations/en.lproj/Localizable.strings @@ -1193,8 +1193,6 @@ "PasswordLastUpdated" = "Password last updated: %1$@"; "DecryptionError" = "Decryption error"; "BitwardenCouldNotDecryptThisVaultItemDescriptionLong" = "Bitwarden could not decrypt this vault item. Copy and share this error report with customer success to avoid additional data loss."; -"BitwardenCouldNotDecryptOneVaultItemDescriptionLong" = "Bitwarden could not decrypt 1 vault item. Copy and share this error report with customer success to avoid additional data loss."; -"BitwardenCouldNotDecryptXVaultItemsDescriptionLong" = "Bitwarden could not decrypt %1$@ vault items. Copy and share this error report with customer success to avoid additional data loss."; "CopyErrorReport" = "Copy error report"; "ErrorCannotDecrypt" = "[error: cannot decrypt]"; "AccountName" = "Account name"; diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict index b70c2eef4e..cce955a056 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict +++ b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict @@ -2,6 +2,23 @@ + + BitwardenCouldNotDecryptXVaultItemsDescriptionLong + + NSStringLocalizedFormatKey + Bitwarden could not decrypt %#@vaultitems@. Copy and share this error report with customer success to avoid additional data loss. + vaultitems + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d vault item + other + %d vault items + + XDays diff --git a/BitwardenShared/UI/Vault/Extensions/Alert+Vault.swift b/BitwardenShared/UI/Vault/Extensions/Alert+Vault.swift index a4d9eb1f7c..c3dfb13a9c 100644 --- a/BitwardenShared/UI/Vault/Extensions/Alert+Vault.swift +++ b/BitwardenShared/UI/Vault/Extensions/Alert+Vault.swift @@ -26,9 +26,7 @@ extension Alert { let message = if isFromCipherTap { Localizations.bitwardenCouldNotDecryptThisVaultItemDescriptionLong } else { - cipherIds.count == 1 - ? Localizations.bitwardenCouldNotDecryptOneVaultItemDescriptionLong - : Localizations.bitwardenCouldNotDecryptXVaultItemsDescriptionLong(cipherIds.count) + Localizations.bitwardenCouldNotDecryptXVaultItemsDescriptionLong(cipherIds.count) } return Alert( diff --git a/BitwardenShared/UI/Vault/Extensions/AlertVaultTests.swift b/BitwardenShared/UI/Vault/Extensions/AlertVaultTests.swift index 16a890e47f..f2d8563a29 100644 --- a/BitwardenShared/UI/Vault/Extensions/AlertVaultTests.swift +++ b/BitwardenShared/UI/Vault/Extensions/AlertVaultTests.swift @@ -48,7 +48,7 @@ class AlertVaultTests: BitwardenTestCase { // swiftlint:disable:this type_body_l XCTAssertEqual(subject.title, Localizations.decryptionError) XCTAssertEqual( subject.message, - Localizations.bitwardenCouldNotDecryptOneVaultItemDescriptionLong, + Localizations.bitwardenCouldNotDecryptXVaultItemsDescriptionLong(1), ) XCTAssertEqual(subject.alertActions.count, 2) XCTAssertEqual(subject.alertActions[0].title, Localizations.copyErrorReport) @@ -61,7 +61,7 @@ class AlertVaultTests: BitwardenTestCase { // swiftlint:disable:this type_body_l copyString, """ \(Localizations.decryptionError) - \(Localizations.bitwardenCouldNotDecryptOneVaultItemDescriptionLong) + \(Localizations.bitwardenCouldNotDecryptXVaultItemsDescriptionLong(1)) 123abc """, From 9d5d62286f1e54efe541e7a41442f0ad50730198 Mon Sep 17 00:00:00 2001 From: Katherine Bertelsen Date: Fri, 31 Oct 2025 13:56:23 -0500 Subject: [PATCH 7/8] Adjust for languages --- .../Localizations/en.lproj/Localizable.stringsdict | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict index cce955a056..fe35a649f8 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict +++ b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict @@ -6,7 +6,7 @@ BitwardenCouldNotDecryptXVaultItemsDescriptionLong NSStringLocalizedFormatKey - Bitwarden could not decrypt %#@vaultitems@. Copy and share this error report with customer success to avoid additional data loss. + %#@vaultitems@. Copy and share this error report with customer success to avoid additional data loss. vaultitems NSStringFormatSpecTypeKey @@ -14,9 +14,9 @@ NSStringFormatValueTypeKey d one - %d vault item + Bitwarden could not decrypt %d vault item other - %d vault items + Bitwarden could not decrypt %d vault items From 4b04e3a2291d20e5fc51ff176209f86d319fe4e5 Mon Sep 17 00:00:00 2001 From: Katherine Bertelsen Date: Fri, 31 Oct 2025 14:35:06 -0500 Subject: [PATCH 8/8] Items imported --- .../Localizations/en.lproj/Localizable.strings | 1 - .../en.lproj/Localizable.stringsdict | 17 +++++++++++++++++ .../ImportCXF/ImportCXF/ImportCXFState.swift | 2 +- .../ImportCXF/ImportCXFStateTests.swift | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.strings b/BitwardenResources/Localizations/en.lproj/Localizable.strings index aa9deeb377..69942a52ce 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.strings +++ b/BitwardenResources/Localizations/en.lproj/Localizable.strings @@ -1080,7 +1080,6 @@ "ImportingEllipsis" = "Importing…"; "AreYouSureYouWantToCancelTheImportProcessQuestionMark" = "Are you sure you want to cancel the import process?"; "ImportFailed" = "Import failed"; -"ItemsSuccessfullyImported" = "%1$@ items successfully imported"; "ThereWasAnIssueImportingAllOfYourPasswordsNoDataWasDeleted" = "There was an issue importing all of your passwords.\n\nNo data was deleted."; "RetryImport" = "Retry import"; "ShowVault" = "Show vault"; diff --git a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict index fe35a649f8..4378a060de 100644 --- a/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict +++ b/BitwardenResources/Localizations/en.lproj/Localizable.stringsdict @@ -53,6 +53,23 @@ %d items + + XItemsSuccessfullyImported + + NSStringLocalizedFormatKey + %#@items@ successfully imported + items + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + d + one + %d item + other + %d items + + XHours diff --git a/BitwardenShared/UI/Tools/ImportCXF/ImportCXF/ImportCXFState.swift b/BitwardenShared/UI/Tools/ImportCXF/ImportCXF/ImportCXFState.swift index ed928d7d5f..7f57be13c7 100644 --- a/BitwardenShared/UI/Tools/ImportCXF/ImportCXF/ImportCXFState.swift +++ b/BitwardenShared/UI/Tools/ImportCXF/ImportCXF/ImportCXFState.swift @@ -65,7 +65,7 @@ struct ImportCXFState: Equatable, Sendable { case .importing: Localizations.pleaseDoNotCloseTheApp case let .success(total, _): - Localizations.itemsSuccessfullyImported(total) + Localizations.xItemsSuccessfullyImported(total) case let .failure(message): message } diff --git a/BitwardenShared/UI/Tools/ImportCXF/ImportCXF/ImportCXFStateTests.swift b/BitwardenShared/UI/Tools/ImportCXF/ImportCXF/ImportCXFStateTests.swift index 1451dc354a..33ffceb4c4 100644 --- a/BitwardenShared/UI/Tools/ImportCXF/ImportCXF/ImportCXFStateTests.swift +++ b/BitwardenShared/UI/Tools/ImportCXF/ImportCXF/ImportCXFStateTests.swift @@ -65,7 +65,7 @@ class ImportCXFStateTests: BitwardenTestCase { XCTAssertEqual(subject.message, Localizations.pleaseDoNotCloseTheApp) subject.status = .success(totalImportedCredentials: 1, importedResults: []) - XCTAssertEqual(subject.message, Localizations.itemsSuccessfullyImported(1)) + XCTAssertEqual(subject.message, Localizations.xItemsSuccessfullyImported(1)) subject.status = .failure(message: "Something went wrong") XCTAssertEqual(subject.message, "Something went wrong")