diff --git a/.maestro/release_tests/emailprotection.yaml b/.maestro/release_tests/emailprotection.yaml index 67b41ef000..e4cc61fba4 100644 --- a/.maestro/release_tests/emailprotection.yaml +++ b/.maestro/release_tests/emailprotection.yaml @@ -17,7 +17,7 @@ tags: - scroll - scroll - assertVisible: Email Protection -- tapOn: Email Protection, Block email trackers and hide your address +- tapOn: Email Protection - assertVisible: id: searchEntry - assertVisible: https://duckduckgo.com/email/ diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig index f16be59a1f..773b0e1646 100644 --- a/Configuration/Version.xcconfig +++ b/Configuration/Version.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 7.96.0 +MARKETING_VERSION = 7.97.0 diff --git a/Core/AppPrivacyConfigurationDataProvider.swift b/Core/AppPrivacyConfigurationDataProvider.swift index 3e07b81b83..4e4e1e6202 100644 --- a/Core/AppPrivacyConfigurationDataProvider.swift +++ b/Core/AppPrivacyConfigurationDataProvider.swift @@ -23,8 +23,8 @@ import BrowserServicesKit final public class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"39c652b21aa330463726faf240e03445\"" - public static let embeddedDataSHA = "b19c28e816008ace47a9e3e58f74eef6558b5cbdcd7d79d098d7d2e56d686075" + public static let embeddedDataETag = "\"71b1b5499f333348df4f9bc52b74185f\"" + public static let embeddedDataSHA = "a5b30cf79e5efc40fec6fb28491a7484822041d927a6e2d8c9c7ccd3bd236c61" } public var embeddedDataEtag: String { diff --git a/Core/AppTrackerDataSetProvider.swift b/Core/AppTrackerDataSetProvider.swift index 625fe0a39b..c41f8ed1b5 100644 --- a/Core/AppTrackerDataSetProvider.swift +++ b/Core/AppTrackerDataSetProvider.swift @@ -23,8 +23,8 @@ import BrowserServicesKit final public class AppTrackerDataSetProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"3b73923ebfd4702c33aea682db0bac11\"" - public static let embeddedDataSHA = "16e1e52530db19badfefc9a07d76620f9c608c12dc144f67020da8a9a4ddb0fa" + public static let embeddedDataETag = "\"3a50d09fd78a893f1a284051d1f777de\"" + public static let embeddedDataSHA = "2c1995807a61fd9fa311baab01633411282759732f098765f5380bda5e92b9e2" } public var embeddedDataEtag: String { diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 31259e85d8..12a0824b50 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -205,7 +205,8 @@ extension Pixel { case autofillLoginsSaveLoginModalDisplayed case autofillLoginsSaveLoginModalConfirmed case autofillLoginsSaveLoginModalDismissed - + case autofillLoginsSaveLoginModalExcludeSiteConfirmed + case autofillLoginsSavePasswordModalDisplayed case autofillLoginsSavePasswordModalConfirmed case autofillLoginsSavePasswordModalDismissed @@ -240,6 +241,9 @@ extension Pixel { case autofillLoginsSettingsEnabled case autofillLoginsSettingsDisabled case autofillLoginsSettingsAddNewLoginErrorAttemptedToCreateDuplicate + case autofillLoginsSettingsResetExcludedDisplayed + case autofillLoginsSettingsResetExcludedConfirmed + case autofillLoginsSettingsResetExcludedDismissed case autofillLoginsPasswordGenerationPromptDisplayed case autofillLoginsPasswordGenerationPromptConfirmed @@ -702,7 +706,8 @@ extension Pixel.Event { case .autofillLoginsSaveLoginModalDisplayed: return "m_autofill_logins_save_login_inline_displayed" case .autofillLoginsSaveLoginModalConfirmed: return "m_autofill_logins_save_login_inline_confirmed" case .autofillLoginsSaveLoginModalDismissed: return "m_autofill_logins_save_login_inline_dismissed" - + case .autofillLoginsSaveLoginModalExcludeSiteConfirmed: return "m_autofill_logins_save_login_exclude_site_confirmed" + case .autofillLoginsSavePasswordModalDisplayed: return "m_autofill_logins_save_password_inline_displayed" case .autofillLoginsSavePasswordModalConfirmed: return "m_autofill_logins_save_password_inline_confirmed" case .autofillLoginsSavePasswordModalDismissed: return "m_autofill_logins_save_password_inline_dismissed" @@ -744,6 +749,9 @@ extension Pixel.Event { case .autofillLoginsSettingsDisabled: return "m_autofill_logins_settings_disabled" case .autofillLoginsSettingsAddNewLoginErrorAttemptedToCreateDuplicate: return "m_autofill_logins_settings_add-new-login_error_attempted-to-create-duplicate" + case .autofillLoginsSettingsResetExcludedDisplayed: return "m_autofill_settings_reset_excluded_displayed" + case .autofillLoginsSettingsResetExcludedConfirmed: return "m_autofill_settings_reset_excluded_confirmed" + case .autofillLoginsSettingsResetExcludedDismissed: return "m_autofill_settings_reset_excluded_dismissed" case .autofillLoginsPasswordGenerationPromptDisplayed: return "m_autofill_logins_password_generation_prompt_displayed" case .autofillLoginsPasswordGenerationPromptConfirmed: return "m_autofill_logins_password_generation_prompt_confirmed" diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift index 78a4507ba0..47c17546f9 100644 --- a/Core/UserDefaultsPropertyWrapper.swift +++ b/Core/UserDefaultsPropertyWrapper.swift @@ -81,7 +81,7 @@ public struct UserDefaultsWrapper { case autofillCredentialsSavePromptShowAtLeastOnce = "com.duckduckgo.ios.autofillCredentialsSavePromptShowAtLeastOnce" case autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = "com.duckduckgo.ios.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary" - + case featureFlaggingDidVerifyInternalUser = "com.duckduckgo.app.featureFlaggingDidVerifyInternalUser" case voiceSearchEnabled = "com.duckduckgo.app.voiceSearchEnabled" diff --git a/Core/ios-config.json b/Core/ios-config.json index 530bbe5602..ce6aeae32a 100644 --- a/Core/ios-config.json +++ b/Core/ios-config.json @@ -1,6 +1,6 @@ { "readme": "https://github.com/duckduckgo/privacy-configuration", - "version": 1699039046694, + "version": 1699875322077, "features": { "adClickAttribution": { "readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection", @@ -82,6 +82,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -107,7 +110,7 @@ ] }, "state": "enabled", - "hash": "5a2395ef011fb7be4acb7885024e63fe" + "hash": "5bfae22c5e0cb13c0a25ce80531827ff" }, "androidBrowserConfig": { "exceptions": [], @@ -247,6 +250,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -255,7 +261,7 @@ ] }, "state": "enabled", - "hash": "03b154384cddc4cecfd685959d658256" + "hash": "4719cb6c793d13a9ac81c329f4d206c8" }, "autofill": { "exceptions": [ @@ -298,12 +304,15 @@ }, { "percent": 10 + }, + { + "percent": 100 } ] } } }, - "hash": "968968437514e582ebd4789a22207b91" + "hash": "3d95a9b3c8112148eda0ad09b1002b53" }, "clickToLoad": { "exceptions": [ @@ -915,6 +924,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -932,7 +944,7 @@ } }, "state": "disabled", - "hash": "f57113e4f2e7dd0fb93f5f73f9ef4fdb" + "hash": "36e8971fa9bb204b78a5929a14a108dd" }, "clickToPlay": { "exceptions": [ @@ -944,6 +956,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -956,7 +971,7 @@ } }, "state": "disabled", - "hash": "6724dd4acc868b402c6d23193bc6ba56" + "hash": "4390af06f967ef97a827aeab0ac0d1ca" }, "contentBlocking": { "state": "enabled", @@ -976,9 +991,6 @@ { "domain": "ads.google.com" }, - { - "domain": "sundancecatalog.com" - }, { "domain": "earth.google.com" }, @@ -987,9 +999,12 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], - "hash": "aa730da73ce0d03c67fcac68f9196b97" + "hash": "71ad0f38f9ce2bbacae5ff7db05511ec" }, "cookie": { "settings": { @@ -1036,10 +1051,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "01ed94213fc52b4ef93d988070491c49" + "hash": "e41dbd0af3841636937030d91bc305b1" }, "customUserAgent": { "settings": { @@ -1218,12 +1236,18 @@ { "domain": "marvel.com" }, + { + "domain": "sundancecatalog.com" + }, { "domain": "cvs.com" }, { "domain": "facebook.com" }, + { + "domain": "finewineandgoodspirits.com" + }, { "domain": "formula1.com" }, @@ -1261,12 +1285,15 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ] }, "exceptions": [], "state": "enabled", - "hash": "232df10f29daf038ce889d28a9064a6b" + "hash": "b101ded240bc51fce0ece83191b2da62" }, "duckPlayer": { "exceptions": [], @@ -1339,60 +1366,6 @@ { "domain": "duckduckgo.com" }, - { - "domain": "bild.de" - }, - { - "domain": "derstandard.at" - }, - { - "domain": "foxnews.com" - }, - { - "domain": "kbb.com" - }, - { - "domain": "wiwo.de" - }, - { - "domain": "metro.co.uk" - }, - { - "domain": "blick.ch" - }, - { - "domain": "thechive.com" - }, - { - "domain": "bizjournals.com" - }, - { - "domain": "slate.com" - }, - { - "domain": "dailycaller.com" - }, - { - "domain": "dailymail.co.uk" - }, - { - "domain": "eltiempo.com" - }, - { - "domain": "dailyherald.com" - }, - { - "domain": "publico.es" - }, - { - "domain": "rawstory.com" - }, - { - "domain": "allgemeine-zeitung.de" - }, - { - "domain": "thehindu.com" - }, { "domain": "earth.google.com" }, @@ -1401,6 +1374,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -1610,6 +1586,10 @@ "selector": ".ad_container", "type": "closest-empty" }, + { + "selector": ".ad-container--leaderboard", + "type": "hide-empty" + }, { "selector": ".ads_container", "type": "hide-empty" @@ -1813,10 +1793,6 @@ { "selector": "#ez-content-blocker-container", "type": "hide" - }, - { - "selector": "#notify-adblock", - "type": "hide" } ], "styleTagExceptions": [ @@ -1863,6 +1839,7 @@ "advertisementhide ad", "advertisement - scroll to continue", "advertisement · scroll to continue", + "advertisement - story continues below", "advertising", "advertising\nskip ad", "advertising\nskip ad\nskip ad\nskip ad", @@ -1911,6 +1888,35 @@ } ] }, + { + "domain": "allgemeine-zeitung.de", + "rules": [ + { + "type": "disable-default" + }, + { + "selector": ".adSlot", + "type": "hide-empty" + }, + { + "selector": ".adBorder", + "type": "hide-empty" + }, + { + "selector": ".nativeAd", + "type": "closest-empty" + } + ] + }, + { + "domain": "androidpolice.com", + "rules": [ + { + "selector": "[class*='ad-zone']", + "type": "hide" + } + ] + }, { "domain": "apnews.com", "rules": [ @@ -1951,6 +1957,31 @@ } ] }, + { + "domain": "bild.de", + "rules": [ + { + "type": "disable-default" + }, + { + "selector": "[id^='mrec']", + "type": "hide-empty" + }, + { + "selector": "#superbanner", + "type": "hide-empty" + } + ] + }, + { + "domain": "bizjournals.com", + "rules": [ + { + "selector": ".adwrap", + "type": "closest-empty" + } + ] + }, { "domain": "bleacherreport.com", "rules": [ @@ -1969,6 +2000,15 @@ } ] }, + { + "domain": "blick.ch", + "rules": [ + { + "selector": "[id*='appnexus-placement-']", + "type": "hide-empty" + } + ] + }, { "domain": "bloomberg.com", "rules": [ @@ -2070,6 +2110,31 @@ } ] }, + { + "domain": "dailyherald.com", + "rules": [ + { + "selector": ".instoryAdBlock", + "type": "hide" + } + ] + }, + { + "domain": "dailymail.co.uk", + "rules": [ + { + "type": "disable-default" + }, + { + "selector": "[class*='dmg-ads']", + "type": "hide-empty" + }, + { + "selector": ".mol-ads-label-container", + "type": "closest-empty" + } + ] + }, { "domain": "dallasnews.com", "rules": [ @@ -2235,6 +2300,27 @@ } ] }, + { + "domain": "foodnetwork.co.uk", + "rules": [ + { + "selector": ".bg-bodyBg", + "type": "hide-empty" + }, + { + "selector": ".module--ad-module-primary", + "type": "hide-empty" + }, + { + "selector": "#mtf-1", + "type": "closest-empty" + }, + { + "selector": "#btf-1", + "type": "closest-empty" + } + ] + }, { "domain": "football365.com", "rules": [ @@ -2481,6 +2567,15 @@ } ] }, + { + "domain": "insider.com", + "rules": [ + { + "selector": ".in-post-sticky", + "type": "hide-empty" + } + ] + }, { "domain": "investing.com", "rules": [ @@ -2581,6 +2676,18 @@ } ] }, + { + "domain": "metro.co.uk", + "rules": [ + { + "type": "disable-default" + }, + { + "selector": ".ad-slot-container", + "type": "hide-empty" + } + ] + }, { "domain": "mirror.co.uk", "rules": [ @@ -2847,6 +2954,19 @@ } ] }, + { + "domain": "publico.es", + "rules": [ + { + "selector": ".pb-ads", + "type": "hide-empty" + }, + { + "selector": "#sc_intxt_container", + "type": "hide" + } + ] + }, { "domain": "qz.com", "rules": [ @@ -2856,6 +2976,35 @@ } ] }, + { + "domain": "rawstory.com", + "rules": [ + { + "selector": ".container_proper-ad-unit", + "type": "hide" + }, + { + "selector": ".controlled_via_ad_manager", + "type": "hide" + }, + { + "selector": ".mgid_3x2", + "type": "hide-empty" + }, + { + "selector": ".proper-ad-unit", + "type": "hide" + }, + { + "selector": "[id^='rc-widget-']", + "type": "hide-empty" + }, + { + "selector": "#story-top-ad", + "type": "hide" + } + ] + }, { "domain": "reddit.com", "rules": [ @@ -2983,6 +3132,10 @@ { "selector": ".slate-ad", "type": "hide-empty" + }, + { + "selector": ".top-ad", + "type": "hide" } ] }, @@ -3021,6 +3174,15 @@ } ] }, + { + "domain": "sportbible.com", + "rules": [ + { + "selector": "[class*='Advert']", + "type": "hide" + } + ] + }, { "domain": "target.com", "rules": [ @@ -3039,6 +3201,15 @@ } ] }, + { + "domain": "thegatewaypundit.com", + "rules": [ + { + "selector": ".code-block", + "type": "hide" + } + ] + }, { "domain": "thehour.com", "rules": [ @@ -3048,6 +3219,15 @@ } ] }, + { + "domain": "thehindu.com", + "rules": [ + { + "selector": "#articledivrec", + "type": "hide-empty" + } + ] + }, { "domain": "thetimes.co.uk", "rules": [ @@ -3183,6 +3363,10 @@ { "selector": "[class^='Ad__Container-']", "type": "hide" + }, + { + "selector": "#ac-lre-player", + "type": "hide-empty" } ] }, @@ -3212,6 +3396,15 @@ } ] }, + { + "domain": "westernjournal.com", + "rules": [ + { + "selector": ".sponsor", + "type": "hide-empty" + } + ] + }, { "domain": "washingtonpost.com", "rules": [ @@ -3247,6 +3440,14 @@ } ] }, + { + "domain": "wiwo.de", + "rules": [ + { + "type": "disable-default" + } + ] + }, { "domain": "wsj.com", "rules": [ @@ -3409,7 +3610,7 @@ ] }, "state": "enabled", - "hash": "903602d78d217518a48be612b2a08f3e" + "hash": "15184cba961aadf588965f6caf070306" }, "exceptionHandler": { "exceptions": [ @@ -3421,10 +3622,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "acf631a1f283d1ea71e5d3116f17a110" + "hash": "5e792dd491428702bc0104240fbce0ce" }, "fingerprintingAudio": { "state": "disabled", @@ -3440,9 +3644,12 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], - "hash": "aec17726775580a32c51d6ad0559c13f" + "hash": "f25a8f2709e865c2bd743828c7ee2f77" }, "fingerprintingBattery": { "exceptions": [ @@ -3457,10 +3664,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", - "hash": "f74e2255710593a76b5a80571da555a2" + "hash": "440f8d663d59430c93d66208655d9238" }, "fingerprintingCanvas": { "settings": { @@ -3559,10 +3769,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "55ba309065f40d78a5f0308411d6df97" + "hash": "ea4c565bae27996f0d651300d757594c" }, "fingerprintingHardware": { "settings": { @@ -3610,10 +3823,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", - "hash": "81bda64a0a893eebb721772fbd64126a" + "hash": "911cbc583f376d416ac75c57ecc577f1" }, "fingerprintingScreenSize": { "settings": { @@ -3661,10 +3877,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", - "hash": "4fa7c8746240605af7885a953dcbdfe9" + "hash": "0fb22f84b750e0d29bad55bd95d9ce2b" }, "fingerprintingTemporaryStorage": { "exceptions": [ @@ -3682,10 +3901,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", - "hash": "5e81950bd7e1cbf6489ed4fb7d5b57fb" + "hash": "568a23faa984c8e7eda002294ad8f82f" }, "googleRejected": { "exceptions": [ @@ -3697,10 +3919,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "acf631a1f283d1ea71e5d3116f17a110" + "hash": "5e792dd491428702bc0104240fbce0ce" }, "gpc": { "state": "enabled", @@ -3737,6 +3962,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -3748,7 +3976,7 @@ "privacy-test-pages.site" ] }, - "hash": "0a23d1c1dc75bb6664af7d81c6f80e77" + "hash": "083267b595694bd75cda73218f8811c2" }, "harmfulApis": { "settings": { @@ -3858,10 +4086,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "cd14e5f0c64cbe269b73cd40b8c89c42" + "hash": "44d3e707cba3ee0a3578f52dc2ce2aa4" }, "https": { "state": "enabled", @@ -3883,9 +4114,12 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], - "hash": "b055b164b3c3a9f20ad93e041be1810e" + "hash": "f772808ed34cc9ea8cbcbb7cdaf74429" }, "incontextSignup": { "exceptions": [], @@ -3923,6 +4157,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { @@ -3933,7 +4170,7 @@ ] }, "state": "enabled", - "hash": "9cbed3731aad3fb286c8245ba8ff87dd" + "hash": "698de7b963d7d7942c5c5d1e986bb1b1" }, "networkProtection": { "state": "disabled", @@ -3966,10 +4203,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "e2fe271add53f2e5dafb31b235d1fa54" + "hash": "841fa92b9728c9754f050662678f82c7" }, "privacyDashboard": { "exceptions": [], @@ -4012,10 +4252,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "6a035dc634a0eaff88ce00de3905a1bb" + "hash": "0d3df0f7c24ebde89d2dced4e2d34322" }, "requestFilterer": { "state": "disabled", @@ -4028,12 +4271,15 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": { "windowInMs": 0 }, - "hash": "591960d057333a55489a557f5cd7d121" + "hash": "0fff8017d8ea4b5609b8f5c110be1401" }, "runtimeChecks": { "state": "disabled", @@ -4046,10 +4292,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "settings": {}, - "hash": "158fe8be52fa1c0fabf08d8a12fd55b0" + "hash": "800a19533c728bbec7e31e466f898268" }, "serviceworkerInitiatedRequests": { "exceptions": [ @@ -4061,10 +4310,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "acf631a1f283d1ea71e5d3116f17a110" + "hash": "5e792dd491428702bc0104240fbce0ce" }, "trackerAllowlist": { "state": "enabled", @@ -4191,6 +4443,16 @@ } ] }, + "adserver.adtech.advertising.com": { + "rules": [ + { + "rule": "adserver.adtech.advertising.com/pubapi/3.0/1/54669.7/0/0/ADTECH;v=2;cmd=bid;cors=yes", + "domains": [ + "collider.com" + ] + } + ] + }, "adswizz.com": { "rules": [ { @@ -4198,6 +4460,12 @@ "domains": [ "tunein.com" ] + }, + { + "rule": "adswizz.com/adswizz/js/SynchroClient2.js", + "domains": [ + "tunein.com" + ] } ] }, @@ -4773,7 +5041,6 @@ "rule": "pubads.g.doubleclick.net/gampad/ads", "domains": [ "crunchyroll.com", - "fifa.com", "nhl.com", "rocketnews24.com", "viki.com" @@ -5001,6 +5268,7 @@ { "rule": "app.five9.com", "domains": [ + "gmsdnv.com", "machiassavings.bank" ] } @@ -5205,6 +5473,12 @@ "" ] }, + { + "rule": "www.google.com/url", + "domains": [ + "" + ] + }, { "rule": "www.google.com/maps/", "domains": [ @@ -5213,6 +5487,16 @@ } ] }, + "googleapis.com": { + "rules": [ + { + "rule": "imasdk.googleapis.com/js/sdkloader/ima3.js", + "domains": [ + "nfl.com" + ] + } + ] + }, "googleoptimize.com": { "rules": [ { @@ -5235,6 +5519,14 @@ "zefoy.com" ] }, + { + "rule": "pagead2.googlesyndication.com/pagead/show_ads.js", + "domains": [ + "luckylandslots.com", + "rocketnews24.com", + "zefoy.com" + ] + }, { "rule": "tpc.googlesyndication.com/pagead/js/loader21.html", "domains": [ @@ -5383,6 +5675,7 @@ "thecw38.com", "thecw46.com", "thecwtc.com", + "thenationaldesk.com", "turnto10.com", "univisionseattle.com", "upnorthlive.com", @@ -5483,6 +5776,12 @@ "domains": [ "pippintitle.com" ] + }, + { + "rule": "no-cache.hubspot.com/cta/default/", + "domains": [ + "" + ] } ] }, @@ -5588,6 +5887,16 @@ } ] }, + "jsdelivr.net": { + "rules": [ + { + "rule": "cdn.jsdelivr.net/npm/@fingerprintjs/fingerprintjs@3/dist/fp.js", + "domains": [ + "sbermarket.ru" + ] + } + ] + }, "kampyle.com": { "rules": [ { @@ -5638,6 +5947,7 @@ { "rule": "static.klaviyo.com/onsite/js/klaviyo.js", "domains": [ + "essentialpraxis.com", "kidsguide.com", "urbanebikes.com" ] @@ -6774,9 +7084,12 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], - "hash": "2ea09955d838b29daa5416586bb2f25a" + "hash": "65670bfba426ac832fe6bb2082c432c8" }, "trackingCookies1p": { "settings": { @@ -6794,10 +7107,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "057704f003231b68cde1faca12adec27" + "hash": "4dddf681372a2aea9788090b13db6e6f" }, "trackingCookies3p": { "settings": { @@ -6812,10 +7128,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "e2fe271add53f2e5dafb31b235d1fa54" + "hash": "841fa92b9728c9754f050662678f82c7" }, "trackingParameters": { "exceptions": [ @@ -6828,6 +7147,9 @@ { "domain": "marvel.com" }, + { + "domain": "sundancecatalog.com" + }, { "domain": "theverge.com" } @@ -6862,7 +7184,7 @@ ] }, "state": "enabled", - "hash": "2ca96907627936c8912983c971c5f1c9" + "hash": "f2437495da4898e8e048643ab38ef372" }, "userAgentRotation": { "settings": { @@ -6877,10 +7199,13 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "disabled", - "hash": "3893596da5fb3653a6adc10538f08a2e" + "hash": "f65d10dfdf6739feab99a08d42734747" }, "voiceSearch": { "exceptions": [], @@ -6897,6 +7222,9 @@ }, { "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" } ], "state": "enabled", @@ -6929,7 +7257,7 @@ } ] }, - "hash": "3702e5c5e88b46c494d8e4ef4e17a8da" + "hash": "4e94cff79e689ff320de22a57e242bdd" }, "windowsPermissionUsage": { "exceptions": [], diff --git a/Core/trackerData.json b/Core/trackerData.json index 18ddb15be4..84975e1a36 100644 --- a/Core/trackerData.json +++ b/Core/trackerData.json @@ -1,7 +1,7 @@ { "_builtWith": { - "tracker-radar": "29f80529aa526f0a0f8daadb1c8717d6dccdbb1a45f98477de48e8a8d213d386-4013b4e91930c643394cb31c6c745356f133b04f", - "tracker-surrogates": "d61691a2fdf9f4dc062a8d248fd1e78c20b5b892" + "tracker-radar": "ae2fbc01abd26abf1903208a5cabbaed6a96ab2aa13779d2125a98fc45fee2cd-4013b4e91930c643394cb31c6c745356f133b04f", + "tracker-surrogates": "abd6067fac9693cc5a43d48931b111ca08cb0d5a" }, "readme": "https://github.com/duckduckgo/tracker-blocklists", "trackers": { @@ -136,45 +136,14 @@ "Ad Motivated Tracking", "Advertising" ], - "default": "ignore", + "default": "block", "rules": [ { - "rule": "2mdn\\.net/dot\\.gif" - }, - { - "rule": "2mdn\\.net/10533936/1679336805544/" - }, - { - "rule": "2mdn\\.net/8762481/1679421215390" - }, - { - "rule": "2mdn\\.net/879366/" - }, - { - "rule": "2mdn\\.net/ads/" - }, - { - "rule": "2mdn\\.net/creatives/assets/" - }, - { - "rule": "2mdn\\.net/dfp/" - }, - { - "rule": "2mdn\\.net/dynamic/2/" - }, - { - "rule": "2mdn\\.net/sadbundle/" - }, - { - "rule": "2mdn\\.net/simgad/[0-9]+" - }, - { - "rule": "2mdn\\.net/videoplayback" + "rule": "2mdn\\.net/instream/html5/ima3\\.js", + "surrogate": "google-ima.js" }, { "rule": "2mdn\\.net/instream/video/client\\.js", - "fingerprinting": 1, - "cookies": 0, "exceptions": { "domains": [ "dailywire.com", @@ -822,7 +791,17 @@ "Social - Share", "Third-Party Analytics Marketing" ], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "static\\.addtoany\\.com/menu/page\\.js", + "exceptions": { + "domains": [ + "tiny.cc" + ] + } + } + ] }, "adelixir.com": { "domain": "adelixir.com", @@ -2519,9 +2498,16 @@ "foxbusiness.com", "foxnews.com", "fyi.tv", + "gamingbible.co.uk", + "gamingbible.com", "history.com", + "ladbible.com", "mylifetime.com", - "sueddeutsche.de" + "sportbible.com", + "sueddeutsche.de", + "tyla.com", + "unilad.co.uk", + "unilad.com" ] } } @@ -4474,14 +4460,7 @@ "fingerprinting": 2, "cookies": 0.000824, "categories": [], - "default": "ignore", - "rules": [ - { - "rule": "boldchat\\.com/aid/.*/vms\\.js", - "fingerprinting": 2, - "cookies": 0.000201 - } - ] + "default": "ignore" }, "booking.com": { "domain": "booking.com", @@ -7761,9 +7740,14 @@ "default": "ignore", "rules": [ { - "rule": "dbukjj6eu5tsf\\.cloudfront\\.net\\/assets\\.sidearmsports\\.com\\/common\\/js\\/20170825\\/video\\.js", + "rule": "dbukjj6eu5tsf\\.cloudfront\\.net/assets\\.sidearmsports\\.com/common/js/20170825/video\\.js", "fingerprinting": 3, - "cookies": 0 + "cookies": 0, + "exceptions": { + "domains": [ + "utsports.com" + ] + } } ] }, @@ -8257,6 +8241,14 @@ "sbs.com.au" ] } + }, + { + "rule": "g\\.doubleclick\\.net/pagead/ads", + "exceptions": { + "domains": [ + "fukuishimbun.co.jp" + ] + } } ] }, @@ -9825,11 +9817,6 @@ ], "default": "ignore", "rules": [ - { - "rule": "facebook\\.net/.*/all\\.js", - "fingerprinting": 1, - "cookies": 0.0000408 - }, { "rule": "facebook\\.net/.*/fbevents\\.js", "fingerprinting": 1, @@ -10814,14 +10801,7 @@ "fingerprinting": 1, "cookies": 0.0000408, "categories": [], - "default": "ignore", - "rules": [ - { - "rule": "geoip-js\\.com\\/js\\/apis\\/geoip2\\/v2\\.1\\/geoip2\\.js", - "fingerprinting": 1, - "cookies": 0.0000204 - } - ] + "default": "ignore" }, "getblue.io": { "domain": "getblue.io", @@ -11502,7 +11482,33 @@ "Ad Motivated Tracking", "Advertising" ], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "googleadservices\\.com/gampad/cookie\\.js" + }, + { + "rule": "googleadservices\\.com/pagead/conversion\\.js" + }, + { + "rule": "googleadservices\\.com/gampad/google_service\\.js" + }, + { + "rule": "googleadservices\\.com/gampad/google_ads\\.js" + }, + { + "rule": "googleadservices\\.com/favicon\\.ico" + }, + { + "rule": "googleadservices\\.com/ga/phone" + }, + { + "rule": "googleadservices\\.com/ccm/conversion/845940546/" + }, + { + "rule": "googleadservices\\.com/pagead/conversion/" + } + ] }, "googlehosted.com": { "domain": "googlehosted.com", @@ -11619,9 +11625,28 @@ "rule": "googlesyndication\\.com/adsbygoogle\\.js", "surrogate": "adsbygoogle.js" }, + { + "rule": "pagead2\\.googlesyndication\\.com/pagead/js/adsbygoogle\\.js", + "surrogate": "adsbygoogle.js", + "exceptions": { + "domains": [ + "dronedj.com", + "fukuishimbun.co.jp", + "spaceexplored.com" + ] + } + }, { "rule": "googlesyndication\\.com/pagead/js/adsbygoogle\\.js", "surrogate": "adsbygoogle.js" + }, + { + "rule": "pagead2\\.googlesyndication\\.com/pagead/managed/js/adsense", + "exceptions": { + "domains": [ + "fukuishimbun.co.jp" + ] + } } ] }, @@ -11986,11 +12011,6 @@ "rule": "groovehq\\.com\\/api\\/shim\\/27299f7da6676b065f217a683a418325", "fingerprinting": 2, "cookies": 0 - }, - { - "rule": "groovehq\\.com\\/_next\\/static\\/chunks\\/9fd8c5e27f99fce506e2e5d3b010ddba7982b0f2\\.7fb5a86b2706698b7a7e\\.js", - "fingerprinting": 2, - "cookies": 0 } ] }, @@ -12908,14 +12928,6 @@ ] } }, - { - "rule": "hubspot\\.com/api/livechat-public/v1/", - "exceptions": { - "types": [ - "xmlhttprequest" - ] - } - }, { "rule": "hubspot\\.com/hubfs/", "exceptions": { @@ -13255,7 +13267,13 @@ "Content Delivery", "Embedded Content" ], - "default": "ignore" + "default": "ignore", + "rules": [ + { + "rule": "imasdk\\.googleapis\\.com/js/sdkloader/ima3\\.js", + "surrogate": "google-ima.js" + } + ] }, "imedia.cz": { "domain": "imedia.cz", @@ -14240,18 +14258,6 @@ } ] }, - "ipify.org": { - "domain": "ipify.org", - "owner": { - "name": "ipify.org", - "displayName": "ipify.org" - }, - "prevalence": 0.00555, - "fingerprinting": 1, - "cookies": 0.000116, - "categories": [], - "default": "block" - }, "iplsc.com": { "domain": "iplsc.com", "owner": { @@ -15484,25 +15490,7 @@ "Embedded Content", "Third-Party Analytics Marketing" ], - "default": "ignore", - "rules": [ - { - "rule": "lightboxcdn\\.com/vendor/.*/user\\.js", - "fingerprinting": 3, - "cookies": 0.0000749 - }, - { - "rule": "lightboxcdn\\.com\\/w37htfhcq2\\/vendor\\/721dac7b-a982-4a33-afe7-ffe31144fbdd\\/user\\.js", - "fingerprinting": 3, - "cookies": 0.0000136 - }, - { - "rule": "lightboxcdn\\.com\\/vendor\\/b90a8cf1-793b-4cc5-b282-f863e44f81fa\\/lightbox_inline\\.js", - "fingerprinting": 0, - "cookies": 0, - "comment": "pixel" - } - ] + "default": "ignore" }, "lijit.com": { "domain": "lijit.com", @@ -15653,7 +15641,60 @@ "Ad Motivated Tracking", "Advertising" ], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "linksynergy\\.com/rcs" + }, + { + "rule": "linksynergy\\.com/jsp" + }, + { + "rule": "linksynergy\\.com/cs" + }, + { + "rule": "linksynergy\\.com/act\\.php" + }, + { + "rule": "linksynergy\\.com/t" + }, + { + "rule": "linksynergy\\.com/consent/v1/p" + }, + { + "rule": "linksynergy\\.com/imp" + }, + { + "rule": "linksynergy\\.com/consent/v3/p" + }, + { + "rule": "linksynergy\\.com/phoenix/phoenix-2\\.26\\.min\\.js" + }, + { + "rule": "linksynergy\\.com/privacy/ad_choices\\.png" + }, + { + "rule": "linksynergy\\.com/fs-bin/show" + }, + { + "rule": "linksynergy\\.com/cc" + }, + { + "rule": "linksynergy\\.com/js/" + }, + { + "rule": "linksynergy\\.com/wakeup/" + }, + { + "rule": "linksynergy\\.com/advertisers/owllab9118/" + }, + { + "rule": "linksynergy\\.com/pix/[0-9]+" + }, + { + "rule": "linksynergy\\.com/[0-9]+\\.ct\\.js" + } + ] }, "list-manage.com": { "domain": "list-manage.com", @@ -16454,7 +16495,8 @@ "Embedded Content", "Social - Share" ], - "default": "ignore" + "default": "ignore", + "rules": [] }, "mailchimp.com": { "domain": "mailchimp.com", @@ -18041,7 +18083,20 @@ "fingerprinting": 0, "cookies": 0.00373, "categories": [], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "hello\\.myfonts\\.net/count/", + "exceptions": { + "domains": [ + "condor.com" + ], + "types": [ + "stylesheet" + ] + } + } + ] }, "myregistry.com": { "domain": "myregistry.com", @@ -18105,7 +18160,30 @@ "fingerprinting": 2, "cookies": 0.00189, "categories": [], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "nakanohito\\.jp/b3/bi\\.js" + }, + { + "rule": "nakanohito\\.jp/b3/" + }, + { + "rule": "nakanohito\\.jp/uhj2/uh\\.js" + }, + { + "rule": "nakanohito\\.jp/cm/inner\\.css" + }, + { + "rule": "nakanohito\\.jp/ua/uwa\\.js" + }, + { + "rule": "nakanohito\\.jp/ua/" + }, + { + "rule": "nakanohito\\.jp/chatbot_pc\\.css" + } + ] }, "nanorep.co": { "domain": "nanorep.co", @@ -18359,6 +18437,15 @@ ], "default": "block", "rules": [ + { + "rule": "js-agent\\.newrelic\\.com", + "exceptions": { + "domains": [ + "chaturbate.com", + "johnlewis.com" + ] + } + }, { "rule": "newrelic\\.com", "exceptions": { @@ -18712,11 +18799,7 @@ "rules": [ { "rule": "npttech\\.com/advertising\\.js", - "exceptions": { - "types": [ - "script" - ] - } + "surrogate": "noop.js" } ] }, @@ -18734,7 +18817,17 @@ "categories": [ "Analytics" ], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "nr-data\\.net", + "exceptions": { + "domains": [ + "chaturbate.com" + ] + } + } + ] }, "nrich.ai": { "domain": "nrich.ai", @@ -20377,7 +20470,39 @@ "Audience Measurement", "Third-Party Analytics Marketing" ], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "parsely\\.com/plogger/" + }, + { + "rule": "parsely\\.com/videoplugins/brightcove/videojs-parsely-loader-v1-latest\\.min\\.js" + }, + { + "rule": "parsely\\.com/videoplugins/brightcove/videojs-parsely-v1-latest\\.min\\.js" + }, + { + "rule": "parsely\\.com/v2/profile" + }, + { + "rule": "parsely\\.com/px/" + }, + { + "rule": "parsely\\.com/v2/related" + }, + { + "rule": "parsely\\.com/v2/analytics/posts" + }, + { + "rule": "parsely\\.com/v2/similar" + }, + { + "rule": "parsely\\.com/keys/adweek\\.com/p\\.js" + }, + { + "rule": "parsely\\.com/v2/search" + } + ] }, "partplanes.com": { "domain": "partplanes.com", @@ -20592,7 +20717,17 @@ "fingerprinting": 2, "cookies": 0.00574, "categories": [], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "edge\\.permutive\\.app", + "exceptions": { + "domains": [ + "globaltv.com" + ] + } + } + ] }, "permutive.com": { "domain": "permutive.com", @@ -21133,11 +21268,6 @@ "categories": [], "default": "ignore", "rules": [ - { - "rule": "powr\\.io\\/powr\\.js", - "fingerprinting": 1, - "cookies": 0.00000681 - }, { "rule": "powr\\.io\\/popup\\/u\\/61af4f5f_1680291259", "fingerprinting": 1, @@ -21409,14 +21539,7 @@ "fingerprinting": 1, "cookies": 0.000197, "categories": [], - "default": "ignore", - "rules": [ - { - "rule": "providesupport\\.com\\/sjs\\/static\\.js", - "fingerprinting": 1, - "cookies": 0.000123 - } - ] + "default": "ignore" }, "pswec.com": { "domain": "pswec.com", @@ -23122,7 +23245,23 @@ "Ad Motivated Tracking", "Advertising" ], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "micro\\.rubiconproject\\.com/prebid/dynamic/.*\\.js", + "exceptions": { + "domains": [ + "gamingbible.co.uk", + "gamingbible.com", + "ladbible.com", + "sportbible.com", + "tyla.com", + "unilad.co.uk", + "unilad.com" + ] + } + } + ] }, "ruralrobin.com": { "domain": "ruralrobin.com", @@ -25973,7 +26112,7 @@ "cookies": 0.0000136 }, { - "rule": "storage\\.googleapis\\.com/code\\.snapengage\\.com/", + "rule": "storage\\.googleapis\\.com/code\\.snapengage\\.com/js/", "fingerprinting": 3, "cookies": 0.0000136 }, @@ -27133,7 +27272,60 @@ "fingerprinting": 1, "cookies": 0.0436, "categories": [], - "default": "block" + "default": "ignore", + "rules": [ + { + "rule": "tiktok\\.com/i18n/pixel/events\\.js" + }, + { + "rule": "tiktok\\.com/i18n/pixel/static/identify_d1af3\\.js" + }, + { + "rule": "tiktok\\.com/api/v2/pixel" + }, + { + "rule": "tiktok\\.com/i18n/pixel/sdk\\.js" + }, + { + "rule": "tiktok\\.com/api/v2/performance_interaction" + }, + { + "rule": "tiktok\\.com/i18n/pixel/config\\.js" + }, + { + "rule": "tiktok\\.com/i18n/pixel/disable_cookie" + }, + { + "rule": "tiktok\\.com/i18n/pixel/static/identify_821f6\\.js" + }, + { + "rule": "tiktok\\.com/v1/user/webid" + }, + { + "rule": "tiktok\\.com/service/2/abtest_config/" + }, + { + "rule": "tiktok\\.com/web/resource" + }, + { + "rule": "tiktok\\.com/v1/list" + }, + { + "rule": "tiktok\\.com/web/report" + }, + { + "rule": "tiktok\\.com/oembed" + }, + { + "rule": "tiktok\\.com/i18n/pixel/enable_cookie" + }, + { + "rule": "tiktok\\.com/i18n/pixel/static/identify_a7248\\.js" + }, + { + "rule": "tiktok\\.com/i18n/pixel/static/main\\..*\\.js" + } + ] }, "tinypass.com": { "domain": "tinypass.com", @@ -29123,7 +29315,18 @@ "categories": [ "Advertising" ], - "default": "block" + "default": "block", + "rules": [ + { + "rule": "cdn\\.viglink\\.com/api/vglnk\\.js", + "exceptions": { + "domains": [ + "9to5mac.com", + "electrek.co" + ] + } + } + ] }, "visualwebsiteoptimizer.com": { "domain": "visualwebsiteoptimizer.com", @@ -29856,6 +30059,14 @@ "categories": [], "default": "ignore", "rules": [ + { + "rule": "universal\\.wgplayer\\.com/tag/", + "exceptions": { + "domains": [ + "yoho.games" + ] + } + }, { "rule": "wgplayer\\.com\\/tag\\/", "fingerprinting": 1, @@ -31264,21 +31475,6 @@ "categories": [], "default": "block" }, - "zopim.com": { - "domain": "zopim.com", - "owner": { - "name": "Zendesk, Inc.", - "displayName": "Zendesk", - "privacyPolicy": "https://www.zendesk.com/company/customers-partners/privacy-policy/" - }, - "prevalence": 0.0078, - "fingerprinting": 1, - "cookies": 0.00153, - "categories": [ - "Embedded Content" - ], - "default": "block" - }, "zprk.io": { "domain": "zprk.io", "owner": { @@ -42275,13 +42471,6 @@ "prevalence": 0.0926, "displayName": "iPerceptions" }, - "ipify.org": { - "domains": [ - "ipify.org" - ], - "prevalence": 0.0163, - "displayName": "ipify.org" - }, "Grupa Interia.pl Sp. z o.o. sp. k.": { "domains": [ "adretail.pl", @@ -51319,7 +51508,6 @@ "iocnt.net": "INFOnline GmbH", "iper2.com": "iPerceptions Inc.", "iperceptions.com": "iPerceptions Inc.", - "ipify.org": "ipify.org", "adretail.pl": "Grupa Interia.pl Sp. z o.o. sp. k.", "adsearch.pl": "Grupa Interia.pl Sp. z o.o. sp. k.", "bryk.pl": "Grupa Interia.pl Sp. z o.o. sp. k.", diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index d7c28a8d38..532e82fc5e 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -712,9 +712,12 @@ C1B7B52D2894469D0098FD6A /* DefaultVariantManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B52C2894469D0098FD6A /* DefaultVariantManager.swift */; }; C1B7B53028944E390098FD6A /* RemoteMessagingStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B52F28944E390098FD6A /* RemoteMessagingStoreTests.swift */; }; C1B7B53428944EFA0098FD6A /* CoreDataTestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B53328944EFA0098FD6A /* CoreDataTestUtilities.swift */; }; + C1B924B72ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B924B62ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift */; }; C1BF0BA529B63D7200482B73 /* AutofillLoginPromptHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */; }; C1BF0BA929B63E2200482B73 /* AutofillLoginPromptViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */; }; C1CCCBA7283E101500CF3791 /* FaviconsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */; }; + C1CDA3162AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */; }; + C1CDA31E2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */; }; C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */; }; C1D21E2F293A599C006E5A05 /* AutofillLoginSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */; }; C1F341C52A6924000032057B /* EmailAddressPromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F341C42A6924000032057B /* EmailAddressPromptView.swift */; }; @@ -2273,9 +2276,12 @@ C1B7B52C2894469D0098FD6A /* DefaultVariantManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultVariantManager.swift; sourceTree = ""; }; C1B7B52F28944E390098FD6A /* RemoteMessagingStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMessagingStoreTests.swift; sourceTree = ""; }; C1B7B53328944EFA0098FD6A /* CoreDataTestUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataTestUtilities.swift; sourceTree = ""; }; + C1B924B62ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillNeverSavedTableViewCell.swift; sourceTree = ""; }; C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptHelper.swift; sourceTree = ""; }; C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptViewModelTests.swift; sourceTree = ""; }; C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconsHelper.swift; sourceTree = ""; }; + C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManager.swift; sourceTree = ""; }; + C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManagerTests.swift; sourceTree = ""; }; C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSession.swift; sourceTree = ""; }; C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSessionTests.swift; sourceTree = ""; }; C1F341C42A6924000032057B /* EmailAddressPromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailAddressPromptView.swift; sourceTree = ""; }; @@ -3269,6 +3275,7 @@ 311BD1AE2836BB4200AEF6C1 /* AutofillItemsLockedView.swift */, 2DC3FBD62FBAF21E87610FA8 /* AutofillNoAuthAvailableView.swift */, C18ED4392AB6F77600BF3805 /* AutofillSettingsEnableFooterView.swift */, + C1B924B62ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift */, ); name = Table; sourceTree = ""; @@ -5227,6 +5234,7 @@ C1BF0BA629B63E0400482B73 /* AutofillLoginUI */, F40F843528C938370081AE75 /* AutofillLoginListViewModelTests.swift */, C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */, + C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */, ); name = Autofill; sourceTree = ""; @@ -5237,6 +5245,7 @@ D63657182A7BAE7C001AF19D /* EmailManagerRequestDelegate.swift */, F4147353283BF834004AA7A5 /* AutofillContentScopeFeatureToggles.swift */, C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */, + C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */, C13B32D12A0E750700A59236 /* AutofillSettingStatus.swift */, 319A370F28299A850079FBCE /* PasswordHider.swift */, 31C70B5428045E3500FB6AD1 /* SecureVaultErrorReporter.swift */, @@ -6173,6 +6182,7 @@ F1668BCE1E798081008CBA04 /* BookmarksViewController.swift in Sources */, 1E162610296C5C630004127F /* CustomDaxDialogViewModel.swift in Sources */, 8590CB69268A4E190089F6BF /* DebugEtagStorage.swift in Sources */, + C1CDA3162AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift in Sources */, F1CA3C371F045878005FADB3 /* PrivacyStore.swift in Sources */, 37FCAAC029930E26000E420A /* FailedAssertionView.swift in Sources */, F4E1936625AF722F001D2666 /* HighlightCutOutView.swift in Sources */, @@ -6220,6 +6230,7 @@ CB9B873C278C8FEA001F4906 /* WidgetEducationView.swift in Sources */, 85F200002215C17B006BB258 /* FindInPage.swift in Sources */, F1386BA41E6846C40062FC3C /* TabDelegate.swift in Sources */, + C1B924B72ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift in Sources */, 020108A929A7C1CD00644F9D /* AppTrackerImageCache.swift in Sources */, 3132FA2A27A0788F00DD7A12 /* QuickLookPreviewHelper.swift in Sources */, C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */, @@ -6605,6 +6616,7 @@ C1D21E2F293A599C006E5A05 /* AutofillLoginSessionTests.swift in Sources */, 85D2187924BF6B8B004373D2 /* FaviconSourcesProviderTests.swift in Sources */, 1E8146AD28C8ABF000D1AF63 /* TrackerAnimationLogicTests.swift in Sources */, + C1CDA31E2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift in Sources */, B6AD9E3A28D456820019CDE9 /* PrivacyConfigurationManagerMock.swift in Sources */, F189AED71F18F6DE001EBAE1 /* TabTests.swift in Sources */, F13B4BFB1F18E3D900814661 /* TabsModelPersistenceExtensionTests.swift in Sources */, diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 823b00b9ef..55defd9289 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,7 +15,7 @@ "repositoryURL": "https://github.com/DuckDuckGo/BrowserServicesKit", "state": { "branch": "fcappelli/breakage_report_improvements", - "revision": "3beb9e40d9062b330a56b5af77f944a9aa6c39e3", + "revision": "60cc52d888adb482519495b73277b5f15d128ab4", "version": null } }, @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/duckduckgo/duckduckgo-autofill.git", "state": { "branch": null, - "revision": "c8e895c8fd50dc76e8d8dc827a636ad77b7f46ff", - "version": "9.0.0" + "revision": "93677cc02cfe650ce7f417246afd0e8e972cd83e", + "version": "10.0.0" } }, { diff --git a/DuckDuckGo/AppDependencyProvider.swift b/DuckDuckGo/AppDependencyProvider.swift index 3b42c75074..5f7854281c 100644 --- a/DuckDuckGo/AppDependencyProvider.swift +++ b/DuckDuckGo/AppDependencyProvider.swift @@ -34,6 +34,7 @@ protocol DependencyProvider { var voiceSearchHelper: VoiceSearchHelperProtocol { get } var downloadManager: DownloadManager { get } var autofillLoginSession: AutofillLoginSession { get } + var autofillNeverPromptWebsitesManager: AutofillNeverPromptWebsitesManager { get } var configurationManager: ConfigurationManager { get } } @@ -56,6 +57,7 @@ class AppDependencyProvider: DependencyProvider { let voiceSearchHelper: VoiceSearchHelperProtocol = VoiceSearchHelper() let downloadManager = DownloadManager() let autofillLoginSession = AutofillLoginSession() + lazy var autofillNeverPromptWebsitesManager = AutofillNeverPromptWebsitesManager() let configurationManager = ConfigurationManager() } diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index f06c8d7180..552e381a02 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -252,7 +252,7 @@ public class AppUserDefaults: AppSettings { userDefaults?.set(newValue, forKey: Keys.autofillCredentialsEnabled) } } - + @UserDefaultsWrapper(key: .autofillCredentialsSavePromptShowAtLeastOnce, defaultValue: false) var autofillCredentialsSavePromptShowAtLeastOnce: Bool diff --git a/DuckDuckGo/AutofillLoginListViewModel.swift b/DuckDuckGo/AutofillLoginListViewModel.swift index ae9642b488..2295c54873 100644 --- a/DuckDuckGo/AutofillLoginListViewModel.swift +++ b/DuckDuckGo/AutofillLoginListViewModel.swift @@ -45,6 +45,11 @@ internal enum AutofillLoginListSectionType: Comparable { static let miscSectionHeading = "#" } +internal enum EnableAutofillRows: Int, CaseIterable { + case toggleAutofill + case resetNeverPromptWebsites +} + final class AutofillLoginListViewModel: ObservableObject { enum ViewState { @@ -66,10 +71,12 @@ final class AutofillLoginListViewModel: ObservableObject { private let tld: TLD private var currentTabUrl: URL? private let secureVault: (any AutofillSecureVault)? + private let autofillNeverPromptWebsitesManager: AutofillNeverPromptWebsitesManager private var cachedDeletedCredentials: SecureVaultModels.WebsiteCredentials? private let autofillDomainNameUrlMatcher = AutofillDomainNameUrlMatcher() private let autofillDomainNameUrlSort = AutofillDomainNameUrlSort() + @Published private (set) var viewState: AutofillLoginListViewModel.ViewState = .authLocked @Published private(set) var sections = [AutofillLoginListSectionType]() { didSet { @@ -89,11 +96,13 @@ final class AutofillLoginListViewModel: ObservableObject { } } - init(appSettings: AppSettings, tld: TLD, secureVault: (any AutofillSecureVault)?, currentTabUrl: URL? = nil) { + init(appSettings: AppSettings, tld: TLD, secureVault: (any AutofillSecureVault)?, currentTabUrl: URL? = nil, autofillNeverPromptWebsitesManager: AutofillNeverPromptWebsitesManager = AppDependencyProvider.shared.autofillNeverPromptWebsitesManager) { self.appSettings = appSettings self.tld = tld self.secureVault = secureVault self.currentTabUrl = currentTabUrl + self.autofillNeverPromptWebsitesManager = autofillNeverPromptWebsitesManager + updateData() authenticationNotRequired = !hasAccountsSaved || AppDependencyProvider.shared.autofillLoginSession.isValidSession setupCancellables() @@ -153,7 +162,7 @@ final class AutofillLoginListViewModel: ObservableObject { func rowsInSection(_ section: Int) -> Int { switch self.sections[section] { case .enableAutofill: - return 1 + return autofillNeverPromptWebsitesManager.neverPromptWebsites.isEmpty ? 1 : 2 case .credentials(_, let items): return items.count } @@ -180,8 +189,11 @@ final class AutofillLoginListViewModel: ObservableObject { } self.sections = makeSections(with: filteredAccounts) } - - + + func resetNeverPromptWebsites() { + _ = autofillNeverPromptWebsitesManager.deleteAllNeverPromptWebsites() + } + // MARK: Private Methods private func fetchAccounts() -> [SecureVaultModels.WebsiteAccount] { diff --git a/DuckDuckGo/AutofillLoginPromptView.swift b/DuckDuckGo/AutofillLoginPromptView.swift index 0a75d988ee..4570c243f8 100644 --- a/DuckDuckGo/AutofillLoginPromptView.swift +++ b/DuckDuckGo/AutofillLoginPromptView.swift @@ -44,7 +44,7 @@ struct AutofillLoginPromptView: View { VStack { Spacer() .frame(height: Const.Size.topPadding) - AutofillViews.WebsiteWithFavicon(accountDomain: viewModel.domain) + AutofillViews.AppIconHeader() Spacer() .frame(height: Const.Size.headlineTopPadding) AutofillViews.Headline(title: viewModel.message) diff --git a/DuckDuckGo/AutofillLoginSettingsListViewController.swift b/DuckDuckGo/AutofillLoginSettingsListViewController.swift index 2055e7b03f..89fa680bc1 100644 --- a/DuckDuckGo/AutofillLoginSettingsListViewController.swift +++ b/DuckDuckGo/AutofillLoginSettingsListViewController.swift @@ -77,6 +77,7 @@ final class AutofillLoginSettingsListViewController: UIViewController { tableView.estimatedSectionFooterHeight = 40 tableView.registerCell(ofType: AutofillListItemTableViewCell.self) tableView.registerCell(ofType: EnableAutofillSettingsTableViewCell.self) + tableView.registerCell(ofType: AutofillNeverSavedTableViewCell.self) // Have to set tableHeaderView height otherwise tableView content will jump when adding / removing searchController due to tableView insetGrouped style tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 24)) return tableView @@ -217,7 +218,23 @@ final class AutofillLoginSettingsListViewController: UIViewController { navigationController?.pushViewController(detailsController, animated: animated) detailsViewController = detailsController } - + + private func presentNeverPromptResetPromptAtIndexPath(_ indexPath: IndexPath) { + let controller = UIAlertController(title: "", + message: UserText.autofillResetNeverSavedActionTitle, + preferredStyle: .actionSheet) + controller.addAction(UIAlertAction(title: UserText.autofillResetNeverSavedActionConfirmButton, style: .destructive) { [weak self] _ in + self?.viewModel.resetNeverPromptWebsites() + self?.tableView.reloadData() + Pixel.fire(pixel: .autofillLoginsSettingsResetExcludedConfirmed) + }) + controller.addAction(UIAlertAction(title: UserText.autofillResetNeverSavedActionCancelButton, style: .cancel) { _ in + Pixel.fire(pixel: .autofillLoginsSettingsResetExcludedDismissed) + }) + present(controller: controller, fromView: tableView.cellForRow(at: indexPath) ?? tableView) + Pixel.fire(pixel: .autofillLoginsSettingsResetExcludedDisplayed) + } + private func setupCancellables() { viewModel.$viewState .receive(on: DispatchQueue.main) @@ -470,6 +487,12 @@ final class AutofillLoginSettingsListViewController: UIViewController { cell.theme = ThemeManager.shared.currentTheme return cell } + + private func neverSavedCell(for tableView: UITableView, indexPath: IndexPath) -> AutofillNeverSavedTableViewCell { + let cell = tableView.dequeueCell(ofType: AutofillNeverSavedTableViewCell.self, for: indexPath) + cell.theme = ThemeManager.shared.currentTheme + return cell + } } // MARK: UITableViewDelegate @@ -489,11 +512,16 @@ extension AutofillLoginSettingsListViewController: UITableViewDelegate { tableView.deselectRow(at: indexPath, animated: true) switch viewModel.sections[indexPath.section] { + case .enableAutofill: + switch EnableAutofillRows(rawValue: indexPath.row) { + case .resetNeverPromptWebsites: + presentNeverPromptResetPromptAtIndexPath(indexPath) + default: + break + } case .credentials(_, let items): let item = items[indexPath.row] showAccountDetails(item.account) - default: - break } } @@ -541,7 +569,14 @@ extension AutofillLoginSettingsListViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { switch viewModel.sections[indexPath.section] { case .enableAutofill: - return enableAutofillCell(for: tableView, indexPath: indexPath) + switch EnableAutofillRows(rawValue: indexPath.row) { + case .toggleAutofill: + return enableAutofillCell(for: tableView, indexPath: indexPath) + case .resetNeverPromptWebsites: + return neverSavedCell(for: tableView, indexPath: indexPath) + default: + fatalError("No cell for row at index \(indexPath.row)") + } case .credentials(_, let items): return credentialCell(for: tableView, item: items[indexPath.row], indexPath: indexPath) } diff --git a/DuckDuckGo/AutofillNeverPromptWebsitesManager.swift b/DuckDuckGo/AutofillNeverPromptWebsitesManager.swift new file mode 100644 index 0000000000..1671e0b5fb --- /dev/null +++ b/DuckDuckGo/AutofillNeverPromptWebsitesManager.swift @@ -0,0 +1,84 @@ +// +// AutofillNeverPromptWebsitesManager.swift +// DuckDuckGo +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import BrowserServicesKit +import Core + +class AutofillNeverPromptWebsitesManager { + + public private(set) var neverPromptWebsites: [SecureVaultModels.NeverPromptWebsites] = [] + + private let secureVault: (any AutofillSecureVault)? + + public init(secureVault: (any AutofillSecureVault)? = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared)) { + self.secureVault = secureVault + + fetchNeverPromptWebsites() + } + + public func hasNeverPromptWebsitesFor(domain: String) -> Bool { + return neverPromptWebsites.contains { $0.domain == domain } + } + + public func saveNeverPromptWebsite(_ domain: String) throws -> Int64? { + guard let secureVault = secureVault else { + return nil + } + + do { + let id = try secureVault.storeNeverPromptWebsites(SecureVaultModels.NeverPromptWebsites(domain: domain)) + + fetchNeverPromptWebsites() + return id + } catch { + Pixel.fire(pixel: .secureVaultError, error: error) + throw error + } + } + + public func deleteAllNeverPromptWebsites() -> Bool { + guard let secureVault = secureVault else { + return false + } + + do { + try secureVault.deleteAllNeverPromptWebsites() + + fetchNeverPromptWebsites() + return true + } catch { + Pixel.fire(pixel: .secureVaultError, error: error) + return false + } + } + + private func fetchNeverPromptWebsites() { + guard let secureVault = secureVault else { + return + } + + do { + neverPromptWebsites = try secureVault.neverPromptWebsites() + } catch { + Pixel.fire(pixel: .secureVaultError, error: error) + neverPromptWebsites = [] + } + } +} diff --git a/DuckDuckGo/AutofillNeverSavedTableViewCell.swift b/DuckDuckGo/AutofillNeverSavedTableViewCell.swift new file mode 100644 index 0000000000..adfc4c5e53 --- /dev/null +++ b/DuckDuckGo/AutofillNeverSavedTableViewCell.swift @@ -0,0 +1,78 @@ +// +// AutofillNeverSavedTableViewCell.swift +// DuckDuckGo +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit +import DesignResourcesKit + +class AutofillNeverSavedTableViewCell: UITableViewCell { + + var theme: Theme? { + didSet { + updateTheme() + } + } + + private lazy var titleLabel: UILabel = { + let label = UILabel(frame: CGRect.zero) + label.font = .preferredFont(forTextStyle: .callout) + label.text = UserText.autofillNeverSavedSettings + label.numberOfLines = 0 + label.lineBreakMode = .byWordWrapping + return label + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupSubviews() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupSubviews() { + installSubviews() + installConstraints() + } + + private func installSubviews() { + contentView.addSubview(titleLabel) + } + + private func installConstraints() { + titleLabel.translatesAutoresizingMaskIntoConstraints = false + let margins = contentView.layoutMarginsGuide + + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: margins.topAnchor), + titleLabel.bottomAnchor.constraint(equalTo: margins.bottomAnchor), + titleLabel.leadingAnchor.constraint(equalTo: margins.leadingAnchor), + titleLabel.trailingAnchor.constraint(equalTo: margins.trailingAnchor) + ]) + } + + private func updateTheme() { + guard let theme = theme else { + return + } + + titleLabel.textColor = theme.autofillDefaultTitleTextColor + contentView.backgroundColor = UIColor(designSystemColor: .surface) + } +} diff --git a/DuckDuckGo/AutofillViews.swift b/DuckDuckGo/AutofillViews.swift index 8dab1a504d..aae551c98f 100644 --- a/DuckDuckGo/AutofillViews.swift +++ b/DuckDuckGo/AutofillViews.swift @@ -55,18 +55,10 @@ struct AutofillViews { } } - struct WebsiteWithFavicon: View { - let accountDomain: String - + struct AppIconHeader: View { var body: some View { - HStack { - FaviconView(viewModel: FaviconViewModel(domain: accountDomain)) - .scaledToFit() - .frame(width: Const.Size.logoImage, height: Const.Size.logoImage) - Text(accountDomain) - .daxFootnoteRegular() - .foregroundColor(Color(designSystemColor: .textSecondary)) - } + Image.appIcon + .scaledToFit() } } @@ -241,4 +233,5 @@ private enum Const { private extension Image { static let close = Image("Close-24") + static let appIcon = Image("WaitlistShareSheetLogo") } diff --git a/DuckDuckGo/EmailSignupViewController.swift b/DuckDuckGo/EmailSignupViewController.swift index 2bcfe0f28e..abcce2eb84 100644 --- a/DuckDuckGo/EmailSignupViewController.swift +++ b/DuckDuckGo/EmailSignupViewController.swift @@ -421,6 +421,10 @@ extension EmailSignupViewController: SecureVaultManagerDelegate { // no-op } + func secureVaultManager(_: SecureVaultManager, didRequestRuntimeConfigurationForDomain domain: String, completionHandler: @escaping (String?) -> Void) { + completionHandler(nil) + } + func secureVaultManager(_: SecureVaultManager, didReceivePixel pixel: AutofillUserScript.JSPixel) { guard !pixel.isEmailPixel else { // The iOS app uses a native email autofill UI, and sends its pixels separately. Ignore pixels sent from the JS layer. diff --git a/DuckDuckGo/Favicons.swift b/DuckDuckGo/Favicons.swift index 74487c3585..ceda1bf9d3 100644 --- a/DuckDuckGo/Favicons.swift +++ b/DuckDuckGo/Favicons.swift @@ -381,6 +381,8 @@ public class Favicons { return } + /// DuckDuckGo Privacy Browser uses built-in functionality from iOS to fetch the highest quality favicons for your bookmarks and favorites. + /// This functionality uses a user agent that is different from other network requests made by the app in order to find the best favicon available. let metadataFetcher = LPMetadataProvider() let completion: (LPLinkMetadata?, Error?) -> Void = { metadata, metadataError in guard let iconProvider = metadata?.iconProvider, metadataError == nil else { diff --git a/DuckDuckGo/FilePreviewHelper.swift b/DuckDuckGo/FilePreviewHelper.swift index f13b508379..f8f4009311 100644 --- a/DuckDuckGo/FilePreviewHelper.swift +++ b/DuckDuckGo/FilePreviewHelper.swift @@ -33,7 +33,10 @@ struct FilePreviewHelper { static func canAutoPreviewMIMEType(_ mimeType: MIMEType) -> Bool { switch mimeType { - case .reality, .usdz, .passbook, .calendar: + case .passbook: + return UIDevice.current.userInterfaceIdiom == .phone + + case .reality, .usdz, .calendar: return true default: return false diff --git a/DuckDuckGo/PassKitPreviewHelper.swift b/DuckDuckGo/PassKitPreviewHelper.swift index 6b95cbe2e6..3a734eee03 100644 --- a/DuckDuckGo/PassKitPreviewHelper.swift +++ b/DuckDuckGo/PassKitPreviewHelper.swift @@ -34,8 +34,9 @@ class PassKitPreviewHelper: FilePreview { do { let data = try Data(contentsOf: self.filePath) let pass = try PKPass(data: data) - let controller = PKAddPassesViewController(pass: pass)! - viewController?.present(controller, animated: true) + if let controller = PKAddPassesViewController(pass: pass) { + viewController?.present(controller, animated: true) + } } catch { os_log("Can't present passkit: %s", type: .debug, error.localizedDescription) } diff --git a/DuckDuckGo/PasswordGenerationPromptView.swift b/DuckDuckGo/PasswordGenerationPromptView.swift index 1ed7fcdc0f..470084db8f 100644 --- a/DuckDuckGo/PasswordGenerationPromptView.swift +++ b/DuckDuckGo/PasswordGenerationPromptView.swift @@ -42,8 +42,12 @@ struct PasswordGenerationPromptView: View { .zIndex(1) VStack { + Spacer() + .frame(height: Const.Size.topPadding) + AutofillViews.AppIconHeader() + Spacer() + .frame(height: Const.Size.headlineTopPadding) AutofillViews.Headline(title: UserText.autofillPasswordGenerationPromptTitle) - .padding(.top, Const.Size.topPadding) if #available(iOS 16.0, *) { passwordView .padding([.top, .bottom], passwordVerticalPadding) @@ -185,6 +189,7 @@ private enum Const { static let closeButtonOffsetPortrait: CGFloat = 44.0 static let closeButtonOffsetPortraitSmallFrame: CGFloat = 16.0 static let topPadding: CGFloat = 56.0 + static let headlineTopPadding: CGFloat = 24.0 static let ios15scrollOffset: CGFloat = 80.0 static let passwordButtonSpacing: CGFloat = 10.0 static let passwordPaddingHeight: CGFloat = 28.0 diff --git a/DuckDuckGo/SaveAutofillLoginManager.swift b/DuckDuckGo/SaveAutofillLoginManager.swift index 139e12c12d..725b2f823d 100644 --- a/DuckDuckGo/SaveAutofillLoginManager.swift +++ b/DuckDuckGo/SaveAutofillLoginManager.swift @@ -94,6 +94,13 @@ final class SaveAutofillLoginManager: SaveAutofillLoginManagerProtocol { } } + func isNeverPromptWebsiteForDomain() -> Bool { + guard let domain = credentials.account.domain else { + return false + } + return AppDependencyProvider.shared.autofillNeverPromptWebsitesManager.hasNeverPromptWebsitesFor(domain: domain) + } + private var savedMatchingPasswordWithoutUsername: SecureVaultModels.WebsiteCredentials? { let credentialsWithSamePassword = domainStoredCredentials.filter { storedCredentials in storedCredentials.password == credentials.password && (storedCredentials.account.username?.count ?? 0) == 0 diff --git a/DuckDuckGo/SaveLoginView.swift b/DuckDuckGo/SaveLoginView.swift index 4e80ca014a..f2dc2cb311 100644 --- a/DuckDuckGo/SaveLoginView.swift +++ b/DuckDuckGo/SaveLoginView.swift @@ -46,10 +46,8 @@ struct SaveLoginView: View { private var title: String { switch layoutType { - case .newUser, .saveLogin: + case .newUser, .saveLogin, .savePassword: return UserText.autofillSaveLoginTitleNewUser - case .savePassword: - return UserText.autofillSavePasswordTitle case .updateUsername: return UserText.autofillUpdateUsernameTitle case .updatePassword: @@ -59,9 +57,7 @@ struct SaveLoginView: View { private var confirmButton: String { switch layoutType { - case .newUser, .saveLogin: - return UserText.autofillSaveLoginSaveCTA - case .savePassword: + case .newUser, .saveLogin, .savePassword: return UserText.autofillSavePasswordSaveCTA case .updateUsername: return UserText.autofillUpdateUsernameSaveCTA @@ -90,7 +86,7 @@ struct SaveLoginView: View { VStack { Spacer() .frame(height: Const.Size.topPadding) - AutofillViews.WebsiteWithFavicon(accountDomain: viewModel.accountDomain) + AutofillViews.AppIconHeader() Spacer() .frame(height: Const.Size.headlineTopPadding) AutofillViews.Headline(title: title) @@ -141,8 +137,8 @@ struct SaveLoginView: View { AutofillViews.PrimaryButton(title: confirmButton, action: viewModel.save) - AutofillViews.TertiaryButton(title: UserText.autofillSaveLoginNotNowCTA, - action: viewModel.cancelButtonPressed) + AutofillViews.TertiaryButton(title: UserText.autofillSaveLoginNeverPromptCTA, + action: viewModel.neverPrompt) } } @@ -218,7 +214,7 @@ private enum Const { struct SaveLoginView_Previews: PreviewProvider { private struct MockManager: SaveAutofillLoginManagerProtocol { - + var username: String { "dax@duck.com" } var visiblePassword: String { "supersecurepasswordquack" } var isNewAccount: Bool { false } diff --git a/DuckDuckGo/SaveLoginViewController.swift b/DuckDuckGo/SaveLoginViewController.swift index 82d0afec9e..056546bed6 100644 --- a/DuckDuckGo/SaveLoginViewController.swift +++ b/DuckDuckGo/SaveLoginViewController.swift @@ -26,6 +26,7 @@ protocol SaveLoginViewControllerDelegate: AnyObject { func saveLoginViewController(_ viewController: SaveLoginViewController, didSaveCredentials credentials: SecureVaultModels.WebsiteCredentials) func saveLoginViewController(_ viewController: SaveLoginViewController, didUpdateCredentials credentials: SecureVaultModels.WebsiteCredentials) func saveLoginViewControllerDidCancel(_ viewController: SaveLoginViewController) + func saveLoginViewController(_ viewController: SaveLoginViewController, didRequestNeverPromptForWebsite domain: String) func saveLoginViewController(_ viewController: SaveLoginViewController, didRequestPresentConfirmKeepUsingAlertController alertController: UIAlertController) } @@ -136,6 +137,11 @@ extension SaveLoginViewController: SaveLoginViewModelDelegate { delegate?.saveLoginViewControllerDidCancel(self) } + func saveLoginViewModelNeverPrompt(_ viewModel: SaveLoginViewModel) { + Pixel.fire(pixel: .autofillLoginsSaveLoginModalExcludeSiteConfirmed) + delegate?.saveLoginViewController(self, didRequestNeverPromptForWebsite: viewModel.accountDomain) + } + func saveLoginViewModelConfirmKeepUsing(_ viewModel: SaveLoginViewModel, isAlreadyDismissed: Bool) { let isSelfPresentingAlert = !isAlreadyDismissed diff --git a/DuckDuckGo/SaveLoginViewModel.swift b/DuckDuckGo/SaveLoginViewModel.swift index 074b3b76d4..1586627994 100644 --- a/DuckDuckGo/SaveLoginViewModel.swift +++ b/DuckDuckGo/SaveLoginViewModel.swift @@ -24,6 +24,7 @@ import Core protocol SaveLoginViewModelDelegate: AnyObject { func saveLoginViewModelDidSave(_ viewModel: SaveLoginViewModel) func saveLoginViewModelDidCancel(_ viewModel: SaveLoginViewModel) + func saveLoginViewModelNeverPrompt(_ viewModel: SaveLoginViewModel) func saveLoginViewModelConfirmKeepUsing(_ viewModel: SaveLoginViewModel, isAlreadyDismissed: Bool) func saveLoginViewModelDidResizeContent(_ viewModel: SaveLoginViewModel, contentHeight: CGFloat) } @@ -180,4 +181,10 @@ final class SaveLoginViewModel: ObservableObject { autofillFirstTimeUser = false delegate?.saveLoginViewModelDidSave(self) } + + func neverPrompt() { + didSave = true + autofillFirstTimeUser = false + delegate?.saveLoginViewModelNeverPrompt(self) + } } diff --git a/DuckDuckGo/ScriptSourceProviding.swift b/DuckDuckGo/ScriptSourceProviding.swift index 5ac97820af..615dfc71a2 100644 --- a/DuckDuckGo/ScriptSourceProviding.swift +++ b/DuckDuckGo/ScriptSourceProviding.swift @@ -74,8 +74,10 @@ struct DefaultScriptSourceProvider: ScriptSourceProviding { private static func makeAutofillSource(privacyConfigurationManager: PrivacyConfigurationManaging, properties: ContentScopeProperties) -> AutofillUserScriptSourceProvider { - DefaultAutofillSourceProvider(privacyConfigurationManager: privacyConfigurationManager, - properties: properties) + return DefaultAutofillSourceProvider.Builder(privacyConfigurationManager: privacyConfigurationManager, + properties: properties) + .withJSLoading() + .build() } private static func buildContentBlockerRulesConfig(contentBlockingManager: ContentBlockerRulesManagerProtocol, diff --git a/DuckDuckGo/Settings.bundle/Root.plist b/DuckDuckGo/Settings.bundle/Root.plist index fb5f1dc72e..52e3696d8c 100644 --- a/DuckDuckGo/Settings.bundle/Root.plist +++ b/DuckDuckGo/Settings.bundle/Root.plist @@ -6,7 +6,7 @@ DefaultValue - 7.96.0 + 7.97.0 Key version Title diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 621a6dc0ce..b16261e6cb 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -90,6 +90,7 @@ class TabViewController: UIViewController { lazy var featureFlagger = AppDependencyProvider.shared.featureFlagger private lazy var internalUserDecider = AppDependencyProvider.shared.internalUserDecider + private lazy var autofillNeverPromptWebsitesManager = AppDependencyProvider.shared.autofillNeverPromptWebsitesManager private lazy var autofillWebsiteAccountMatcher = AutofillWebsiteAccountMatcher(autofillUrlMatcher: AutofillDomainNameUrlMatcher(), tld: TabViewController.tld) private(set) var tabModel: Tab @@ -122,6 +123,8 @@ class TabViewController: UIViewController { private var saveLoginPromptLastDismissed: Date? private var saveLoginPromptIsPresenting: Bool = false + private var cachedRuntimeConfigurationForDomain: [String: String?] = [:] + // If no trackers dax dialog was shown recently in this tab, ie without the user navigating somewhere else, e.g. backgrounding or tab switcher private var woShownRecently = false @@ -616,6 +619,7 @@ class TabViewController: UIViewController { public func reload() { updateContentMode() + cachedRuntimeConfigurationForDomain = [:] webView.reload() privacyDashboard?.dismiss(animated: true) } @@ -2303,7 +2307,7 @@ extension TabViewController: SecureVaultManagerDelegate { func secureVaultInitFailed(_ error: SecureStorageError) { SecureVaultErrorReporter.shared.secureVaultInitFailed(error) } - + func secureVaultManagerIsEnabledStatus(_ manager: SecureVaultManager, forType type: AutofillType?) -> Bool { let isEnabled = AutofillSettingStatus.isAutofillEnabledInSettings && featureFlagger.isFeatureOn(.autofillCredentialInjecting) && @@ -2316,8 +2320,8 @@ extension TabViewController: SecureVaultManagerDelegate { return isEnabled } - func secureVaultManagerShouldSaveData(_: SecureVaultManager) -> Bool { - true + func secureVaultManagerShouldSaveData(_ manager: SecureVaultManager) -> Bool { + return secureVaultManagerIsEnabledStatus(manager, forType: nil) } func secureVaultManager(_ vault: SecureVaultManager, @@ -2456,6 +2460,38 @@ extension TabViewController: SecureVaultManagerDelegate { func secureVaultManager(_: BrowserServicesKit.SecureVaultManager, didRequestPasswordManagerForDomain domain: String) { } + func secureVaultManager(_: SecureVaultManager, didRequestRuntimeConfigurationForDomain domain: String, completionHandler: @escaping (String?) -> Void) { + // didRequestRuntimeConfigurationForDomain fires for every iframe loaded on a website + // so caching the runtime configuration for the domain to prevent unnecessary re-building of the configuration + if let runtimeConfigurationForDomain = cachedRuntimeConfigurationForDomain[domain] as? String { + completionHandler(runtimeConfigurationForDomain) + return + } + + let runtimeConfiguration = + DefaultAutofillSourceProvider.Builder(privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager, + properties: buildContentScopePropertiesForDomain(domain)) + .build() + .buildRuntimeConfigResponse() + + cachedRuntimeConfigurationForDomain = [domain: runtimeConfiguration] + completionHandler(runtimeConfiguration) + } + + private func buildContentScopePropertiesForDomain(_ domain: String) -> ContentScopeProperties { + var supportedFeatures = ContentScopeFeatureToggles.supportedFeaturesOniOS + + if AutofillSettingStatus.isAutofillEnabledInSettings, + featureFlagger.isFeatureOn(.autofillCredentialsSaving), + autofillNeverPromptWebsitesManager.hasNeverPromptWebsitesFor(domain: domain) { + supportedFeatures.passwordGeneration = false + } + + return ContentScopeProperties(gpcEnabled: appSettings.sendDoNotSell, + sessionKey: autofillUserScript?.sessionKey ?? "", + featureToggles: supportedFeatures) + } + func secureVaultManager(_: SecureVaultManager, didReceivePixel pixel: AutofillUserScript.JSPixel) { guard !pixel.isEmailPixel else { // The iOS app uses a native email autofill UI, and sends its pixels separately. Ignore pixels sent from the JS layer. @@ -2520,6 +2556,18 @@ extension TabViewController: SaveLoginViewControllerDelegate { saveLoginPromptLastDismissed = Date() saveLoginPromptIsPresenting = false } + + func saveLoginViewController(_ viewController: SaveLoginViewController, didRequestNeverPromptForWebsite domain: String) { + viewController.dismiss(animated: true) + saveLoginPromptLastDismissed = Date() + saveLoginPromptIsPresenting = false + + do { + _ = try autofillNeverPromptWebsitesManager.saveNeverPromptWebsite(domain) + } catch { + os_log("%: failed to save never prompt for website %s", type: .error, #function, error.localizedDescription) + } + } func saveLoginViewController(_ viewController: SaveLoginViewController, didRequestPresentConfirmKeepUsingAlertController alertController: UIAlertController) { diff --git a/DuckDuckGo/UserScripts.swift b/DuckDuckGo/UserScripts.swift index 9f8b7cafeb..06cd05c46e 100644 --- a/DuckDuckGo/UserScripts.swift +++ b/DuckDuckGo/UserScripts.swift @@ -45,6 +45,7 @@ final class UserScripts: UserScriptsProvider { contentBlockerUserScript = ContentBlockerRulesUserScript(configuration: sourceProvider.contentBlockerRulesConfig) surrogatesScript = SurrogatesUserScript(configuration: sourceProvider.surrogatesConfig) autofillUserScript = AutofillUserScript(scriptSourceProvider: sourceProvider.autofillSourceProvider) + autofillUserScript.sessionKey = sourceProvider.contentScopeProperties.sessionKey loginFormDetectionScript = sourceProvider.loginDetectionEnabled ? LoginFormDetectionUserScript() : nil contentScopeUserScript = ContentScopeUserScript(sourceProvider.privacyConfigurationManager, diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 80e3e9b5b7..bd7080b3d5 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -415,21 +415,20 @@ public struct UserText { public static let emptyDownloads = NSLocalizedString("downloads.downloads-list.empty", value: "No files downloaded yet", comment: "Empty downloads list placholder") - public static let autofillSaveLoginTitleNewUser = NSLocalizedString("autofill.save-login.new-user.title", value: "Do you want DuckDuckGo to save your Login?", comment: "Title displayed on modal asking for the user to save the login for the first time") + public static let autofillSaveLoginTitleNewUser = NSLocalizedString("autofill.save-login.new-user.title", value: "Do you want DuckDuckGo to save your password?", comment: "Title displayed on modal asking for the user to save the login for the first time") public static let autofillSaveLoginTitle = NSLocalizedString("autofill.save-login.title", value: "Save Login?", comment: "Title displayed on modal asking for the user to save the login") public static let autofillUpdateUsernameTitle = NSLocalizedString("autofill.update-usernamr.title", value: "Update username?", comment: "Title displayed on modal asking for the user to update the username") - public static let autofillSaveLoginMessageNewUser = NSLocalizedString("autofill.save-login.new-user.message", value: "Logins are stored securely on your device in the Logins menu.", comment: "Message displayed on modal asking for the user to save the login for the first time") + public static let autofillSaveLoginMessageNewUser = NSLocalizedString("autofill.save-login.new-user.message", value: "Passwords are stored securely on your device in the Logins menu.", comment: "Message displayed on modal asking for the user to save the login for the first time") public static let autofillSaveLoginNotNowCTA = NSLocalizedString("autofill.save-login.not-now.CTA", value: "Don’t Save", comment: "Cancel CTA displayed on modal asking for the user to save the login") - - public static let autofillSavePasswordTitle = NSLocalizedString("autofill.save-password.title", value: "Save Password?", comment: "Title displayed on modal asking for the user to save the password") + public static let autofillSaveLoginNeverPromptCTA = NSLocalizedString("autofill.save-login.never-prompt.CTA", value:"Never Ask for This Site", comment: "CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin") + public static func autofillUpdatePassword(for title: String) -> String { let message = NSLocalizedString("autofill.update-password.title", value: "Update password for\n%@?", comment: "Title displayed on modal asking for the user to update the password") return message.format(arguments: title) } - public static let autoUpdatePasswordMessage = NSLocalizedString("autofill.update-password.message", value: "DuckDuckGo will update this stored Login on your device.", comment: "Message displayed on modal asking for the user to update the password") + public static let autoUpdatePasswordMessage = NSLocalizedString("autofill.update-password.message", value: "DuckDuckGo will update this stored password on your device.", comment: "Message displayed on modal asking for the user to update the password") - public static let autofillSaveLoginSaveCTA = NSLocalizedString("autofill.save-login.save.CTA", value: "Save Login", comment: "Confirm CTA displayed on modal asking for the user to save the login") public static let autofillSavePasswordSaveCTA = NSLocalizedString("autofill.save-password.save.CTA", value: "Save Password", comment: "Confirm CTA displayed on modal asking for the user to save the password") public static let autofillUpdatePasswordSaveCTA = NSLocalizedString("autofill.update-password.save.CTA", value: "Update Password", comment: "Confirm CTA displayed on modal asking for the user to update the password") public static let autofillShowPassword = NSLocalizedString("autofill.show-password", value: "Show Password", comment: "Accessibility title for a Show Password button displaying actial password instead of *****") @@ -743,13 +742,18 @@ But if you *do* want a peek under the hood, you can find more information about """, comment: "about page") public static let autofillEnableSettings = NSLocalizedString("autofill.logins.list.enable", value:"Save and Autofill Logins", comment: "Title for a toggle that enables autofill") + public static let autofillNeverSavedSettings = NSLocalizedString("autofill.logins.list.never.saved", value:"Reset Excluded Sites", comment: "Title for a button that allows a user to reset their list of never saved sites") public static let autofillLoginListTitle = NSLocalizedString("autofill.logins.list.title", value:"Logins", comment: "Title for screen listing autofill logins") public static let autofillLoginListSearchPlaceholder = NSLocalizedString("autofill.logins.list.search-placeholder", value:"Search Logins", comment: "Placeholder for search field on autofill login listing") public static let autofillLoginListSuggested = NSLocalizedString("autofill.logins.list.suggested", value:"Suggested", comment: "Section title for group of suggested saved logins") + public static let autofillResetNeverSavedActionTitle = NSLocalizedString("autofill.logins.list.never.saved.reset.action.title", value:"If you reset excluded sites, you will be prompted to save your Login next time you sign in to any of these sites.", comment: "Alert title") + public static let autofillResetNeverSavedActionConfirmButton = NSLocalizedString("autofill.logins.list.never.saved.reset.action.confirm", value: "Reset Excluded Sites", comment: "Confirm button to reset list of never saved sites") + public static let autofillResetNeverSavedActionCancelButton = NSLocalizedString("autofill.logins.list.never.saved.reset.action.cancel", value: "Cancel", comment: "Cancel button for resetting list of never saved sites") + public static let autofillLoginPromptAuthenticationCancelButton = NSLocalizedString("autofill.logins.prompt.auth.cancel", value:"Cancel", comment: "Cancel button for auth during login prompt") public static let autofillLoginPromptAuthenticationReason = NSLocalizedString("autofill.logins.prompt.auth.reason", value:"Unlock To Use Saved Login", comment: "Reason for auth during login prompt") - public static let autofillLoginPromptTitle = NSLocalizedString("autofill.logins.prompt.title", value:"Use a saved Login?", comment: "Title for autofill login prompt") + public static let autofillLoginPromptTitle = NSLocalizedString("autofill.logins.prompt.title", value:"Use a saved password?", comment: "Title for autofill login prompt") public static let autofillLoginPromptExactMatchTitle = NSLocalizedString("autofill.logins.prompt.exact.match.title", value:"From this website", comment: "Title for section of autofill logins that are an exact match to the current website") public static func autofillLoginPromptPartialMatchTitle(for type: String) -> String { let message = NSLocalizedString("autofill.logins.prompt.partial.match.title", value: "From %@", comment: "Title for section of autofill logins that are an approximate match to the current website") diff --git a/DuckDuckGo/bg.lproj/Localizable.strings b/DuckDuckGo/bg.lproj/Localizable.strings index a8a38eceec..ebb2fec0f5 100644 --- a/DuckDuckGo/bg.lproj/Localizable.strings +++ b/DuckDuckGo/bg.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Данните за вход са изтрити"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Нулиране на изключените сайтове"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Отмени"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Нулиране на изключените сайтове"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Ако нулирате изключените сайтове, при следващото влизане в някой от тези сайтове ще бъдете подканени да запазите данните си за вход."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Търсене на данни за вход"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Парола за %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Да се използват ли запазените данни за вход?"; +"autofill.logins.prompt.title" = "Използване на запазена парола?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "за '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Потребителското име на личен Duck Address беше премахнато"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Никога не питай за този сайт"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Данните за вход се съхраняват на сигурно място в менюто Данни за вход на Вашето устройство."; +"autofill.save-login.new-user.message" = "Паролите се съхраняват на сигурно място в менюто Данни за вход на Вашето устройство."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Искате ли DuckDuckGo да запази данните за вход?"; +"autofill.save-login.new-user.title" = "Искате ли DuckDuckGo да запази Вашата парола?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Не записвай"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Запазване на данните за вход"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Запазване на данните за вход?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Запазване на паролата"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Запазване на паролата?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Показване на паролата"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ за управление на Вашите Duck Address на това устройство."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo ще актуализира запазените данни за вход във Вашето устройство."; +"autofill.update-password.message" = "DuckDuckGo ще актуализира запазената парола във Вашето устройство."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Актуализиране на паролата"; diff --git a/DuckDuckGo/cs.lproj/Localizable.strings b/DuckDuckGo/cs.lproj/Localizable.strings index d0ede74744..02864ed0e8 100644 --- a/DuckDuckGo/cs.lproj/Localizable.strings +++ b/DuckDuckGo/cs.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Přihlašovací údaje smazány"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Obnovit vyloučené stránky"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Zrušit"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Obnovit vyloučené stránky"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Pokud vyloučené weby resetuješ, při příštím přihlašování na některý z nich se ti zobrazí výzva k uložení přihlašovacích údajů."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Hledání přihlašovacích údajů"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Heslo pro %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Použít uložené přihlášení?"; +"autofill.logins.prompt.title" = "Použít uložené heslo?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "pro „%@“"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Soukromé uživatelské jméno Duck Address je smazané"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Na téhle stránce už se neptat"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Přihlašovací údaje jsou bezpečně uložené v zařízení v nabídce Přihlášení."; +"autofill.save-login.new-user.message" = "Hesla jsou bezpečně uložená v zařízení v nabídce Přihlášení."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Má DuckDuckGo uložit přihlašovací údaje?"; +"autofill.save-login.new-user.title" = "Má DuckDuckGo uložit heslo?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Neukládat"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Uložit přihlašovací údaje"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Uložit přihlašovací údaje?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Uložit heslo"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Uložit heslo?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Zobrazit heslo"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ pro správu adres Duck Address na tomto zařízení."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo zaktualizuje toto uložené přihlášení ve tvém zařízení."; +"autofill.update-password.message" = "DuckDuckGo aktualizuje tohle uložené heslo ve tvém zařízení."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Aktualizuj si heslo"; diff --git a/DuckDuckGo/da.lproj/Localizable.strings b/DuckDuckGo/da.lproj/Localizable.strings index 36e78c8a2f..a0e9bb2c37 100644 --- a/DuckDuckGo/da.lproj/Localizable.strings +++ b/DuckDuckGo/da.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Login slettet"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Nulstil ekskluderede websteder"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Annullér"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Nulstil ekskluderede websteder"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Hvis du nulstiller ekskluderede websteder, vil du blive bedt om at gemme dit login, næste gang du logger ind på en af disse sider."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Søg logins"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Adgangskode til %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Vil du bruge et gemt login?"; +"autofill.logins.prompt.title" = "Brug en gemt adgangskode?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "for '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Privat Duck Address-brugernavn blev fjernet"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Spørg aldrig på dette websted"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Logins gemmes sikkert på din enhed i menuen Logins."; +"autofill.save-login.new-user.message" = "Adgangskoder gemmes sikkert på din enhed i menuen Logins."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Skal DuckDuckGo gemme dit login?"; +"autofill.save-login.new-user.title" = "Skal DuckDuckGo gemme din adgangskode?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Gem ikke"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Gem login"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Gem login?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Gem adgangskode"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Gem adgangskode?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Vis adgangskode"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ for at administrere dine Duck-adresser på denne enhed."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo opdaterer dette gemte login på din enhed."; +"autofill.update-password.message" = "DuckDuckGo opdaterer denne gemte adgangskode på din enhed."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Opdater adgangskode"; diff --git a/DuckDuckGo/de.lproj/Localizable.strings b/DuckDuckGo/de.lproj/Localizable.strings index 93ea701619..6f59a19e6e 100644 --- a/DuckDuckGo/de.lproj/Localizable.strings +++ b/DuckDuckGo/de.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Anmeldedaten gelöscht"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Ausgeschlossene Websites zurücksetzen"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Abbrechen"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Ausgeschlossene Websites zurücksetzen"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Wenn du die ausgeschlossenen Websites zurücksetzt, wirst du aufgefordert, deine Anmeldedaten zu speichern, wenn du dich das nächste Mal auf einer dieser Websites anmeldest."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Anmeldedaten suchen"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Passwort für %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Gespeicherte Anmeldedaten verwenden?"; +"autofill.logins.prompt.title" = "Gespeichertes Passwort verwenden?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "für „%@“"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Benutzername von Private Duck Address wurde entfernt"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Für diese Website niemals fragen"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Anmeldedaten werden sicher auf deinem Gerät im Anmeldedaten-Menü gespeichert."; +"autofill.save-login.new-user.message" = "Passwörter werden sicher auf deinem Gerät im Anmeldedaten-Menü gespeichert."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Möchtest du, dass DuckDuckGo deine Anmeldedaten speichert?"; +"autofill.save-login.new-user.title" = "Möchtest du, dass DuckDuckGo dein Passwort speichert?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Nicht speichern"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Anmeldedaten speichern"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Anmeldedaten speichern?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Passwort speichern"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Passwort speichern?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Passwort anzeigen"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@, um deine Duck Addresses auf diesem Gerät zu verwalten."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo aktualisiert diese gespeicherten Anmeldedaten auf deinem Gerät."; +"autofill.update-password.message" = "DuckDuckGo aktualisiert dieses gespeicherte Passwort auf deinem Gerät."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Passwort aktualisieren"; diff --git a/DuckDuckGo/el.lproj/Localizable.strings b/DuckDuckGo/el.lproj/Localizable.strings index 9f2cd24469..ff3591fc75 100644 --- a/DuckDuckGo/el.lproj/Localizable.strings +++ b/DuckDuckGo/el.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Η σύνδεση διαγράφηκε"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Επαναφορά αποκλεισμένων ιστότοπων"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Ακύρωση"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Επαναφορά αποκλεισμένων ιστότοπων"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Εάν κάνετε επαναφορά των αποκλεισμένων ιστότοπων, θα σας ζητηθεί να αποθηκεύσετε τη σύνδεσή σας την επόμενη φορά που θα συνδεθείτε σε οποιονδήποτε από τους ιστότοπους αυτούς."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Αναζήτηση στοιχείων σύνδεσης"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Κωδικός πρόσβασης για %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Χρήση αποθηκευμένων στοιχείων σύνδεσης;"; +"autofill.logins.prompt.title" = "Χρήση αποθηκευμένου κωδικού πρόσβασης;"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "για '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Το ιδιωτικό όνομα χρήστη Duck Address καταργήθηκε"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Μην ζητάτε ποτέ αυτόν τον ιστότοπο"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Οι συνδέσεις αποθηκεύονται με ασφάλεια στη συσκευή σας στο μενού Συνδέσεις."; +"autofill.save-login.new-user.message" = "Οι κωδικοί πρόσβασης αποθηκεύονται με ασφάλεια στη συσκευή σας στο μενού Συνδέσεις."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Θέλετε να αποθηκεύσει το DuckDuckGo τη σύνδεσή σας;"; +"autofill.save-login.new-user.title" = "Θέλετε το DuckDuckGo να αποθηκεύσει τον κωδικό πρόσβασής σας;"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Να μην αποθηκευτεί"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Αποθήκευση σύνδεσης"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Αποθήκευση σύνδεσης;"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Αποθήκευση κωδικού πρόσβασης"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Αποθήκευση κωδικού πρόσβασης;"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Εμφάνιση κωδικού πρόσβασης"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ για διαχείριση των διευθύνσεών σας Duck Address σε αυτήν τη συσκευή."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "Το DuckDuckGo θα ενημερώσει αυτήν την αποθηκευμένη σύνδεση στη συσκευή σας."; +"autofill.update-password.message" = "Το DuckDuckGo θα ενημερώσει αυτόν τον αποθηκευμένο κωδικό πρόσβασης στη συσκευή σας."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Ενημέρωση κωδικού πρόσβασης"; diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index e38e908120..dd0c568bf0 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -544,6 +544,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Login deleted"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Reset Excluded Sites"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Cancel"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Reset Excluded Sites"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "If you reset excluded sites, you will be prompted to save your Login next time you sign in to any of these sites."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Search Logins"; @@ -578,7 +590,7 @@ "autofill.logins.prompt.password.button.title" = "Password for %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Use a saved Login?"; +"autofill.logins.prompt.title" = "Use a saved password?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "for '%@'"; @@ -628,27 +640,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Private Duck Address username was removed"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Never Ask for This Site"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Logins are stored securely on your device in the Logins menu."; +"autofill.save-login.new-user.message" = "Passwords are stored securely on your device in the Logins menu."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Do you want DuckDuckGo to save your Login?"; +"autofill.save-login.new-user.title" = "Do you want DuckDuckGo to save your password?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Don’t Save"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Save Login"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Save Login?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Save Password"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Save Password?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Show Password"; @@ -656,7 +665,7 @@ "autofill.signin.to.manage" = "%@ to manage your Duck Addresses on this device."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo will update this stored Login on your device."; +"autofill.update-password.message" = "DuckDuckGo will update this stored password on your device."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Update Password"; diff --git a/DuckDuckGo/es.lproj/Localizable.strings b/DuckDuckGo/es.lproj/Localizable.strings index b5d389db5e..9262ddf95a 100644 --- a/DuckDuckGo/es.lproj/Localizable.strings +++ b/DuckDuckGo/es.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Inicio de sesión eliminado"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Restablecer sitios excluidos"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Cancelar"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Restablecer sitios excluidos"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Si restableces los sitios excluidos, se te pedirá que guardes tus datos de inicio de sesión la próxima vez que accedas a cualquiera de estos sitios."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Buscar inicios de sesión"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Contraseña para %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "¿Usar un inicio de sesión guardado?"; +"autofill.logins.prompt.title" = "¿Usar una contraseña guardada?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "para '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Se ha eliminado el nombre de usuario de la Duck Address privada"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "No preguntar nunca para esta página"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Los inicios de sesión se almacenan de forma segura en tu dispositivo en el menú Inicios de sesión."; +"autofill.save-login.new-user.message" = "Las contraseñas se almacenan de forma segura en tu dispositivo en el menú Inicios de sesión."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "¿Quieres que DuckDuckGo guarde tu inicio de sesión?"; +"autofill.save-login.new-user.title" = "¿Quieres que DuckDuckGo guarde tu contraseña?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "No guardar"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Guardar inicio de sesión"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "¿Guardar inicio de sesión?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Guardar contraseña"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "¿Guardar contraseña?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Mostrar contraseña"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ para gestionar tus Duck Addresses en este dispositivo."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo actualizará este inicio de sesión almacenado en tu dispositivo."; +"autofill.update-password.message" = "DuckDuckGo actualizará esta contraseña almacenada en tu dispositivo."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Actualizar contraseña"; diff --git a/DuckDuckGo/et.lproj/Localizable.strings b/DuckDuckGo/et.lproj/Localizable.strings index e895da5908..3df8179e8c 100644 --- a/DuckDuckGo/et.lproj/Localizable.strings +++ b/DuckDuckGo/et.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Sisselogimisandmed kustutati"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Lähtesta välistatud saidid"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Tühista"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Lähtesta välistatud saidid"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Kui lähtestad välistatud saidid, küsitakse järgmisel mõnele neist saitidest sisselogimisel, kas soovid salvestada oma sisselogimisandmed."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Otsi sisselogimisandmeid"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Parool veebisaidi %@ jaoks"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Kas kasutada salvestatud sisselogimisandmeid?"; +"autofill.logins.prompt.title" = "Kas kasutada salvestatud parooli?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "otsinguga '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Privaatse Duck Addressi kasutajanimi eemaldati"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Ära selle saidi kohta rohkem küsi"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Logisid hoitakse turvaliselt sinu seadmes logide menüüs."; +"autofill.save-login.new-user.message" = "Paroole hoitakse turvaliselt sinu seadmes sisselogimisandmete menüüs."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Kas soovid, et DuckDuckGo salvestaks sinu sisselogimisandmed?"; +"autofill.save-login.new-user.title" = "Kas soovid, et DuckDuckGo salvestaks sinu parooli?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Ära salvesta"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Salvesta sisselogimisandmed"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Kas salvestada sisselogimisandmed?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Salvesta parool"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Kas salvestada parool?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Kuva parool"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@, et hallata selles seadmes oma Duck Addresse."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo värskendab need salvestatud sisselogimisandmed sinu seadmes."; +"autofill.update-password.message" = "DuckDuckGo värskendab selle salvestatud parooli sinu seadmes."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Värskenda parooli"; diff --git a/DuckDuckGo/fi.lproj/Localizable.strings b/DuckDuckGo/fi.lproj/Localizable.strings index 98e26c789f..2f5ff76343 100644 --- a/DuckDuckGo/fi.lproj/Localizable.strings +++ b/DuckDuckGo/fi.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Kirjautumistieto poistettu"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Nollaa poissuljetut sivustot"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Peruuta"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Nollaa poissuljetut sivustot"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Jos nollaat poissuljetut sivustot, sinua pyydetään tallentamaan kirjautumistietosi, kun seuraavan kerran kirjaudut sisään jollekin näistä sivustoista."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Hae kirjautumistietoja"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Sivuston %@ salasana"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Käytä tallennettuja kirjautumistietoja?"; +"autofill.logins.prompt.title" = "Käytetäänkö tallennettua salasanaa?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "kohteelle '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Yksityinen Duck Address -käyttäjätunnus on poistettu"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Älä kysy enää tällä sivustolla"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Kirjautumistiedot tallennetaan turvallisesti laitteellesi kirjautumistiedot-valikkoon."; +"autofill.save-login.new-user.message" = "Salasanat tallennetaan turvallisesti laitteellesi kirjautumistiedot-valikkoon."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Haluatko, että DuckDuckGo tallentaa kirjautumistietosi?"; +"autofill.save-login.new-user.title" = "Haluatko, että DuckDuckGo tallentaa salasanasi?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Älä tallenna"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Tallenna kirjautumistiedot"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Tallennetaanko kirjautumistiedot?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Tallenna salasana"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Tallennetaanko salasana?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Näytä salasana"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ hallitaksesi Duck Address -osoitteita tällä laitteella."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo päivittää tämän laitteellesi tallennetun kirjautumistiedon."; +"autofill.update-password.message" = "DuckDuckGo päivittää tämän tallennetun salasanan laitteellesi."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Päivitä salasana"; diff --git a/DuckDuckGo/fr.lproj/Localizable.strings b/DuckDuckGo/fr.lproj/Localizable.strings index 4831775401..e29c841bb2 100644 --- a/DuckDuckGo/fr.lproj/Localizable.strings +++ b/DuckDuckGo/fr.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Identifiant supprimé"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Réinitialiser les sites exclus"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Annuler"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Réinitialiser les sites exclus"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Si vous réinitialisez les sites exclus, on vous invitera à enregistrer votre identifiant la prochaine fois que vous vous connecterez à l'un de ces sites."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Recherche d'identifiants"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Mot de passe pour %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Utiliser un identifiant enregistré ?"; +"autofill.logins.prompt.title" = "Utiliser un mot de passe enregistré ?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "pour '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Le nom d'utilisateur de la Duck Address privée a été supprimé"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Ne jamais demander pour ce site"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Les identifiants de connexion sont stockés en toute sécurité sur votre appareil dans le menu Identifiants."; +"autofill.save-login.new-user.message" = "Les mots de passe sont stockés en toute sécurité sur votre appareil dans le menu Identifiants."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Voulez-vous que DuckDuckGo enregistre votre identifiant ?"; +"autofill.save-login.new-user.title" = "Voulez-vous que DuckDuckGo enregistre votre mot de passe ?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Ne pas enregistrer"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Enregistrer l'identifiant"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Enregistrer l'identifiant ?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Enregistrer le mot de passe"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Enregistrer le mot de passe ?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Afficher le mot de passe"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ pour gérer vos Duck Addresses sur cet appareil."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo mettra à jour cet identifiant enregistré sur votre appareil."; +"autofill.update-password.message" = "DuckDuckGo mettra à jour ce mot de passe enregistré sur votre appareil."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Modifier le mot de passe"; diff --git a/DuckDuckGo/hr.lproj/Localizable.strings b/DuckDuckGo/hr.lproj/Localizable.strings index d997b91152..47220b3f4c 100644 --- a/DuckDuckGo/hr.lproj/Localizable.strings +++ b/DuckDuckGo/hr.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Prijava je izbrisana"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Vrati izvorne isključene web lokacije"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Otkaži"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Resetiraj isključene web lokacije"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Ako resetiraš isključene web lokacije, od tebe će se zatražiti da spremiš svoju prijavu sljedeći put kad se prijaviš na bilo koju od ovih lokacija."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Pretraživanje prijava"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Lozinka za %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Koristiti spremljene podatke za prijavu?"; +"autofill.logins.prompt.title" = "Koristiti spremljenu lozinku?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "za '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Korisničko ime privatne Duck Address adrese uklonjeno je"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Nikada ne traži za ovu web lokaciju"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Prijave su sigurno pohranjene na tvom uređaju u izborniku Prijave."; +"autofill.save-login.new-user.message" = "Lozinke su sigurno pohranjene na tvom uređaju u izborniku Prijava."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Želiš li da DuckDuckGo spremi tvoju prijavu?"; +"autofill.save-login.new-user.title" = "Želiš li da DuckDuckGo spremi tvoju lozinku?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Nemoj spremiti"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Spremi prijavu"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Želiš li spremiti prijavu?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Spremi lozinku"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Želiš li spremiti lozinku?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Pokaži lozinku"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ za upravljanje tvojim Duck Address adresama na ovom uređaju."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo će ažurirati ovu spremljenu prijavu na tvom uređaju."; +"autofill.update-password.message" = "DuckDuckGo će ažurirati ovu pohranjenu lozinku na tvom uređaju."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Ažuriraj lozinku"; diff --git a/DuckDuckGo/hu.lproj/Localizable.strings b/DuckDuckGo/hu.lproj/Localizable.strings index 106dcde5b1..340223040d 100644 --- a/DuckDuckGo/hu.lproj/Localizable.strings +++ b/DuckDuckGo/hu.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Bejelentkezés törölve"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Kizárt webhelyek visszaállítása"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Mégsem"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Kizárt webhelyek visszaállítása"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "A kizárt webhelyek visszaállítása esetén a rendszer a bejelentkezési adataid mentését kéri, amikor legközelebb bejelentkezel ezen webhelyek bármelyikére."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Bejelentkezési adatok keresése"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "%@ jelszava"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Mentett bejelentkezés használata?"; +"autofill.logins.prompt.title" = "Mentett jelszót használsz?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "erre: „%@“"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Privát Duck-cím felhasználóneve eltávolítva"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Soha ne kérdezzen rá ennél a webhelynél"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "A rendszer biztonságosan tárolja az eszköz Bejelentkezés menüjében elérhető bejelentkezési adatokat."; +"autofill.save-login.new-user.message" = "A rendszer biztonságosan tárolja az eszköz Bejelentkezés menüjében elérhető jelszavakat."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "A DuckDuckGo mentse a bejelentkezést?"; +"autofill.save-login.new-user.title" = "A DuckDuckGo mentse a jelszót?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Mentés mellőzése"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Bejelentkezés mentése"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Mented a bejelentkezést?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Jelszó mentése"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Mented a jelszót?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Jelszó megjelenítése"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ a Duck-címek kezeléséhez ezen az eszközön."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "A DuckDuckGo frissíti az eszközödön ezt a tárolt bejelentkezést."; +"autofill.update-password.message" = "A DuckDuckGo frissíti az eszközödön ezt a tárolt jelszót."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Jelszó frissítése"; diff --git a/DuckDuckGo/it.lproj/Localizable.strings b/DuckDuckGo/it.lproj/Localizable.strings index 09a883c5c0..70109a5069 100644 --- a/DuckDuckGo/it.lproj/Localizable.strings +++ b/DuckDuckGo/it.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Dati di accesso eliminati"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Ripristina siti esclusi"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Annulla"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Ripristina siti esclusi"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Se ripristini i siti esclusi, ti verrà richiesto di salvare i tuoi dati di accesso la prossima volta che accederai a uno di questi siti."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Cerca dati di accesso"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Password per %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Usare i dati di accesso salvati?"; +"autofill.logins.prompt.title" = "Utilizzare una password salvata?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "per \"%@\""; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Il nome utente Private Duck Address è stato rimosso"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Non chiedere mai per questo sito"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Gli accessi sono archiviati in modo sicuro sul tuo dispositivo nel menu Accessi."; +"autofill.save-login.new-user.message" = "Le password sono archiviate in modo sicuro sul tuo dispositivo nel menu Accessi."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Vuoi che DuckDuckGo salvi i dati di accesso?"; +"autofill.save-login.new-user.title" = "Vuoi che DuckDuckGo salvi la password?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Non salvare"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Salva dati di accesso"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Salvare dati di accesso?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Salva password"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Salvare password?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Mostra password"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ per gestire i tuoi Duck Address su questo dispositivo."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo aggiornerà questi dati di accesso memorizzati sul tuo dispositivo."; +"autofill.update-password.message" = "DuckDuckGo aggiornerà questa password memorizzata sul tuo dispositivo."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Aggiorna password"; diff --git a/DuckDuckGo/lt.lproj/Localizable.strings b/DuckDuckGo/lt.lproj/Localizable.strings index a84e48bbcc..3a1bb62474 100644 --- a/DuckDuckGo/lt.lproj/Localizable.strings +++ b/DuckDuckGo/lt.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Prisijungimas ištrintas"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Iš naujo nustatyti neįtrauktas svetaines"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Atšaukti"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Iš naujo nustatyti neįtrauktas svetaines"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Jei iš naujo nustatysite neįtrauktas svetaines, kitą kartą, kai prisijungsite prie bet kurios iš šių svetainių, būsite paraginti išsaugoti savo prisijungimo vardą."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Ieškoti prisijungimų"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Slaptažodis, skirtas %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Naudoti išsaugotą prisijungimą?"; +"autofill.logins.prompt.title" = "Naudoti išsaugotą slaptažodį?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "„%@“"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Privatus „Duck Address“ naudotojo vardas buvo pašalintas"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Niekada neklauskite šioje svetainėje"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Prisijungimai saugiai saugomi jūsų įrenginio meniu „Prisijungimai“."; +"autofill.save-login.new-user.message" = "Slaptažodžiai saugiai saugomi jūsų įrenginio meniu „Prisijungimai“."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Ar norite, kad „DuckDuckGo“ išsaugotų jūsų prisijungimą?"; +"autofill.save-login.new-user.title" = "Ar norite, kad „DuckDuckGo“ išsaugotų jūsų slaptažodį?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Neišsaugokite"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Išsaugoti prisijungimą"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Išsaugoti prisijungimą?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Išsaugoti slaptažodį"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Išsaugoti slaptažodį?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Rodyti slaptažodį"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@, kad galėtumėte valdyti savo „Duck Address“ šiame įrenginyje."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "„DuckDuckGo“ atnaujins šį jūsų įrenginyje įrašytą prisijungimą."; +"autofill.update-password.message" = "„DuckDuckGo“ atnaujins šį jūsų įrenginyje išsaugotą slaptažodį."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Atnaujinti slaptažodį"; diff --git a/DuckDuckGo/lv.lproj/Localizable.strings b/DuckDuckGo/lv.lproj/Localizable.strings index f7d274b201..02d64bd141 100644 --- a/DuckDuckGo/lv.lproj/Localizable.strings +++ b/DuckDuckGo/lv.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Pieteikšanās dati izdzēsti"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Atiestatīt izslēgtās vietnes"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Atcelt"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Atiestatīt izslēgtās vietnes"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Ja atiestatīsi izslēgtās vietnes, nākamreiz pierakstoties kādā no šīm vietnēm, tev tiks piedāvāts saglabāt savus pieteikšanās datus."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Meklēt pieteikšanās datus"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "%@ parole"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Vai izmantot saglabātos pieteikšanās datus?"; +"autofill.logins.prompt.title" = "Izmantot saglabāto paroli?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "meklējumam \"%@\""; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Privātās Duck adreses lietotājvārds tika noņemts"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Nekad nejautāt par šo vietni"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Pieteikšanās dati tiek droši saglabāti tavā ierīcē, izvēlnē Pieteikšanās dati."; +"autofill.save-login.new-user.message" = "Paroles tiek droši saglabātas tavā ierīcē, izvēlnē Pieteikšanās dati."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Vai vēlies, lai DuckDuckGo saglabātu tavus pieteikšanās datus?"; +"autofill.save-login.new-user.title" = "Vai vēlies, lai DuckDuckGo saglabātu tavu paroli?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Nesaglabāt"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Saglabāt pieteikšanās datus"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Saglabāt pieteikšanās datus?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Saglabāt paroli"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Saglabāt paroli?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Rādīt paroli"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@, lai pārvaldītu savas Duck adreses šajā ierīcē."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo atjauninās šos saglabātos pieteikšanās datus tavā ierīcē."; +"autofill.update-password.message" = "DuckDuckGo atjauninās tavā ierīcē saglabāto paroli."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Atjaunināt paroli"; diff --git a/DuckDuckGo/nb.lproj/Localizable.strings b/DuckDuckGo/nb.lproj/Localizable.strings index 6193960e6e..5ace68b096 100644 --- a/DuckDuckGo/nb.lproj/Localizable.strings +++ b/DuckDuckGo/nb.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Påloggingen er slettet"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Tilbakestill ekskluderte nettsteder"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Avbryt"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Tilbakestill ekskluderte nettsteder"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Hvis du tilbakestiller ekskluderte nettsteder, blir du bedt om å lagre påloggingsinformasjonen din neste gang du logger på disse nettstedene."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Søk i pålogginger"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Passord for %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Vil du bruke en lagret pålogging?"; +"autofill.logins.prompt.title" = "Vil du bruke et lagret passord?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "for «%@»"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Brukernavn for privat Duck-adresse ble fjernet"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Aldri spør for dette nettstedet"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Pålogginger lagres trygt på enheten din i påloggingsmenyen."; +"autofill.save-login.new-user.message" = "Passord lagres trygt på enheten din i påloggingsmenyen."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Vil du at DuckDuckGo skal lagre påloggingen din?"; +"autofill.save-login.new-user.title" = "Vil du at DuckDuckGo skal lagre passordet ditt?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Ikke lagre"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Lagre påloggingen"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Vil du lagre påloggingen?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Lagre passordet"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Vil du lagre passordet?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Vis passord"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ for å administrere Duck-adressene dine på denne enheten."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo oppdaterer denne lagrede påloggingen på enheten din."; +"autofill.update-password.message" = "DuckDuckGo oppdaterer dette lagrede passordet på enheten din."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Oppdater passordet"; diff --git a/DuckDuckGo/nl.lproj/Localizable.strings b/DuckDuckGo/nl.lproj/Localizable.strings index e7669b6136..0a52970964 100644 --- a/DuckDuckGo/nl.lproj/Localizable.strings +++ b/DuckDuckGo/nl.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Aanmeldgegevens verwijderd"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Uitgesloten sites opnieuw instellen"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Annuleren"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Uitgesloten sites opnieuw instellen"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Als je uitgesloten sites opnieuw instelt, zie je de volgende keer dat je bij een van deze sites inlogt een melding om je inloggegevens op te slaan."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Aanmeldgegevens zoeken"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Wachtwoord voor %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Opgeslagen aanmeldgegevens gebruiken?"; +"autofill.logins.prompt.title" = "Een opgeslagen wachtwoord gebruiken?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "voor '%@'"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "De persoonlijke gebruikersnaam voor het Duck Address is verwijderd"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Nooit vragen voor deze site"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Aanmeldgegevens worden veilig opgeslagen op je apparaat in het menu 'Aanmeldingen'."; +"autofill.save-login.new-user.message" = "Wachtwoorden worden veilig opgeslagen op je apparaat in het menu 'Aanmeldingen'."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Wil je dat DuckDuckGo je login opslaat?"; +"autofill.save-login.new-user.title" = "Wil je dat DuckDuckGo je wachtwoord opslaat?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Niet opslaan"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Login opslaan"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Login opslaan?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Wachtwoord opslaan"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Wachtwoord opslaan?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Wachtwoord weergeven"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ om je Duck-adressen op dit apparaat te beheren."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo werkt deze opgeslagen aanmeldgegevens op je apparaat bij."; +"autofill.update-password.message" = "DuckDuckGo werkt dit opgeslagen wachtwoord op je apparaat bij."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Wachtwoord bijwerken"; diff --git a/DuckDuckGo/pl.lproj/Localizable.strings b/DuckDuckGo/pl.lproj/Localizable.strings index 29a6530843..a9577094e3 100644 --- a/DuckDuckGo/pl.lproj/Localizable.strings +++ b/DuckDuckGo/pl.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Login usunięty"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Resetowanie wykluczonych witryn"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Anuluj"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Resetowanie wykluczonych witryn"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Jeśli zresetujesz wykluczone witryny, przy następnym logowaniu do dowolnej z nich pojawi się monit o zapisanie danych logowania."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Wyszukiwanie loginów"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Hasło %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Czy chcesz użyć zapisanego loginu?"; +"autofill.logins.prompt.title" = "Użyć zapisanego hasła?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "dla frazy: %@"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Nazwa użytkownika prywatnego adresu Duck Address została usunięta"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Nigdy nie pytaj o tę witrynę"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Loginy są bezpiecznie przechowywane na Twoim urządzeniu w menu Loginy."; +"autofill.save-login.new-user.message" = "Hasła są bezpiecznie przechowywane na Twoim urządzeniu w menu Loginy."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Czy chcesz zapisać dane logowania w DuckDuckGo?"; +"autofill.save-login.new-user.title" = "Czy chcesz zapisać hasło w DuckDuckGo?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Nie zapisuj"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Zapisz logowanie"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Zapisać logowanie?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Zapisz hasło"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Zapisać hasło?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Pokaż hasło"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@, aby zarządzać adresami Duck Address na tym urządzeniu."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo zaktualizuje ten zapisany login na Twoim urządzeniu."; +"autofill.update-password.message" = "DuckDuckGo zaktualizuje to zapisane hasło na Twoim urządzeniu."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Aktualizuj hasło"; diff --git a/DuckDuckGo/pt.lproj/Localizable.strings b/DuckDuckGo/pt.lproj/Localizable.strings index 7f1f5eddb8..929e1ca91a 100644 --- a/DuckDuckGo/pt.lproj/Localizable.strings +++ b/DuckDuckGo/pt.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Início de sessão eliminado"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Repor sites excluídos"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Cancelar"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Repor sites excluídos"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Se repuseres os sites excluídos, ser-te-á pedido que guardes os teus dados de início de sessão da próxima vez que iniciares sessão num destes sites."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Pesquisar inícios de sessão"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Palavra-passe para % @"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Utilizar um início de sessão guardado?"; +"autofill.logins.prompt.title" = "Usar uma palavra-passe guardada?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "para \"%@\""; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "O nome de utilizador privado do Duck Address foi removido"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Nunca pedir para este site"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Os dados de início de sessão são armazenados de forma segura no teu dispositivo no menu Inícios de sessão."; +"autofill.save-login.new-user.message" = "As palavras-passe são armazenadas de forma segura no teu dispositivo no menu Inícios de sessão."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Queres que o DuckDuckGo guarde o teu início de sessão?"; +"autofill.save-login.new-user.title" = "Queres que o DuckDuckGo guarde a tua palavra-passe?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Não guardes"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Guardar início de sessão"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Guardar início de sessão?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Guardar palavra-passe"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Guardar palavra-passe?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Mostrar palavra-passe"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ para gerires os teus Duck Addresses neste dispositivo."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "O DuckDuckGo vai atualizar este início de sessão armazenado no teu dispositivo."; +"autofill.update-password.message" = "O DuckDuckGo vai atualizar esta palavra-passe armazenada no teu dispositivo."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Atualizar palavra-passe"; diff --git a/DuckDuckGo/ro.lproj/Localizable.strings b/DuckDuckGo/ro.lproj/Localizable.strings index 313a252957..0064a3f2b3 100644 --- a/DuckDuckGo/ro.lproj/Localizable.strings +++ b/DuckDuckGo/ro.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Date de conectare șterse"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Resetează site-urile excluse"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Renunță"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Resetează site-urile excluse"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Dacă resetezi site-urile excluse, ți se va cere să îți salvezi datele de conectare data viitoare când te conectezi la oricare dintre aceste site-uri."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Date de autentificare pentru căutare"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Parola pentru %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Folosești datele de conectare salvate?"; +"autofill.logins.prompt.title" = "Folosești o parolă salvată?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "pentru „%@”"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Numele de utilizator pentru Duck Address privată a fost eliminat"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Nu solicita niciodată pentru acest site"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Conexiunile sunt stocate în siguranță pe dispozitivul dvs. în meniul Conectări."; +"autofill.save-login.new-user.message" = "Parolele sunt stocate în siguranță pe dispozitivul dvs. în meniul Autentificări."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Dorești ca DuckDuckGo să îți salveze datele de autentificare?"; +"autofill.save-login.new-user.title" = "Dorești ca DuckDuckGo să-ți salveze parola?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Nu salva"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Salvează autentificarea"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Salvezi autentificarea?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Salvează parola"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Salvezi parola?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Arată parola"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ pentru a-ți gestiona adresele Duck Address pe acest dispozitiv."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo va actualiza aceste date de conectare stocate pe dispozitivul tău."; +"autofill.update-password.message" = "DuckDuckGo va actualiza această parolă stocată pe dispozitivul tău."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Actualizează parola"; diff --git a/DuckDuckGo/ru.lproj/Localizable.strings b/DuckDuckGo/ru.lproj/Localizable.strings index 4c33e53f36..4b79bf5001 100644 --- a/DuckDuckGo/ru.lproj/Localizable.strings +++ b/DuckDuckGo/ru.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Логин удален"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Сбросить список исключений"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Отменить"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Сбросить список исключений"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "В случае сброса списка исключений, при следующем входе на любой из этих сайтов вам предложат сохранить свои учетные данные."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Поиск логинов"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Пароль %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Использовать сохраненный логин?"; +"autofill.logins.prompt.title" = "Использовать сохраненный пароль?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "по запросу «%@»"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Приватное имя пользователя Duck Address удалено"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Больше не спрашивать на этом сайте"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Учетные данные надежно хранятся на вашем устройстве в меню «Логины»."; +"autofill.save-login.new-user.message" = "Пароли надежно хранятся на вашем устройстве в меню «Логины»."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Хотите, чтобы DuckDuckGo сохранил логин?"; +"autofill.save-login.new-user.title" = "Хотите, чтобы DuckDuckGo сохранил ваш пароль?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Не сохранять"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Сохранить логин"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Сохранить логин?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Сохранить пароль"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Сохранить пароль?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Показать пароль"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ для управления адресами Duck Address с этого устройства."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo обновит логин, сохраненный на вашем устройстве."; +"autofill.update-password.message" = "DuckDuckGo обновит пароль, сохраненный на вашем устройстве."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Обновить пароль"; diff --git a/DuckDuckGo/sk.lproj/Localizable.strings b/DuckDuckGo/sk.lproj/Localizable.strings index 234ca6884d..2cc71be60f 100644 --- a/DuckDuckGo/sk.lproj/Localizable.strings +++ b/DuckDuckGo/sk.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Prihlasovacie údaje boli odstránené"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Obnovenie vylúčených lokalít"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Zrušiť"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Obnovenie vylúčených lokalít"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Ak obnovíte vylúčené lokality, pri ďalšom prihlásení na niektorú z týchto lokalít dostanete výzvu na uloženie prihlasovacích údajov."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Vyhľadávanie prihlásení"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Heslo pre %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Použiť uložené prihlasovacie údaje?"; +"autofill.logins.prompt.title" = "Použiť uložené heslo?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "pre „%@”"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Používateľské meno Private Duck Address bolo odstránené"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Nikdy sa nepýtať na túto stránku"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Prihlasovacie údaje sú bezpečne uložené v zariadení v ponuke Prihlásenia."; +"autofill.save-login.new-user.message" = "Heslá sú bezpečne uložené na vašom zariadení v ponuke Prihlásenia."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Chcete, aby DuckDuckGo uložil vaše prihlasovacie údaje?"; +"autofill.save-login.new-user.title" = "Chcete, aby DuckDuckGo uložil vaše heslo?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Neukladať"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Uložiť prihlasovacie údaje"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Uložiť prihlasovacie údaje?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Uložiť heslo"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Uložiť heslo?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Zobraziť heslo"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ na správu vašich Duck adries na tomto zariadení."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo bude aktualizovať tieto uložené prihlasovacie údaje vo vašom zariadení."; +"autofill.update-password.message" = "DuckDuckGo aktualizuje toto uložené heslo vo vašom zariadení."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Aktualizovať heslo"; diff --git a/DuckDuckGo/sl.lproj/Localizable.strings b/DuckDuckGo/sl.lproj/Localizable.strings index 81eb46dbb6..47190ef484 100644 --- a/DuckDuckGo/sl.lproj/Localizable.strings +++ b/DuckDuckGo/sl.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Prijava je izbrisana"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Ponastavi izključena spletna mesta"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Prekliči"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Ponastavi izključena spletna mesta"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Če ponastavite izključena spletna mesta, boste ob naslednji prijavi na katero koli od teh spletnih mest pozvani, da shranite svojo prijavo."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Iskanje podatkov za prijavo"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Geslo za %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Želite uporabiti shranjene podatke za prijavo?"; +"autofill.logins.prompt.title" = "Želite uporabiti shranjeno geslo?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "za »%@«"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Uporabniško ime za zasebni naslov Duck Address je bilo odstranjeno"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Nikoli ne vprašaj za to spletno mesto"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Prijave so varno shranjene v vaši napravi v meniju Prijave."; +"autofill.save-login.new-user.message" = "Gesla so varno shranjena v napravi v meniju Prijave."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Ali želite, da DuckDuckGo shrani vašo prijavo?"; +"autofill.save-login.new-user.title" = "Ali želite, da DuckDuckGo shrani vaše geslo?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Ne shrani"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Shrani prijavo"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Želite shraniti prijavo?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Shrani geslo"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Želite shraniti geslo?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Prikaži geslo"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ za upravljanje naslovov Duck Address v tej napravi."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo bo posodobil to shranjeno prijavo v vaši napravi."; +"autofill.update-password.message" = "DuckDuckGo bo posodobil to shranjeno geslo v vaši napravi."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Posodobitev gesla"; diff --git a/DuckDuckGo/sv.lproj/Localizable.strings b/DuckDuckGo/sv.lproj/Localizable.strings index b2549b8d22..8cd3fdbc47 100644 --- a/DuckDuckGo/sv.lproj/Localizable.strings +++ b/DuckDuckGo/sv.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Inloggning raderad"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Återställ exkluderade webbplatser"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "Avbryt"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Återställ exkluderade webbplatser"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Om du återställer exkluderade webbplatser kommer du att uppmanas att spara din inloggning nästa gång du loggar in på någon av dessa webbplatser."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Sök inloggningar"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "Lösenord för %@"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Använd sparad inloggning?"; +"autofill.logins.prompt.title" = "Vill du använda ett sparat lösenord?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "för ”%@”"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Användarnamn för privat Duck Address har tagits bort"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Fråga aldrig för den här webbplatsen"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Inloggningar lagras säkert på din enhet i menyn Inloggningar."; +"autofill.save-login.new-user.message" = "Lösenord lagras säkert på din enhet i menyn Inloggningar."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "Vill du att DuckDuckGo ska spara din inloggning?"; +"autofill.save-login.new-user.title" = "Vill du att DuckDuckGo ska spara ditt lösenord?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Spara inte"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Spara inloggning"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Spara inloggning?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Spara lösenord"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Spara lösenord?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Visa lösenord"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "%@ för att hantera Duck Addresses på denna enhet."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo uppdaterar den här lagrade inloggningen på din enhet."; +"autofill.update-password.message" = "DuckDuckGo kommer att uppdatera det lagrade lösenordet på din enhet."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Uppdatera lösenord"; diff --git a/DuckDuckGo/tr.lproj/Localizable.strings b/DuckDuckGo/tr.lproj/Localizable.strings index 1b5077a154..1b87ef3f5d 100644 --- a/DuckDuckGo/tr.lproj/Localizable.strings +++ b/DuckDuckGo/tr.lproj/Localizable.strings @@ -529,6 +529,18 @@ /* Toast message when a login item without a title is deleted */ "autofill.logins.list.login-deleted-message-no-title" = "Giriş bilgileri silindi"; +/* Title for a button that allows a user to reset their list of never saved sites */ +"autofill.logins.list.never.saved" = "Hariç Tutulan Siteleri Sıfırla"; + +/* Cancel button for resetting list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.cancel" = "İptal"; + +/* Confirm button to reset list of never saved sites */ +"autofill.logins.list.never.saved.reset.action.confirm" = "Hariç Tutulan Siteleri Sıfırla"; + +/* Alert title */ +"autofill.logins.list.never.saved.reset.action.title" = "Hariç tutulan siteleri sıfırlarsanız, bu sitelerden herhangi birinde bir sonraki oturum açışınızda Giriş bilgilerinizi kaydetmeniz istenecektir."; + /* Placeholder for search field on autofill login listing */ "autofill.logins.list.search-placeholder" = "Giriş Ara"; @@ -563,7 +575,7 @@ "autofill.logins.prompt.password.button.title" = "%@ için parola"; /* Title for autofill login prompt */ -"autofill.logins.prompt.title" = "Kayıtlı Giriş kullanılsın mı?"; +"autofill.logins.prompt.title" = "Kayıtlı bir şifre mi kullanıyorsunuz?"; /* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */ "autofill.logins.search.no-results.subtitle" = "\"%@\" için"; @@ -613,27 +625,24 @@ /* Title for the alert dialog telling the user an updated username is no longer a private email address */ "autofill.removed.duck.address.title" = "Özel Duck Address kullanıcı adı kaldırıldı"; +/* CTA displayed on modal asking if the user never wants to be prompted to save a login for this website agin */ +"autofill.save-login.never-prompt.CTA" = "Bu Site için Hiçbir Zaman Sorma"; + /* Message displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.message" = "Giriş bilgileri cihazınızdaki Giriş Bilgileri menüsünde güvenli bir şekilde saklanır."; +"autofill.save-login.new-user.message" = "Şifreler cihazınızdaki Oturum Açma menüsünde güvenli bir şekilde saklanır."; /* Title displayed on modal asking for the user to save the login for the first time */ -"autofill.save-login.new-user.title" = "DuckDuckGo'nun Girişinizi kaydetmesini istiyor musunuz?"; +"autofill.save-login.new-user.title" = "DuckDuckGo'nun şifrenizi kaydetmesini istiyor musunuz?"; /* Cancel CTA displayed on modal asking for the user to save the login */ "autofill.save-login.not-now.CTA" = "Kaydetme"; -/* Confirm CTA displayed on modal asking for the user to save the login */ -"autofill.save-login.save.CTA" = "Girişi Kaydet"; - /* Title displayed on modal asking for the user to save the login */ "autofill.save-login.title" = "Giriş Kaydedilsin mi?"; /* Confirm CTA displayed on modal asking for the user to save the password */ "autofill.save-password.save.CTA" = "Şifre Kaydet"; -/* Title displayed on modal asking for the user to save the password */ -"autofill.save-password.title" = "Şifre Kaydedilsin mi?"; - /* Accessibility title for a Show Password button displaying actial password instead of ***** */ "autofill.show-password" = "Parolayı göster"; @@ -641,7 +650,7 @@ "autofill.signin.to.manage" = "Bu cihazdaki Duck Address'leri yönetmek için %@."; /* Message displayed on modal asking for the user to update the password */ -"autofill.update-password.message" = "DuckDuckGo, cihazınızdaki bu kayıtlı Giriş bilgisini güncelleyecektir."; +"autofill.update-password.message" = "DuckDuckGo bu kayıtlı şifreyi cihazınızda güncelleyecektir."; /* Confirm CTA displayed on modal asking for the user to update the password */ "autofill.update-password.save.CTA" = "Şifreyi Güncelle"; diff --git a/DuckDuckGoTests/AutofillLoginListViewModelTests.swift b/DuckDuckGoTests/AutofillLoginListViewModelTests.swift index cd6ff8c211..bf6d6eace3 100644 --- a/DuckDuckGoTests/AutofillLoginListViewModelTests.swift +++ b/DuckDuckGoTests/AutofillLoginListViewModelTests.swift @@ -31,6 +31,18 @@ class AutofillLoginListViewModelTests: XCTestCase { private let tld = TLD() private let appSettings = AppUserDefaults() private let vault = (try? MockSecureVaultFactory.makeVault(errorReporter: nil))! + private var manager: AutofillNeverPromptWebsitesManager! + + override func setUpWithError() throws { + try super.setUpWithError() + manager = AutofillNeverPromptWebsitesManager(secureVault: vault) + } + + override func tearDownWithError() throws { + manager = nil + + try super.tearDownWithError() + } func testWhenOneLoginDeletedWithNoSuggestionsThenAlphabeticalSectionIsDeleted() { let accountIdToDelete = "1" @@ -38,7 +50,7 @@ class AutofillLoginListViewModelTests: XCTestCase { SecureVaultModels.WebsiteAccount(id: accountIdToDelete, title: nil, username: "", domain: "testsite.com", created: Date(), lastUpdated: Date()) ] - let model = AutofillLoginListViewModel(appSettings: appSettings, tld: tld, secureVault: vault) + let model = AutofillLoginListViewModel(appSettings: appSettings, tld: tld, secureVault: vault, autofillNeverPromptWebsitesManager: manager) let tableContentsToDelete = model.tableContentsToDelete(accountId: accountIdToDelete) XCTAssertEqual(tableContentsToDelete.sectionsToDelete.count, 1) XCTAssertEqual(tableContentsToDelete.rowsToDelete.count, 0) @@ -52,7 +64,7 @@ class AutofillLoginListViewModelTests: XCTestCase { SecureVaultModels.WebsiteAccount(id: "3", title: nil, username: "", domain: "testsite3.com", created: Date(), lastUpdated: Date()) ] - let model = AutofillLoginListViewModel(appSettings: appSettings, tld: tld, secureVault: vault) + let model = AutofillLoginListViewModel(appSettings: appSettings, tld: tld, secureVault: vault, autofillNeverPromptWebsitesManager: manager) let tableContentsToDelete = model.tableContentsToDelete(accountId: accountIdToDelete) XCTAssertEqual(tableContentsToDelete.sectionsToDelete.count, 0) XCTAssertEqual(tableContentsToDelete.rowsToDelete.count, 1) @@ -100,6 +112,31 @@ class AutofillLoginListViewModelTests: XCTestCase { XCTAssertEqual(tableContentsToDelete.sectionsToDelete.count, 0) XCTAssertEqual(tableContentsToDelete.rowsToDelete.count, 2) } + + func testWhenNoNeverPromptWebsitesSavedThenNeverPromptSectionIsNotShown() { + XCTAssertTrue(manager.deleteAllNeverPromptWebsites()) + let model = AutofillLoginListViewModel(appSettings: appSettings, tld: tld, secureVault: vault, autofillNeverPromptWebsitesManager: manager) + XCTAssertEqual(model.rowsInSection(0), 1) + } + + func testWhenOneNeverPromptWebsiteSavedThenNeverPromptSectionIsShown() { + XCTAssertTrue(manager.deleteAllNeverPromptWebsites()) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("example.com")) + let model = AutofillLoginListViewModel(appSettings: appSettings, tld: tld, secureVault: vault, autofillNeverPromptWebsitesManager: manager) + XCTAssertEqual(model.rowsInSection(0), 2) + } + + func testWhenManyNeverPromptWebsiteSavedThenNeverPromptSectionIsShown() { + XCTAssertTrue(manager.deleteAllNeverPromptWebsites()) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("example.com")) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("example.co.uk")) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("duckduckgo.com")) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("daxisawesome.com")) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("123domain.com")) + + let model = AutofillLoginListViewModel(appSettings: appSettings, tld: tld, secureVault: vault, autofillNeverPromptWebsitesManager: manager) + XCTAssertEqual(model.rowsInSection(0), 2) + } } class AutofillLoginListSectionTypeTests: XCTestCase { diff --git a/DuckDuckGoTests/AutofillNeverPromptWebsitesManagerTests.swift b/DuckDuckGoTests/AutofillNeverPromptWebsitesManagerTests.swift new file mode 100644 index 0000000000..cea49d96c2 --- /dev/null +++ b/DuckDuckGoTests/AutofillNeverPromptWebsitesManagerTests.swift @@ -0,0 +1,85 @@ +// +// AutofillNeverPromptWebsitesManagerTests.swift +// DuckDuckGo +// +// Copyright © 2023 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import XCTest + +@testable import DuckDuckGo +import BrowserServicesKit + +final class AutofillNeverPromptWebsitesManagerTests: XCTestCase { + + private var manager: AutofillNeverPromptWebsitesManager! + private let vault = (try? MockSecureVaultFactory.makeVault(errorReporter: nil))! + + override func setUpWithError() throws { + try super.setUpWithError() + manager = AutofillNeverPromptWebsitesManager(secureVault: vault) + } + + override func tearDownWithError() throws { + manager = nil + + try super.tearDownWithError() + } + + func testWhenSavingNeverPromptWebsiteThenHasNeverPromptWebsiteForDomain() throws { + let domain = "example.com" + _ = try manager.saveNeverPromptWebsite(domain) + + let result = manager.hasNeverPromptWebsitesFor(domain: domain) + + XCTAssertTrue(result) + } + + func testWhenMultipleNeverPromptWebsitesThenHasNeverPromptWebsiteForDomain() { + XCTAssertTrue(manager.deleteAllNeverPromptWebsites()) + + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("example.com")) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("sub.example.com")) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite("anotherdomain.com")) + + XCTAssertEqual(manager.neverPromptWebsites.count, 3) + XCTAssertTrue(manager.hasNeverPromptWebsitesFor(domain: "example.com")) + } + + func testWhenDeletingAllNeverPromptWebsitesTheAllNeverPromptWebsitesDeleted() { + XCTAssertTrue(manager.deleteAllNeverPromptWebsites()) + + let domain = "example.com" + XCTAssertNoThrow(try manager.saveNeverPromptWebsite(domain)) + XCTAssertEqual(manager.neverPromptWebsites.count, 1) + + XCTAssertTrue(manager.deleteAllNeverPromptWebsites()) + XCTAssertEqual(manager.neverPromptWebsites.count, 0) + } + + func testWhenNoNeverPromptWebsitesForDomainThenNoHasNeverPromptWebsitesForDomain() { + let domain = "example.com" + XCTAssertTrue(manager.deleteAllNeverPromptWebsites()) + XCTAssertFalse(manager.hasNeverPromptWebsitesFor(domain: domain)) + } + + func testWhenSaveNeverPromptWebsiteThatAlreadyExistsThenHasNeverPromptWebsiteForDomain() { + let domain = "example.com" + XCTAssertNoThrow(try manager.saveNeverPromptWebsite(domain)) + XCTAssertNoThrow(try manager.saveNeverPromptWebsite(domain)) + XCTAssertTrue(manager.hasNeverPromptWebsitesFor(domain: "example.com")) + } + +} diff --git a/DuckDuckGoTests/MockDependencyProvider.swift b/DuckDuckGoTests/MockDependencyProvider.swift index e16288eeb9..7676843d3c 100644 --- a/DuckDuckGoTests/MockDependencyProvider.swift +++ b/DuckDuckGoTests/MockDependencyProvider.swift @@ -34,6 +34,7 @@ class MockDependencyProvider: DependencyProvider { var voiceSearchHelper: VoiceSearchHelperProtocol var downloadManager: DownloadManager var autofillLoginSession: AutofillLoginSession + var autofillNeverPromptWebsitesManager: AutofillNeverPromptWebsitesManager var configurationManager: ConfigurationManager init() { @@ -48,6 +49,7 @@ class MockDependencyProvider: DependencyProvider { voiceSearchHelper = defaultProvider.voiceSearchHelper downloadManager = defaultProvider.downloadManager autofillLoginSession = defaultProvider.autofillLoginSession + autofillNeverPromptWebsitesManager = defaultProvider.autofillNeverPromptWebsitesManager configurationManager = defaultProvider.configurationManager } } diff --git a/DuckDuckGoTests/MockSecureVault.swift b/DuckDuckGoTests/MockSecureVault.swift index 9949ea064a..9dfc62644f 100644 --- a/DuckDuckGoTests/MockSecureVault.swift +++ b/DuckDuckGoTests/MockSecureVault.swift @@ -44,6 +44,7 @@ final class MockSecureVault: AutofillSecureVault { var storedAccounts: [SecureVaultModels.WebsiteAccount] = [] var storedCredentials: [Int64: SecureVaultModels.WebsiteCredentials] = [:] + var storedNeverPromptWebsites = [SecureVaultModels.NeverPromptWebsites]() var storedNotes: [SecureVaultModels.Note] = [] var storedIdentities: [SecureVaultModels.Identity] = [] var storedCards: [SecureVaultModels.CreditCard] = [] @@ -99,6 +100,29 @@ final class MockSecureVault: AutofillSecureVault { storedCredentials[accountId] = nil } + func neverPromptWebsites() throws -> [SecureVaultModels.NeverPromptWebsites] { + return storedNeverPromptWebsites + } + + func hasNeverPromptWebsitesFor(domain: String) throws -> Bool { + return !storedNeverPromptWebsites.filter { $0.domain == domain }.isEmpty + } + + func storeNeverPromptWebsites(_ neverPromptWebsite: SecureVaultModels.NeverPromptWebsites) throws -> Int64 { + if let neverPromptWebsiteId = neverPromptWebsite.id { + storedNeverPromptWebsites.append(neverPromptWebsite) + return neverPromptWebsiteId + } else { + storedNeverPromptWebsites.append(neverPromptWebsite) + return -1 + } + + } + + func deleteAllNeverPromptWebsites() throws { + storedNeverPromptWebsites = [] + } + func notes() throws -> [SecureVaultModels.Note] { return storedNotes } @@ -203,6 +227,8 @@ class MockDatabaseProvider: AutofillDatabaseProvider { var _forDomain = [String]() var _credentialsDict = [Int64: SecureVaultModels.WebsiteCredentials]() var _note: SecureVaultModels.Note? + var _neverPromptWebsites = [SecureVaultModels.NeverPromptWebsites]() + var db: GRDB.DatabaseWriter // swiftlint:enable identifier_name @@ -247,6 +273,33 @@ class MockDatabaseProvider: AutofillDatabaseProvider { return _accounts } + func neverPromptWebsites() throws -> [SecureVaultModels.NeverPromptWebsites] { + return _neverPromptWebsites + } + + func hasNeverPromptWebsitesFor(domain: String) throws -> Bool { + return false + } + + func storeNeverPromptWebsite(_ neverPromptWebsite: SecureVaultModels.NeverPromptWebsites) throws -> Int64 { + if let neverPromptWebsiteId = neverPromptWebsite.id { + _neverPromptWebsites.append(neverPromptWebsite) + return neverPromptWebsiteId + } else { + return -1 + } + } + + func deleteAllNeverPromptWebsites() throws { + _neverPromptWebsites.removeAll() + } + + func updateNeverPromptWebsite(_ neverPromptWebsite: SecureVaultModels.NeverPromptWebsites) throws { + } + + func insertNeverPromptWebsite(_ neverPromptWebsite: SecureVaultModels.NeverPromptWebsites) throws { + } + func notes() throws -> [SecureVaultModels.Note] { return _notes }