TF-250 Improvements, translations

This commit is contained in:
Zbigniew Cisiński 2024-04-21 14:39:28 +02:00
parent a86207ec93
commit d950dac300
39 changed files with 236 additions and 102 deletions

View File

@ -639,6 +639,8 @@
C27D543F275D393D001E9ABF /* BackupMenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D543E275D393D001E9ABF /* BackupMenuPresenter.swift */; };
C27D5441275D462D001E9ABF /* BackupMenuViewController+TableCellHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D5440275D462D001E9ABF /* BackupMenuViewController+TableCellHandling.swift */; };
C27D5443275D478E001E9ABF /* BackupMenuViewControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D5442275D478E001E9ABF /* BackupMenuViewControlling.swift */; };
C27D99DF2BD52C8A0008203F /* WatchConsts.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D99DE2BD52C8A0008203F /* WatchConsts.swift */; };
C27D99E12BD53AB30008203F /* LogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D99E02BD53AB30008203F /* LogoView.swift */; };
C27E6FAF28FC57FD00AC9FD1 /* DynamicTypesEntityMigrationPolicySync.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FAE28FC57FD00AC9FD1 /* DynamicTypesEntityMigrationPolicySync.swift */; };
C27E6FB128FC7E3800AC9FD1 /* ServiceRecord2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB028FC7E3800AC9FD1 /* ServiceRecord2.swift */; };
C27E6FB328FC87AD00AC9FD1 /* InfoRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB228FC87AD00AC9FD1 /* InfoRecord.swift */; };
@ -2423,6 +2425,8 @@
C27D543E275D393D001E9ABF /* BackupMenuPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupMenuPresenter.swift; sourceTree = "<group>"; };
C27D5440275D462D001E9ABF /* BackupMenuViewController+TableCellHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BackupMenuViewController+TableCellHandling.swift"; sourceTree = "<group>"; };
C27D5442275D478E001E9ABF /* BackupMenuViewControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupMenuViewControlling.swift; sourceTree = "<group>"; };
C27D99DE2BD52C8A0008203F /* WatchConsts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConsts.swift; sourceTree = "<group>"; };
C27D99E02BD53AB30008203F /* LogoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoView.swift; sourceTree = "<group>"; };
C27E6FAB28FC463600AC9FD1 /* Sync5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Sync5.xcdatamodel; sourceTree = "<group>"; };
C27E6FAE28FC57FD00AC9FD1 /* DynamicTypesEntityMigrationPolicySync.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicTypesEntityMigrationPolicySync.swift; sourceTree = "<group>"; };
C27E6FB028FC7E3800AC9FD1 /* ServiceRecord2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceRecord2.swift; sourceTree = "<group>"; };
@ -4978,6 +4982,7 @@
isa = PBXGroup;
children = (
C29378352BD1A3B6008D5125 /* AboutView.swift */,
C27D99E02BD53AB30008203F /* LogoView.swift */,
);
path = About;
sourceTree = "<group>";
@ -5606,6 +5611,7 @@
C268918B2BC4960C00713078 /* ServiceList */ = {
isa = PBXGroup;
children = (
C260DCC12BC885F1007807CC /* ServiceCellView.swift */,
C2B86D312BC356BA00AAAC63 /* ServiceListView.swift */,
C26891892BC4960600713078 /* ServiceListPresenter.swift */,
C268918C2BC4962300713078 /* ServiceListInteractor.swift */,
@ -5763,24 +5769,19 @@
C274C9CE2BAB8ABB008E7212 /* TwoFASWatch Watch App */ = {
isa = PBXGroup;
children = (
C2B86D272BC32FA300AAAC63 /* InteractorFactory.swift */,
C244BE492BD07AA000F7E566 /* Settings */,
C269837E2BCC7180009B3BE2 /* PIN */,
C269837D2BCC7175009B3BE2 /* Repositories */,
C269837C2BCC715C009B3BE2 /* Models */,
C274C9D52BAB8ABC008E7212 /* Preview Content */,
C27D99DD2BD52A690008203F /* Data */,
C260DCC02BC882AD007807CC /* TwoFASWatch-Watch-App-Info.plist */,
C274CAA02BAB98A5008E7212 /* TwoFASWatch Watch App.entitlements */,
C274C9CF2BAB8ABB008E7212 /* TwoFASWatchApp.swift */,
C26983812BCC8326009B3BE2 /* AppPresenter.swift */,
C27D99DC2BD52A5E0008203F /* App */,
C274C9D32BAB8ABC008E7212 /* Assets.xcassets */,
C281A2762BD489590068451C /* IntroductionView.swift */,
C26983832BCC8F6B009B3BE2 /* Main */,
C274C9D32BAB8ABC008E7212 /* Assets.xcassets */,
C274C9D52BAB8ABC008E7212 /* Preview Content */,
C2B86D292BC33D3000AAAC63 /* AppDelegateInteractor.swift */,
C260DCC12BC885F1007807CC /* ServiceCellView.swift */,
C244BE492BD07AA000F7E566 /* Settings */,
C269837E2BCC7180009B3BE2 /* PIN */,
C268918B2BC4960C00713078 /* ServiceList */,
C2627F382BC72E19009F93A9 /* Service */,
C2B86D372BC35B8300AAAC63 /* IconRenderer.swift */,
);
path = "TwoFASWatch Watch App";
sourceTree = "<group>";
@ -5958,6 +5959,27 @@
path = View;
sourceTree = "<group>";
};
C27D99DC2BD52A5E0008203F /* App */ = {
isa = PBXGroup;
children = (
C26983812BCC8326009B3BE2 /* AppPresenter.swift */,
C2B86D292BC33D3000AAAC63 /* AppDelegateInteractor.swift */,
);
path = App;
sourceTree = "<group>";
};
C27D99DD2BD52A690008203F /* Data */ = {
isa = PBXGroup;
children = (
C27D99DE2BD52C8A0008203F /* WatchConsts.swift */,
C2B86D272BC32FA300AAAC63 /* InteractorFactory.swift */,
C269837D2BCC7175009B3BE2 /* Repositories */,
C269837C2BCC715C009B3BE2 /* Models */,
C2B86D372BC35B8300AAAC63 /* IconRenderer.swift */,
);
path = Data;
sourceTree = "<group>";
};
C27E6FB428FC8AF200AC9FD1 /* Info */ = {
isa = PBXGroup;
children = (
@ -10187,9 +10209,11 @@
C2A4D32D2BC0B1AD0001587C /* TokenHandler.swift in Sources */,
C2B86D222BC3058A00AAAC63 /* UserDefaultsRepository.swift in Sources */,
C2B86D342BC3571E00AAAC63 /* ServiceView.swift in Sources */,
C27D99E12BD53AB30008203F /* LogoView.swift in Sources */,
C2A4D3322BC0B2B30001587C /* String+.swift in Sources */,
C2B86D2C2BC3492A00AAAC63 /* Service.swift in Sources */,
C293783A2BD1BF23008D5125 /* SecurityInteractor.swift in Sources */,
C27D99DF2BD52C8A0008203F /* WatchConsts.swift in Sources */,
C2B86D382BC35B8300AAAC63 /* IconRenderer.swift in Sources */,
C2B86D322BC356BA00AAAC63 /* ServiceListView.swift in Sources */,
C281A2732BD47D6C0068451C /* SuccessView.swift in Sources */,

View File

@ -284,8 +284,8 @@ internal enum T {
internal static let name = T.tr("Localizable", "app__name", fallback: "2FAS Authenticator")
}
internal enum Appearance {
/// Active search on startup
internal static let activeSearchDescription = T.tr("Localizable", "appearance__active_search_description", fallback: "Active search on startup")
/// Active search on startup.
internal static let activeSearchDescription = T.tr("Localizable", "appearance__active_search_description", fallback: "Active search on startup.")
/// Active search
internal static let toggleActiveSearch = T.tr("Localizable", "appearance__toggle_active_search", fallback: "Active search")
}
@ -336,8 +336,8 @@ internal enum T {
internal static let exportToFile = T.tr("Localizable", "backup__export_to_file", fallback: "Export to file")
/// File Backup
internal static let fileBackup = T.tr("Localizable", "backup__file_backup", fallback: "File Backup")
/// Use File Backup for offline backup of your tokens
internal static let fileBackupOfflineTitle = T.tr("Localizable", "backup__file_backup_offline_title", fallback: "Use File Backup for offline backup of your tokens")
/// Use File Backup for offline backup of your tokens.
internal static let fileBackupOfflineTitle = T.tr("Localizable", "backup__file_backup_offline_title", fallback: "Use File Backup for offline backup of your tokens.")
/// File error!
internal static let fileError = T.tr("Localizable", "backup__file_error", fallback: "File error!")
/// Google Drive has been disabled by the user
@ -442,8 +442,8 @@ internal enum T {
internal static let userOverQuotaIcloud = T.tr("Localizable", "backup__user_over_quota_icloud", fallback: "User is over quota on iCloud")
/// Verify PIN
internal static let verifyPin = T.tr("Localizable", "backup__verify_pin", fallback: "Verify PIN")
/// Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion
internal static let warningIntroduction = T.tr("Localizable", "backup__warning_introduction", fallback: "Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion")
/// Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion.
internal static let warningIntroduction = T.tr("Localizable", "backup__warning_introduction", fallback: "Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion.")
}
internal enum Browser {
/// Do you want to share the 2FA token for
@ -482,8 +482,8 @@ internal enum T {
internal static let deviceName = T.tr("Localizable", "browser__device_name", fallback: "Device nickname")
/// Forget this web browser
internal static let forgetThisBrowser = T.tr("Localizable", "browser__forget_this_browser", fallback: "Forget this web browser")
/// Install the 2FAS browser extension on your desktop computer
internal static let infoDescriptionFirst = T.tr("Localizable", "browser__info_description_first", fallback: "Install the 2FAS browser extension on your desktop computer")
/// Install the 2FAS browser extension on your desktop computer.
internal static let infoDescriptionFirst = T.tr("Localizable", "browser__info_description_first", fallback: "Install the 2FAS browser extension on your desktop computer.")
/// Pair it with your 2FAS app.
internal static let infoDescriptionSecond = T.tr("Localizable", "browser__info_description_second", fallback: "Pair it with your 2FAS app.")
/// 2FAS Web Browser extension
@ -666,6 +666,8 @@ internal enum T {
internal static let `set` = T.tr("Localizable", "commons__set", fallback: "Set")
/// Skip
internal static let skip = T.tr("Localizable", "commons__skip", fallback: "Skip")
/// Success
internal static let success = T.tr("Localizable", "commons__success", fallback: "Success")
/// The provided text is too long (max. %d chars)
internal static func textLongTitle(_ p1: Int) -> String {
return T.tr("Localizable", "commons__text_long_title", p1, fallback: "The provided text is too long (max. %d chars)")
@ -970,6 +972,8 @@ internal enum T {
internal static let enterCurrentPin = T.tr("Localizable", "security__enter_current_pin", fallback: "Please enter your current PIN")
/// Please enter your new PIN
internal static let enterNewPin = T.tr("Localizable", "security__enter_new_pin", fallback: "Please enter your new PIN")
/// Enter new PIN
internal static let enterNewPinShort = T.tr("Localizable", "security__enter_new_pin_short", fallback: "Enter new PIN")
/// Please enter your PIN
internal static let enterPin = T.tr("Localizable", "security__enter_pin", fallback: "Please enter your PIN")
/// Please enter your new %s PIN
@ -980,6 +984,8 @@ internal enum T {
internal static let incorrectPIN = T.tr("Localizable", "security__incorrect_PIN", fallback: "Incorrect PIN")
/// PIN incorrect! Please try again
internal static let pinErrorIncorrect = T.tr("Localizable", "security__pin_error_incorrect", fallback: "PIN incorrect! Please try again")
/// Repeat new PIN
internal static let repeatNewPinShort = T.tr("Localizable", "security__repeat_new_pin_short", fallback: "Repeat new PIN")
/// Too many attempts. Please try again later.
internal static let tooManyAttemptsError = T.tr("Localizable", "security__too_many_attempts_error", fallback: "Too many attempts. Please try again later.")
/// Too many attempts. Please try after one minute
@ -1053,16 +1059,15 @@ internal enum T {
internal static let gdSyncInfo = T.tr("Localizable", "settings__gd_sync_info", fallback: "Google Drive sync reminder")
/// General
internal static let general = T.tr("Localizable", "settings__general", fallback: "General")
/// Tokens will be revealed on tap
internal static let hideTokensDescription = T.tr("Localizable", "settings__hide_tokens_description", fallback: "Tokens will be revealed on tap")
/// Tokens will be revealed on tap.
internal static let hideTokensDescription = T.tr("Localizable", "settings__hide_tokens_description", fallback: "Tokens will be revealed on tap.")
/// Hide tokens
internal static let hideTokensTitle = T.tr("Localizable", "settings__hide_tokens_title", fallback: "Hide tokens")
/// Select the maximum number of unsuccessful attempts to enter the passcode before locking the application (lockout time can be changed below).
///
internal static let howManyAttemptsFooter = T.tr("Localizable", "settings__how_many_attempts_footer", fallback: "Select the maximum number of unsuccessful attempts to enter the passcode before locking the application (lockout time can be changed below).\n")
/// Your support allows us to develop new features and
/// improvements. Thank you!
internal static let infoFooter = T.tr("Localizable", "settings__info_footer", fallback: "Your support allows us to develop new features and\nimprovements. Thank you!")
/// Your support allows us to develop new features and improvements. Thank you!
internal static let infoFooter = T.tr("Localizable", "settings__info_footer", fallback: "Your support allows us to develop new features and improvements. Thank you!")
/// It matters
internal static let itMatters = T.tr("Localizable", "settings__it_matters", fallback: "It matters")
/// Knowledge
@ -1314,6 +1319,8 @@ internal enum T {
internal static let enterServiceName = T.tr("Localizable", "tokens__enter_service_name", fallback: "Enter Service Name")
/// Add manually
internal static let fabAddmanually = T.tr("Localizable", "tokens__fab_addmanually", fallback: "Add manually")
/// Favorite Services
internal static let favoriteServices = T.tr("Localizable", "tokens__favorite_services", fallback: "Favorite Services")
/// Service added successfully. We strongly recommend that you
internal static let galleryAdviceContentFirst = T.tr("Localizable", "tokens__gallery_advice_content_first", fallback: "Service added successfully. We strongly recommend that you ")
///
@ -1339,6 +1346,8 @@ internal enum T {
internal static let groupName = T.tr("Localizable", "tokens__group_name", fallback: "Group name:")
/// HOTP
internal static let hotp = T.tr("Localizable", "tokens__hotp", fallback: "HOTP")
/// HOTP services aren't supported yet
internal static let hotpNotSupported = T.tr("Localizable", "tokens__hotp_not_supported", fallback: "HOTP services aren't supported yet")
/// Yes, I want to delete this service
internal static let iWantToDeleteThisToken = T.tr("Localizable", "tokens__i_want_to_delete_this_token", fallback: "Yes, I want to delete this service")
/// Incorrect Secret key (only numbers 2 to 7, letters), max. 512 chars long
@ -1590,6 +1599,36 @@ internal enum T {
/// Use the Add Service button to add a new service
internal static let useAddServiceButtonTitle = T.tr("Localizable", "voiceover__use_add_service_button_title", fallback: "Use the Add Service button to add a new service")
}
internal enum Watch {
/// 2FAS watchOS app is a companion app for the 2FAS iOS application. It will present services backed up using iCloud sync.
///
/// For quick access, add them to Favorite Services.
///
/// Please remember to donate so we can further improve the 2FAS platform!
internal static let intro = T.tr("Localizable", "watch__intro", fallback: "2FAS watchOS app is a companion app for the 2FAS iOS application. It will present services backed up using iCloud sync.\n\nFor quick access, add them to Favorite Services.\n\nPlease remember to donate so we can further improve the 2FAS platform!")
}
internal enum Widget {
/// My secured account
internal static let mySecuredAccount = T.tr("Localizable", "widget__my_secured_account", fallback: "My secured account")
/// There are no services in the app available for selection
internal static let noServices = T.tr("Localizable", "widget__no_services", fallback: "There are no services in the app available for selection")
/// Widget functionality is not enabled in 2FAS Settings section
internal static let notEnabled = T.tr("Localizable", "widget__not_enabled", fallback: "Widget functionality is not enabled in 2FAS Settings section")
/// Widget functionality is not enabled in 2FAS Settings section and there are no services in the app available for selection
internal static let notEnabledNoServices = T.tr("Localizable", "widget__not_enabled_no_services", fallback: "Widget functionality is not enabled in 2FAS Settings section and there are no services in the app available for selection")
/// Placeholder
internal static let placeholder = T.tr("Localizable", "widget__placeholder", fallback: "Placeholder")
/// Select Service you want to show on your 2FAS Widget
internal static let selectServiceIntentDescription = T.tr("Localizable", "widget__select_service_intent_description", fallback: "Select Service you want to show on your 2FAS Widget")
/// Service icon
internal static let serviceIcon = T.tr("Localizable", "widget__service_icon", fallback: "Service icon")
/// Select which Services you would like to display on the Widget. If no Services are available, make sure that you've enabled Widgets in app Settings section
internal static let settingsDescription = T.tr("Localizable", "widget__settings_description", fallback: "Select which Services you would like to display on the Widget. If no Services are available, make sure that you've enabled Widgets in app Settings section")
/// This size is not supported yet
internal static let sizeNotSupported = T.tr("Localizable", "widget__size_not_supported", fallback: "This size is not supported yet")
/// Token
internal static let token = T.tr("Localizable", "widget__token", fallback: "Token")
}
internal enum Widgets {
/// Expires in:
internal static let expiresIn = T.tr("Localizable", "widgets__expires_in", fallback: "Expires in:")

View File

@ -284,8 +284,8 @@ internal enum T {
internal static let name = T.tr("Localizable", "app__name", fallback: "2FAS Authenticator")
}
internal enum Appearance {
/// Active search on startup
internal static let activeSearchDescription = T.tr("Localizable", "appearance__active_search_description", fallback: "Active search on startup")
/// Active search on startup.
internal static let activeSearchDescription = T.tr("Localizable", "appearance__active_search_description", fallback: "Active search on startup.")
/// Active search
internal static let toggleActiveSearch = T.tr("Localizable", "appearance__toggle_active_search", fallback: "Active search")
}
@ -336,8 +336,8 @@ internal enum T {
internal static let exportToFile = T.tr("Localizable", "backup__export_to_file", fallback: "Export to file")
/// File Backup
internal static let fileBackup = T.tr("Localizable", "backup__file_backup", fallback: "File Backup")
/// Use File Backup for offline backup of your tokens
internal static let fileBackupOfflineTitle = T.tr("Localizable", "backup__file_backup_offline_title", fallback: "Use File Backup for offline backup of your tokens")
/// Use File Backup for offline backup of your tokens.
internal static let fileBackupOfflineTitle = T.tr("Localizable", "backup__file_backup_offline_title", fallback: "Use File Backup for offline backup of your tokens.")
/// File error!
internal static let fileError = T.tr("Localizable", "backup__file_error", fallback: "File error!")
/// Google Drive has been disabled by the user
@ -442,8 +442,8 @@ internal enum T {
internal static let userOverQuotaIcloud = T.tr("Localizable", "backup__user_over_quota_icloud", fallback: "User is over quota on iCloud")
/// Verify PIN
internal static let verifyPin = T.tr("Localizable", "backup__verify_pin", fallback: "Verify PIN")
/// Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion
internal static let warningIntroduction = T.tr("Localizable", "backup__warning_introduction", fallback: "Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion")
/// Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion.
internal static let warningIntroduction = T.tr("Localizable", "backup__warning_introduction", fallback: "Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion.")
}
internal enum Browser {
/// Do you want to share the 2FA token for
@ -482,8 +482,8 @@ internal enum T {
internal static let deviceName = T.tr("Localizable", "browser__device_name", fallback: "Device nickname")
/// Forget this web browser
internal static let forgetThisBrowser = T.tr("Localizable", "browser__forget_this_browser", fallback: "Forget this web browser")
/// Install the 2FAS browser extension on your desktop computer
internal static let infoDescriptionFirst = T.tr("Localizable", "browser__info_description_first", fallback: "Install the 2FAS browser extension on your desktop computer")
/// Install the 2FAS browser extension on your desktop computer.
internal static let infoDescriptionFirst = T.tr("Localizable", "browser__info_description_first", fallback: "Install the 2FAS browser extension on your desktop computer.")
/// Pair it with your 2FAS app.
internal static let infoDescriptionSecond = T.tr("Localizable", "browser__info_description_second", fallback: "Pair it with your 2FAS app.")
/// 2FAS Web Browser extension
@ -666,6 +666,8 @@ internal enum T {
internal static let `set` = T.tr("Localizable", "commons__set", fallback: "Set")
/// Skip
internal static let skip = T.tr("Localizable", "commons__skip", fallback: "Skip")
/// Success
internal static let success = T.tr("Localizable", "commons__success", fallback: "Success")
/// The provided text is too long (max. %d chars)
internal static func textLongTitle(_ p1: Int) -> String {
return T.tr("Localizable", "commons__text_long_title", p1, fallback: "The provided text is too long (max. %d chars)")
@ -970,6 +972,8 @@ internal enum T {
internal static let enterCurrentPin = T.tr("Localizable", "security__enter_current_pin", fallback: "Please enter your current PIN")
/// Please enter your new PIN
internal static let enterNewPin = T.tr("Localizable", "security__enter_new_pin", fallback: "Please enter your new PIN")
/// Enter new PIN
internal static let enterNewPinShort = T.tr("Localizable", "security__enter_new_pin_short", fallback: "Enter new PIN")
/// Please enter your PIN
internal static let enterPin = T.tr("Localizable", "security__enter_pin", fallback: "Please enter your PIN")
/// Please enter your new %s PIN
@ -980,6 +984,8 @@ internal enum T {
internal static let incorrectPIN = T.tr("Localizable", "security__incorrect_PIN", fallback: "Incorrect PIN")
/// PIN incorrect! Please try again
internal static let pinErrorIncorrect = T.tr("Localizable", "security__pin_error_incorrect", fallback: "PIN incorrect! Please try again")
/// Repeat new PIN
internal static let repeatNewPinShort = T.tr("Localizable", "security__repeat_new_pin_short", fallback: "Repeat new PIN")
/// Too many attempts. Please try again later.
internal static let tooManyAttemptsError = T.tr("Localizable", "security__too_many_attempts_error", fallback: "Too many attempts. Please try again later.")
/// Too many attempts. Please try after one minute
@ -1053,8 +1059,8 @@ internal enum T {
internal static let gdSyncInfo = T.tr("Localizable", "settings__gd_sync_info", fallback: "Google Drive sync reminder")
/// General
internal static let general = T.tr("Localizable", "settings__general", fallback: "General")
/// Tokens will be revealed on tap
internal static let hideTokensDescription = T.tr("Localizable", "settings__hide_tokens_description", fallback: "Tokens will be revealed on tap")
/// Tokens will be revealed on tap.
internal static let hideTokensDescription = T.tr("Localizable", "settings__hide_tokens_description", fallback: "Tokens will be revealed on tap.")
/// Hide tokens
internal static let hideTokensTitle = T.tr("Localizable", "settings__hide_tokens_title", fallback: "Hide tokens")
/// Select the maximum number of unsuccessful attempts to enter the passcode before locking the application (lockout time can be changed below).
@ -1313,6 +1319,8 @@ internal enum T {
internal static let enterServiceName = T.tr("Localizable", "tokens__enter_service_name", fallback: "Enter Service Name")
/// Add manually
internal static let fabAddmanually = T.tr("Localizable", "tokens__fab_addmanually", fallback: "Add manually")
/// Favorite Services
internal static let favoriteServices = T.tr("Localizable", "tokens__favorite_services", fallback: "Favorite Services")
/// Service added successfully. We strongly recommend that you
internal static let galleryAdviceContentFirst = T.tr("Localizable", "tokens__gallery_advice_content_first", fallback: "Service added successfully. We strongly recommend that you ")
///
@ -1338,6 +1346,8 @@ internal enum T {
internal static let groupName = T.tr("Localizable", "tokens__group_name", fallback: "Group name:")
/// HOTP
internal static let hotp = T.tr("Localizable", "tokens__hotp", fallback: "HOTP")
/// HOTP services aren't supported yet
internal static let hotpNotSupported = T.tr("Localizable", "tokens__hotp_not_supported", fallback: "HOTP services aren't supported yet")
/// Yes, I want to delete this service
internal static let iWantToDeleteThisToken = T.tr("Localizable", "tokens__i_want_to_delete_this_token", fallback: "Yes, I want to delete this service")
/// Incorrect Secret key (only numbers 2 to 7, letters), max. 512 chars long
@ -1589,6 +1599,14 @@ internal enum T {
/// Use the Add Service button to add a new service
internal static let useAddServiceButtonTitle = T.tr("Localizable", "voiceover__use_add_service_button_title", fallback: "Use the Add Service button to add a new service")
}
internal enum Watch {
/// 2FAS watchOS app is a companion app for the 2FAS iOS application. It will present services backed up using iCloud sync.
///
/// For quick access, add them to Favorite Services.
///
/// Please remember to donate so we can further improve the 2FAS platform!
internal static let intro = T.tr("Localizable", "watch__intro", fallback: "2FAS watchOS app is a companion app for the 2FAS iOS application. It will present services backed up using iCloud sync.\n\nFor quick access, add them to Favorite Services.\n\nPlease remember to donate so we can further improve the 2FAS platform!")
}
internal enum Widget {
/// My secured account
internal static let mySecuredAccount = T.tr("Localizable", "widget__my_secured_account", fallback: "My secured account")

View File

@ -38,7 +38,7 @@ extension CategoryData {
if let section {
return section.title
}
return "Services" // TODO: Add translation
return T.Commons.service
}()
return Category(id: id, name: name, services: services.toServices())
}

View File

@ -112,7 +112,7 @@ final class MainRepositoryImpl: MainRepository {
let storage = Storage(readOnly: false) { Log($0, module: .storage) }
let serviceMigration = ServiceMigrationController(storageRepository: storage.storageRepository)
serviceMigration.serviceNameTranslation = "Service"// TODO: Add translation T.Commons.service
serviceMigration.serviceNameTranslation = T.Commons.service
SyncInstanceWatch.initialize(commonSectionHandler: storage.section, commonServiceHandler: storage.service) {
Log("Sync: \($0)")

View File

@ -0,0 +1,25 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2024 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
import Foundation
enum WatchConsts {
static let minRowHeight: CGFloat = 60
static let listSectionRowSpacing: CGFloat = 4
}

View File

@ -24,20 +24,10 @@ struct IntroductionView: View {
var body: some View {
ScrollView {
VStack(alignment: .center, spacing: 4) {
HStack(spacing: 0) {
Spacer()
Image("AboutLogo")
.scaleEffect(0.5)
Text("2FAS")
.font(.title)
.padding(4)
.foregroundStyle(.primary)
Spacer()
}
LogoView()
Spacer()
Text("Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.")
Text(T.Watch.intro)
.font(.body)
.padding(4)
.foregroundStyle(.primary)
@ -45,9 +35,13 @@ struct IntroductionView: View {
Button(action: {
close()
}, label: {
Text("Continue")
Text(T.Commons.continue)
})
}
}
}
}
#Preview {
IntroductionView(close: {})
}

View File

@ -30,10 +30,10 @@ struct MainView: View {
if !presenter.favoriteList.isEmpty {
Section(header:
HStack(alignment: .center) {
Image(systemName: "star.fill")
Text("Favorite Services")
}
) {
Image(systemName: "star.fill")
Text(T.Tokens.favoriteServices)
}
) {
ForEach(presenter.favoriteList, id: \.self) { service in
NavigationLink(destination: ServiceView(
presenter: ServicePresenter(
@ -45,6 +45,7 @@ struct MainView: View {
}
.listRowBackground(Color.clear)
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.listSectionSpacing(WatchConsts.listSectionRowSpacing)
}
}
}
@ -56,7 +57,7 @@ struct MainView: View {
)) {
HStack(alignment: .center) {
Image(systemName: "folder")
Text("All Services")
Text(T.Commons.tokens)
.font(.callout)
.padding(4)
.foregroundStyle(.primary)
@ -82,8 +83,8 @@ struct MainView: View {
}
.containerBackground(.red.gradient, for: .navigation)
.listStyle(.carousel)
.environment(\.defaultMinListRowHeight, 40)
.navigationTitle("2FAS")
.environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
.navigationTitle(T.Commons._2fasToolbar)
.navigationBarTitleDisplayMode(.automatic)
.listItemTint(.clear)
}

View File

@ -143,14 +143,10 @@ private extension PINKeyboardPresenter {
private extension PINKeyboardVariant {
var navigationTitle: String {
switch self {
case .PINValidation:
"Enter PIN"
case .PINValidationWithClose:
"Enter PIN"
case .enterNewPIN:
"Enter new PIN"
case .verifyPIN:
"Repeat PIN"
case .PINValidation: T.Security.enterPin
case .PINValidationWithClose: T.Security.enterPin
case .enterNewPIN: T.Security.enterNewPinShort
case .verifyPIN: T.Security.repeatNewPinShort
}
}

View File

@ -94,7 +94,7 @@ struct PINKeyboardView: View {
Button {
presenter.onCloseAction()
} label: {
Label("Close", systemImage: "xmark")
Label(T.Commons.close, systemImage: "xmark")
}
}
}

View File

@ -99,7 +99,7 @@ struct ServiceView: View {
@ViewBuilder
private func unsupportedHOTP() -> some View {
Text("HOTP services aren't supported yet")
Text(T.Tokens.hotpNotSupported)
}
@ViewBuilder

View File

@ -53,6 +53,7 @@ struct ServiceCellView: View {
.padding(.vertical, 4)
}
.padding(.trailing, 4)
.frame(maxWidth: .infinity, alignment: .leading)
.background(
Material.ultraThinMaterial,
in: UnevenRoundedRectangle(
@ -66,7 +67,6 @@ struct ServiceCellView: View {
style: .continuous
)
)
.frame(maxWidth: .infinity, alignment: .leading)
.listItemTint(.clear)
}
}
@ -87,7 +87,7 @@ struct ServiceCellView: View {
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
}
.containerBackground(.red.gradient, for: .navigation)
.environment(\.defaultMinListRowHeight, 40)
.environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
.listRowBackground(Color.clear)
}
}

View File

@ -28,7 +28,7 @@ struct ServiceListView: View {
VStack(alignment: .center, spacing: 8) {
Image(systemName: "folder")
.font(.system(size: 40))
Text("No services")
Text(T.Tokens.tokensListIsEmpty)
}
} else {
NavigationStack {
@ -47,6 +47,7 @@ struct ServiceListView: View {
}
.listRowBackground(Color.clear)
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.listSectionSpacing(WatchConsts.listSectionRowSpacing)
}
}
}
@ -59,8 +60,8 @@ struct ServiceListView: View {
}
.containerBackground(.red.gradient, for: .navigation)
.listStyle(.carousel)
.environment(\.defaultMinListRowHeight, 40)
.navigationTitle("Services")
.environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
.navigationTitle(T.Commons.tokens)
.navigationBarTitleDisplayMode(.automatic)
.listItemTint(.clear)
}

View File

@ -19,42 +19,34 @@
import SwiftUI
// swiftlint:disable line_length
struct AboutView: View {
var body: some View {
ScrollView {
VStack(alignment: .center, spacing: 4) {
HStack(spacing: 0) {
Spacer()
Image("AboutLogo")
.scaleEffect(0.5)
Text("2FAS")
.font(.title)
.padding(4)
.foregroundStyle(.primary)
Spacer()
}
LogoView()
Spacer()
Text("Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.")
Text(T.Watch.intro)
.font(.body)
.padding(4)
.foregroundStyle(.primary)
Spacer()
Text("App version: \(appVersion)")
Text(T.Settings.version(appVersion))
.font(.body)
.padding(4)
.foregroundStyle(.primary)
}
}
.navigationTitle("About")
.navigationTitle(T.Settings.about)
}
private var appVersion: String {
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "-"
}
}
// swiftlint:enable line_length
#Preview {
AboutView()
}

View File

@ -0,0 +1,44 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2024 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
import SwiftUI
struct LogoView: View {
var body: some View {
VStack(alignment: .leading) {
HStack(alignment: .center, spacing: 4) {
Image("AboutLogo")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40)
.padding(.leading, 4)
.padding(.bottom, 4)
Text(T.Commons._2fasToolbar)
.font(.title)
.multilineTextAlignment(.leading)
.padding(.horizontal, 12)
.foregroundStyle(.primary)
Spacer()
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}

View File

@ -36,17 +36,17 @@ struct PINTypeView: View {
Button {
didSelect(.digits4)
} label: {
Text("4 digits")
Text(T.Settings.pin4Digits)
}
Button {
didSelect(.digits6)
} label: {
Text("6 digits")
Text(T.Settings.pin6Digits)
}
}
.containerBackground(.red.gradient, for: .navigation)
.navigationTitle("Select PIN length")
.navigationTitle(T.Settings.selectPinLength)
.navigationBarTitleDisplayMode(.automatic)
.navigationBarBackButtonHidden(showClose)
.toolbar(content: {
@ -55,7 +55,7 @@ struct PINTypeView: View {
Button {
} label: {
Label("Close", systemImage: "xmark")
Label(T.Commons.close, systemImage: "xmark")
}
}
}

View File

@ -33,21 +33,21 @@ struct SecurityView: View {
NavigationLink(value: SecurityPath.changePIN(.verify)) {
HStack {
Image(systemName: "lock.rotation")
Text("Change PIN")
Text(T.Security.changePin)
}
}
NavigationLink(value: SecurityPath.disablePIN(.verify)) {
HStack {
Image(systemName: "lock.open.fill")
Text("Disable PIN")
Text(T.Security.disablePin)
}
}
} else {
NavigationLink(value: SecurityPath.setPIN(.selectLength)) {
HStack {
Image(systemName: "lock.fill")
Text("Set PIN")
Text(T.Security.createPin)
}
}
}
@ -142,8 +142,8 @@ struct SecurityView: View {
}
.containerBackground(.red.gradient, for: .navigation)
.listStyle(.carousel)
.environment(\.defaultMinListRowHeight, 60)
.navigationTitle("Security")
.environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
.navigationTitle(T.Settings.security)
.navigationBarTitleDisplayMode(.automatic)
.listItemTint(.clear)
}

View File

@ -25,12 +25,12 @@ struct SuccessView: View {
VStack(spacing: 8) {
Image(systemName: "checkmark.shield.fill")
.font(.system(size: 40))
Text("Success")
Text(T.Commons.success)
Spacer()
Button {
close()
} label: {
Text("Close")
Text(T.Commons.close)
}
.controlSize(.large)
}

View File

@ -28,7 +28,7 @@ struct SettingsView: View {
NavigationLink(value: SettingsPath.security) {
HStack {
Image(systemName: "lock.fill")
Text("Security")
Text(T.Settings.security)
.font(.callout)
.padding(4)
.foregroundStyle(.primary)
@ -38,7 +38,7 @@ struct SettingsView: View {
NavigationLink(value: SettingsPath.about) {
HStack {
Image(systemName: "info.bubble.fill")
Text("About")
Text(T.Settings.about)
.font(.callout)
.padding(4)
.foregroundStyle(.primary)
@ -58,8 +58,8 @@ struct SettingsView: View {
}
.containerBackground(.red.gradient, for: .navigation)
.listStyle(.carousel)
.environment(\.defaultMinListRowHeight, 60)
.navigationTitle("Settings")
.environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
.navigationTitle(T.Settings.settings)
.navigationBarTitleDisplayMode(.automatic)
.listItemTint(.clear)
}